add meta: and fn: tag namespaces, bib/meta.py for docstring ↔ Zotero mapping
- Tag.meta() for section-level citations (cclf-ip-s2.2.1, 42-cfr-425.502) - Tag.fn() for linking Zotero items to express functions - bib/meta.py: extract_meta_tags() parses docstrings for CCLF IP, CFR, FR citation patterns; tag_items_from_pipeline() walks pipeline and adds fn:/meta: tags to matched Zotero items; generate_docstring_refs() pulls Zotero items for an expression into a formatted reference block
This commit is contained in:
301
src/bib/meta.py
Normal file
301
src/bib/meta.py
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
"""Bidirectional mapping between Zotero bibliography and module docstrings.
|
||||||
|
|
||||||
|
Extracts structured citation references from express function docstrings,
|
||||||
|
generates ``meta:`` and ``fn:`` tags for Zotero items, and produces
|
||||||
|
formatted reference blocks that can be embedded in docstrings.
|
||||||
|
|
||||||
|
Three capabilities:
|
||||||
|
|
||||||
|
1. **Extract** — parse docstring citation patterns into ``meta:`` tags
|
||||||
|
2. **Tag** — walk a pipeline and tag Zotero items with ``fn:`` and ``meta:``
|
||||||
|
3. **Generate** — pull Zotero items for an expression and format a
|
||||||
|
reference block suitable for a docstring
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
from bib.meta import extract_meta_tags, tag_items_from_pipeline
|
||||||
|
from bib.meta import generate_docstring_refs
|
||||||
|
from bib.store import Store
|
||||||
|
|
||||||
|
# Extract meta tags from a function's docstring
|
||||||
|
tags = extract_meta_tags(cclf.stg_beneficiary_xref)
|
||||||
|
# [Tag(meta, cclf-ip-s3.1), Tag(meta, cclf-ip-s5.1.1)]
|
||||||
|
|
||||||
|
# Tag all Zotero items referenced by a pipeline
|
||||||
|
store = Store("data/bib.sqlite")
|
||||||
|
report = tag_items_from_pipeline(pipeline, store)
|
||||||
|
|
||||||
|
# Generate a reference block for a docstring
|
||||||
|
refs = generate_docstring_refs("cclf._stg_beneficiary_xref", store)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from bib.tag import Tag
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from collections.abc import Callable
|
||||||
|
|
||||||
|
from bib.store import Store
|
||||||
|
|
||||||
|
# ── Citation pattern extractors ───────────────────────────────────
|
||||||
|
|
||||||
|
# CCLF IP Section 2.2.1 "Title" (p.8-9):
|
||||||
|
_CCLF_IP_RE = re.compile(
|
||||||
|
r"CCLF\s+IP\s+Section\s+([\d.]+)"
|
||||||
|
r'(?:\s+"([^"]*)")?'
|
||||||
|
r"(?:\s*\(p\.([\d-]+)\))?"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 42 CFR § 425.502 or 42 CFR 425.502
|
||||||
|
_CFR_RE = re.compile(r"(\d+)\s+CFR\s+§?\s*([\d.]+)")
|
||||||
|
|
||||||
|
# Federal Register: 90 FR 86252
|
||||||
|
_FR_RE = re.compile(r"(\d+)\s+FR\s+(\d+)")
|
||||||
|
|
||||||
|
|
||||||
|
def extract_meta_tags(fn: Callable) -> list[Tag]:
|
||||||
|
"""Parse a function's docstring for citation patterns.
|
||||||
|
|
||||||
|
Returns ``meta:`` tags for each structured reference found.
|
||||||
|
|
||||||
|
Recognized patterns:
|
||||||
|
|
||||||
|
- ``CCLF IP Section 2.2.1 "Title" (p.8)`` → ``meta:cclf-ip-s2.2.1``
|
||||||
|
- ``42 CFR § 425.502`` → ``meta:42-cfr-425.502``
|
||||||
|
- ``90 FR 86252`` → ``meta:fr-90-86252``
|
||||||
|
"""
|
||||||
|
doc = getattr(fn, "__doc__", None) or ""
|
||||||
|
tags: list[Tag] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
|
||||||
|
for m in _CCLF_IP_RE.finditer(doc):
|
||||||
|
section = m.group(1)
|
||||||
|
ref = f"cclf-ip-s{section}"
|
||||||
|
if ref not in seen:
|
||||||
|
seen.add(ref)
|
||||||
|
tags.append(Tag.meta(ref))
|
||||||
|
|
||||||
|
for m in _CFR_RE.finditer(doc):
|
||||||
|
title, section = m.group(1), m.group(2)
|
||||||
|
ref = f"{title}-cfr-{section}"
|
||||||
|
if ref not in seen:
|
||||||
|
seen.add(ref)
|
||||||
|
tags.append(Tag.meta(ref))
|
||||||
|
|
||||||
|
for m in _FR_RE.finditer(doc):
|
||||||
|
volume, page = m.group(1), m.group(2)
|
||||||
|
ref = f"fr-{volume}-{page}"
|
||||||
|
if ref not in seen:
|
||||||
|
seen.add(ref)
|
||||||
|
tags.append(Tag.meta(ref))
|
||||||
|
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def extract_meta_details(fn: Callable) -> list[dict[str, str]]:
|
||||||
|
"""Parse a function's docstring for citation details.
|
||||||
|
|
||||||
|
Returns a list of dicts with keys: ``tag``, ``title``, ``page``,
|
||||||
|
``source``. More detailed than :func:`extract_meta_tags`.
|
||||||
|
"""
|
||||||
|
doc = getattr(fn, "__doc__", None) or ""
|
||||||
|
details: list[dict[str, str]] = []
|
||||||
|
seen: set[str] = set()
|
||||||
|
|
||||||
|
for m in _CCLF_IP_RE.finditer(doc):
|
||||||
|
section = m.group(1)
|
||||||
|
ref = f"cclf-ip-s{section}"
|
||||||
|
if ref in seen:
|
||||||
|
continue
|
||||||
|
seen.add(ref)
|
||||||
|
details.append(
|
||||||
|
{
|
||||||
|
"tag": f"meta:{ref}",
|
||||||
|
"source": "CCLF Information Packet",
|
||||||
|
"title": m.group(2) or "",
|
||||||
|
"section": section,
|
||||||
|
"page": m.group(3) or "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for m in _CFR_RE.finditer(doc):
|
||||||
|
title, section = m.group(1), m.group(2)
|
||||||
|
ref = f"{title}-cfr-{section}"
|
||||||
|
if ref in seen:
|
||||||
|
continue
|
||||||
|
seen.add(ref)
|
||||||
|
details.append(
|
||||||
|
{
|
||||||
|
"tag": f"meta:{ref}",
|
||||||
|
"source": "Code of Federal Regulations",
|
||||||
|
"title": f"{title} CFR § {section}",
|
||||||
|
"section": section,
|
||||||
|
"page": "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for m in _FR_RE.finditer(doc):
|
||||||
|
volume, page = m.group(1), m.group(2)
|
||||||
|
ref = f"fr-{volume}-{page}"
|
||||||
|
if ref in seen:
|
||||||
|
continue
|
||||||
|
seen.add(ref)
|
||||||
|
details.append(
|
||||||
|
{
|
||||||
|
"tag": f"meta:{ref}",
|
||||||
|
"source": "Federal Register",
|
||||||
|
"title": f"{volume} FR {page}",
|
||||||
|
"section": "",
|
||||||
|
"page": page,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return details
|
||||||
|
|
||||||
|
|
||||||
|
def expr_fn_tag(expr_name: str) -> Tag:
|
||||||
|
"""Generate a ``fn:`` tag from an expression name.
|
||||||
|
|
||||||
|
Strips the schema prefix to produce the function-level reference::
|
||||||
|
|
||||||
|
"cclf._stg_beneficiary_xref" → fn:cclf.stg_beneficiary_xref
|
||||||
|
"readmissions._int_encounter" → fn:readmissions.int_encounter
|
||||||
|
|
||||||
|
Internal names (prefixed with ``_``) have the underscore stripped
|
||||||
|
from the table part since ``fn:`` tags identify the *function*, not
|
||||||
|
the table naming convention.
|
||||||
|
"""
|
||||||
|
schema, _, table = expr_name.partition(".")
|
||||||
|
# Strip leading underscore from intermediate table names
|
||||||
|
fn_name = table.lstrip("_")
|
||||||
|
return Tag.fn(f"{schema}.{fn_name}")
|
||||||
|
|
||||||
|
|
||||||
|
# ── Pipeline → Zotero tagging ────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
def tag_items_from_pipeline(
|
||||||
|
pipeline: object,
|
||||||
|
store: Store,
|
||||||
|
) -> dict[str, list[str]]:
|
||||||
|
"""Walk a pipeline and tag matching Zotero items.
|
||||||
|
|
||||||
|
For each expression in the pipeline:
|
||||||
|
|
||||||
|
1. Generates a ``fn:`` tag from the expression name
|
||||||
|
2. Extracts ``meta:`` tags from the function's docstring
|
||||||
|
3. Finds Zotero items that match the expression's ``refs`` tags
|
||||||
|
4. Adds the ``fn:`` and ``meta:`` tags to those items
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
pipeline : Pipeline
|
||||||
|
Pipeline with ``.exprs`` list of ``Expr`` objects.
|
||||||
|
store : Store
|
||||||
|
Bibliography store to update.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[str, list[str]]
|
||||||
|
Mapping of expression name → list of tags added.
|
||||||
|
"""
|
||||||
|
report: dict[str, list[str]] = {}
|
||||||
|
|
||||||
|
for expr in pipeline.exprs: # type: ignore[attr-defined]
|
||||||
|
fn_tag = expr_fn_tag(expr.name)
|
||||||
|
meta_tags = extract_meta_tags(expr.fn)
|
||||||
|
all_new_tags = [fn_tag.label, *(t.label for t in meta_tags)]
|
||||||
|
|
||||||
|
# Find Zotero items matching the expression's existing refs
|
||||||
|
matched_keys: set[str] = set()
|
||||||
|
for ref in expr.refs:
|
||||||
|
items = store.list_items(tag=ref.label)
|
||||||
|
for item in items:
|
||||||
|
matched_keys.add(item.key)
|
||||||
|
|
||||||
|
# Also match by source tags from the module-level _REFS
|
||||||
|
if not matched_keys:
|
||||||
|
# Try the table tag as a fallback
|
||||||
|
table_tag = Tag.table(expr.name)
|
||||||
|
items = store.list_items(tag=table_tag.label)
|
||||||
|
for item in items:
|
||||||
|
matched_keys.add(item.key)
|
||||||
|
|
||||||
|
# Add new tags to matched items
|
||||||
|
added: list[str] = []
|
||||||
|
for key in matched_keys:
|
||||||
|
item = store.get(key)
|
||||||
|
for tag_label in all_new_tags:
|
||||||
|
if tag_label not in item.tags:
|
||||||
|
store.add_tag(key, tag_label)
|
||||||
|
added.append(f"{key}:{tag_label}")
|
||||||
|
|
||||||
|
report[expr.name] = added
|
||||||
|
|
||||||
|
return report
|
||||||
|
|
||||||
|
|
||||||
|
# ── Docstring reference generation ────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
def generate_docstring_refs(
|
||||||
|
expr_name: str,
|
||||||
|
store: Store,
|
||||||
|
*,
|
||||||
|
style: str = "apa",
|
||||||
|
) -> str:
|
||||||
|
"""Generate a formatted reference block for an expression's docstring.
|
||||||
|
|
||||||
|
Looks up Zotero items tagged with the expression's ``fn:`` tag
|
||||||
|
and formats them as a bibliography section.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
expr_name : str
|
||||||
|
Qualified expression name (e.g. ``cclf._stg_beneficiary_xref``).
|
||||||
|
store : Store
|
||||||
|
Bibliography store to query.
|
||||||
|
style : str
|
||||||
|
Citation style (``apa`` or ``bluebook``).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
Formatted reference block, or empty string if no items found.
|
||||||
|
"""
|
||||||
|
fn_tag = expr_fn_tag(expr_name)
|
||||||
|
items = store.list_items(tag=fn_tag.label)
|
||||||
|
if not items:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
lines = ["References", "~~~~~~~~~~"]
|
||||||
|
for item in items:
|
||||||
|
citation = store.format_citation(item.key, style=style)
|
||||||
|
lines.append(f"- {citation}")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_pipeline_bibliography(
|
||||||
|
pipeline: object,
|
||||||
|
store: Store,
|
||||||
|
*,
|
||||||
|
style: str = "apa",
|
||||||
|
) -> dict[str, str]:
|
||||||
|
"""Generate reference blocks for every expression in a pipeline.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict[str, str]
|
||||||
|
Mapping of expression name → formatted reference block.
|
||||||
|
"""
|
||||||
|
result: dict[str, str] = {}
|
||||||
|
for expr in pipeline.exprs: # type: ignore[attr-defined]
|
||||||
|
refs = generate_docstring_refs(expr.name, store, style=style)
|
||||||
|
if refs:
|
||||||
|
result[expr.name] = refs
|
||||||
|
return result
|
||||||
@@ -38,6 +38,17 @@ Namespaces
|
|||||||
slug (``YEAR_ASSET_VERSION``):
|
slug (``YEAR_ASSET_VERSION``):
|
||||||
``sup:2023_PFS_PR``, ``sup:2026_PFS_FR``
|
``sup:2023_PFS_PR``, ``sup:2026_PFS_FR``
|
||||||
|
|
||||||
|
``meta``
|
||||||
|
Section-level citation reference from a source document:
|
||||||
|
``meta:cclf-ip-s2.2.1``, ``meta:42-cfr-425.502``,
|
||||||
|
``meta:fr-90-86252``
|
||||||
|
|
||||||
|
``fn``
|
||||||
|
Links a bibliography item to a specific express function
|
||||||
|
that references it:
|
||||||
|
``fn:cclf.stg_beneficiary_xref``,
|
||||||
|
``fn:readmissions.int_encounter``
|
||||||
|
|
||||||
Usage::
|
Usage::
|
||||||
|
|
||||||
from bib.tag import Tag
|
from bib.tag import Tag
|
||||||
@@ -172,6 +183,40 @@ class Tag(BaseModel):
|
|||||||
"""
|
"""
|
||||||
return cls(namespace="program", value=program_name.lower())
|
return cls(namespace="program", value=program_name.lower())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def meta(cls, citation_ref: str) -> Tag:
|
||||||
|
"""Tag for a section-level citation reference.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
citation_ref : str
|
||||||
|
Structured reference string, e.g. ``cclf-ip-s2.2.1``,
|
||||||
|
``42-cfr-425.502``, ``fr-90-86252``.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
Tag.meta("cclf-ip-s2.2.1") # meta:cclf-ip-s2.2.1
|
||||||
|
Tag.meta("42-cfr-425.502") # meta:42-cfr-425.502
|
||||||
|
"""
|
||||||
|
return cls(namespace="meta", value=citation_ref)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fn(cls, qualified_name: str) -> Tag:
|
||||||
|
"""Tag linking a bibliography item to an express function.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
qualified_name : str
|
||||||
|
Dotted function path without the ``aco.express.`` prefix,
|
||||||
|
e.g. ``cclf.stg_beneficiary_xref``.
|
||||||
|
|
||||||
|
Examples::
|
||||||
|
|
||||||
|
Tag.fn("cclf.stg_beneficiary_xref") # fn:cclf.stg_beneficiary_xref
|
||||||
|
Tag.fn("readmissions.int_encounter") # fn:readmissions.int_encounter
|
||||||
|
"""
|
||||||
|
return cls(namespace="fn", value=qualified_name)
|
||||||
|
|
||||||
|
|
||||||
_RULE_KIND = {"Final": "FR", "Proposed": "PR", "Correction": "CR"}
|
_RULE_KIND = {"Final": "FR", "Proposed": "PR", "Correction": "CR"}
|
||||||
|
|
||||||
|
|||||||
248
tests/bib/test_meta.py
Normal file
248
tests/bib/test_meta.py
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
"""Tests for bib.meta — docstring ↔ Zotero bidirectional mapping."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from bib.meta import (
|
||||||
|
expr_fn_tag,
|
||||||
|
extract_meta_details,
|
||||||
|
extract_meta_tags,
|
||||||
|
generate_docstring_refs,
|
||||||
|
tag_items_from_pipeline,
|
||||||
|
)
|
||||||
|
from bib.tag import Tag
|
||||||
|
|
||||||
|
# ── extract_meta_tags ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestExtractMetaTags:
|
||||||
|
def test_cclf_ip_section(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 2.2.1 "Part A Claims Header File" (p.8-9):"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:cclf-ip-s2.2.1"
|
||||||
|
|
||||||
|
def test_multiple_cclf_sections(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 3.1 "Matching MBIs" (p.14):
|
||||||
|
|
||||||
|
CCLF IP Section 5.1.1 "Creation of MBI field" (p.19):
|
||||||
|
"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 2
|
||||||
|
labels = {t.label for t in tags}
|
||||||
|
assert labels == {"meta:cclf-ip-s3.1", "meta:cclf-ip-s5.1.1"}
|
||||||
|
|
||||||
|
def test_cclf_section_no_title(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 3.1 (p.14):"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:cclf-ip-s3.1"
|
||||||
|
|
||||||
|
def test_cclf_section_no_page(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 5.3.1"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:cclf-ip-s5.3.1"
|
||||||
|
|
||||||
|
def test_cfr_reference(self):
|
||||||
|
def fn():
|
||||||
|
"""See 42 CFR § 425.502 for details."""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:42-cfr-425.502"
|
||||||
|
|
||||||
|
def test_cfr_without_section_symbol(self):
|
||||||
|
def fn():
|
||||||
|
"""See 42 CFR 425.502 for details."""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:42-cfr-425.502"
|
||||||
|
|
||||||
|
def test_federal_register(self):
|
||||||
|
def fn():
|
||||||
|
"""Published at 90 FR 86252."""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
assert tags[0].label == "meta:fr-90-86252"
|
||||||
|
|
||||||
|
def test_mixed_citations(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 2.2 "Part A" (p.8):
|
||||||
|
|
||||||
|
See also 42 CFR § 425.502 and 90 FR 86252.
|
||||||
|
"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 3
|
||||||
|
labels = {t.label for t in tags}
|
||||||
|
assert "meta:cclf-ip-s2.2" in labels
|
||||||
|
assert "meta:42-cfr-425.502" in labels
|
||||||
|
assert "meta:fr-90-86252" in labels
|
||||||
|
|
||||||
|
def test_deduplication(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 2.2 (p.8):
|
||||||
|
Another ref to CCLF IP Section 2.2 (p.8):
|
||||||
|
"""
|
||||||
|
|
||||||
|
tags = extract_meta_tags(fn)
|
||||||
|
assert len(tags) == 1
|
||||||
|
|
||||||
|
def test_no_docstring(self):
|
||||||
|
fn = lambda: None # noqa: E731
|
||||||
|
assert extract_meta_tags(fn) == []
|
||||||
|
|
||||||
|
def test_no_citations(self):
|
||||||
|
def fn():
|
||||||
|
"""Just a regular function."""
|
||||||
|
|
||||||
|
assert extract_meta_tags(fn) == []
|
||||||
|
|
||||||
|
def test_real_cclf_function(self):
|
||||||
|
from aco.express.cclf import stg_beneficiary_xref
|
||||||
|
|
||||||
|
tags = extract_meta_tags(stg_beneficiary_xref)
|
||||||
|
labels = {t.label for t in tags}
|
||||||
|
assert "meta:cclf-ip-s3.1" in labels
|
||||||
|
assert "meta:cclf-ip-s5.1.1" in labels
|
||||||
|
|
||||||
|
|
||||||
|
# ── extract_meta_details ──────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestExtractMetaDetails:
|
||||||
|
def test_cclf_ip_details(self):
|
||||||
|
def fn():
|
||||||
|
"""CCLF IP Section 2.2.1 "Part A Claims Header File" (p.8-9):"""
|
||||||
|
|
||||||
|
details = extract_meta_details(fn)
|
||||||
|
assert len(details) == 1
|
||||||
|
d = details[0]
|
||||||
|
assert d["tag"] == "meta:cclf-ip-s2.2.1"
|
||||||
|
assert d["source"] == "CCLF Information Packet"
|
||||||
|
assert d["title"] == "Part A Claims Header File"
|
||||||
|
assert d["section"] == "2.2.1"
|
||||||
|
assert d["page"] == "8-9"
|
||||||
|
|
||||||
|
def test_cfr_details(self):
|
||||||
|
def fn():
|
||||||
|
"""42 CFR § 425.502"""
|
||||||
|
|
||||||
|
details = extract_meta_details(fn)
|
||||||
|
assert len(details) == 1
|
||||||
|
assert details[0]["source"] == "Code of Federal Regulations"
|
||||||
|
assert details[0]["title"] == "42 CFR § 425.502"
|
||||||
|
|
||||||
|
|
||||||
|
# ── expr_fn_tag ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestExprFnTag:
|
||||||
|
def test_intermediate_table(self):
|
||||||
|
tag = expr_fn_tag("cclf._stg_beneficiary_xref")
|
||||||
|
assert tag.label == "fn:cclf.stg_beneficiary_xref"
|
||||||
|
|
||||||
|
def test_output_table(self):
|
||||||
|
tag = expr_fn_tag("cclf.medical_claim")
|
||||||
|
assert tag.label == "fn:cclf.medical_claim"
|
||||||
|
|
||||||
|
def test_double_underscore_internal(self):
|
||||||
|
tag = expr_fn_tag("readmissions._int_encounter")
|
||||||
|
assert tag.label == "fn:readmissions.int_encounter"
|
||||||
|
|
||||||
|
|
||||||
|
# ── Tag factory methods ───────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestTagFactories:
|
||||||
|
def test_meta_tag(self):
|
||||||
|
t = Tag.meta("cclf-ip-s2.2.1")
|
||||||
|
assert t.namespace == "meta"
|
||||||
|
assert t.value == "cclf-ip-s2.2.1"
|
||||||
|
assert t.label == "meta:cclf-ip-s2.2.1"
|
||||||
|
|
||||||
|
def test_fn_tag(self):
|
||||||
|
t = Tag.fn("cclf.stg_beneficiary_xref")
|
||||||
|
assert t.namespace == "fn"
|
||||||
|
assert t.value == "cclf.stg_beneficiary_xref"
|
||||||
|
assert t.label == "fn:cclf.stg_beneficiary_xref"
|
||||||
|
|
||||||
|
def test_from_label_meta(self):
|
||||||
|
t = Tag.from_label("meta:cclf-ip-s2.2.1")
|
||||||
|
assert t.namespace == "meta"
|
||||||
|
assert t.value == "cclf-ip-s2.2.1"
|
||||||
|
|
||||||
|
def test_from_label_fn(self):
|
||||||
|
t = Tag.from_label("fn:cclf.stg_beneficiary_xref")
|
||||||
|
assert t.namespace == "fn"
|
||||||
|
assert t.value == "cclf.stg_beneficiary_xref"
|
||||||
|
|
||||||
|
|
||||||
|
# ── tag_items_from_pipeline ───────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestTagItemsFromPipeline:
|
||||||
|
def test_tags_matched_items(self):
|
||||||
|
from bib.item import Source
|
||||||
|
from bib.store import Store
|
||||||
|
|
||||||
|
store = Store(":memory:")
|
||||||
|
item = Source(
|
||||||
|
title="CCLF Information Packet",
|
||||||
|
tags=["source:cms-cclf-ip", "module:aco"],
|
||||||
|
)
|
||||||
|
key = store.create(item)
|
||||||
|
|
||||||
|
from aco.pipe.cclf import pipeline
|
||||||
|
|
||||||
|
report = tag_items_from_pipeline(pipeline, store)
|
||||||
|
|
||||||
|
# At least some expressions should have tagged the item
|
||||||
|
tagged = {k: v for k, v in report.items() if v}
|
||||||
|
assert len(tagged) > 0
|
||||||
|
|
||||||
|
# Verify the item now has fn: and meta: tags
|
||||||
|
updated = store.get(key)
|
||||||
|
fn_tags = [t for t in updated.tags if t.startswith("fn:")]
|
||||||
|
meta_tags = [t for t in updated.tags if t.startswith("meta:")]
|
||||||
|
assert len(fn_tags) > 0
|
||||||
|
assert len(meta_tags) > 0
|
||||||
|
|
||||||
|
|
||||||
|
# ── generate_docstring_refs ───────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
class TestGenerateDocstringRefs:
|
||||||
|
def test_no_items(self):
|
||||||
|
from bib.store import Store
|
||||||
|
|
||||||
|
store = Store(":memory:")
|
||||||
|
refs = generate_docstring_refs("cclf._stg_beneficiary_xref", store)
|
||||||
|
assert refs == ""
|
||||||
|
|
||||||
|
def test_with_tagged_item(self):
|
||||||
|
from bib.item import Source
|
||||||
|
from bib.store import Store
|
||||||
|
|
||||||
|
store = Store(":memory:")
|
||||||
|
item = Source(
|
||||||
|
title="CCLF Information Packet v41.0",
|
||||||
|
tags=["fn:cclf.stg_beneficiary_xref"],
|
||||||
|
institution="CMS",
|
||||||
|
date_published="2025-07-16",
|
||||||
|
)
|
||||||
|
store.create(item)
|
||||||
|
|
||||||
|
refs = generate_docstring_refs("cclf._stg_beneficiary_xref", store)
|
||||||
|
assert "References" in refs
|
||||||
|
assert "CCLF Information Packet" in refs
|
||||||
Reference in New Issue
Block a user