Files
stack/tests/bib/test_meta.py
kert c0ddf54c31
Some checks failed
CI / lint-test (push) Failing after 1m25s
CI / skinny-install (aco) (push) Successful in 52s
CI / skinny-install (api) (push) Successful in 27s
CI / skinny-install (bcda) (push) Successful in 36s
CI / skinny-install (bib) (push) Successful in 36s
CI / skinny-install (bls) (push) Successful in 28s
CI / skinny-install (ccw) (push) Successful in 31s
CI / skinny-install (cms) (push) Successful in 27s
CI / skinny-install (cli) (push) Successful in 36s
CI / skinny-install (conf) (push) Successful in 30s
CI / skinny-install (api) (pull_request) Successful in 32s
CI / skinny-install (bcda) (pull_request) Successful in 34s
CI / skinny-install (bls) (pull_request) Successful in 29s
CI / skinny-install (bib) (pull_request) Successful in 42s
CI / skinny-install (ccw) (pull_request) Successful in 29s
CI / skinny-install (opps) (push) Successful in 30s
CI / skinny-install (perf) (push) Successful in 32s
CI / skinny-install (pfs) (push) Successful in 34s
CI / skinny-install (rex) (push) Successful in 33s
CI / lint-test (pull_request) Failing after 1m22s
CI / skinny-install (aco) (pull_request) Successful in 1m1s
CI / skinny-install (cli) (pull_request) Successful in 32s
CI / skinny-install (cms) (pull_request) Successful in 30s
CI / skinny-install (conf) (pull_request) Successful in 30s
CI / skinny-install (rex) (pull_request) Successful in 26s
Infra CI / zotero (push) Successful in 6s
Infra CI / mc (push) Successful in 6s
Infra CI / notebooks (pull_request) Successful in 6s
Infra CI / zotero (pull_request) Successful in 6s
Infra CI / docs (pull_request) Failing after 6s
CI / skinny-install (opps) (pull_request) Successful in 26s
CI / skinny-install (perf) (pull_request) Successful in 33s
CI / skinny-install (pfs) (pull_request) Successful in 27s
Infra CI / notebooks (push) Successful in 7s
Infra CI / docs (push) Failing after 8s
Infra CI / api (push) Successful in 8s
Infra CI / api (pull_request) Successful in 9s
Infra CI / mc (pull_request) Successful in 7s
fix: rekey 10,236 invalid bib.sqlite keys to Zotero charset, convert CCLF cites
Two changes:

1. Rekeyed all bib.sqlite items/attachments with chars outside the
   Zotero charset (23456789ABCDEFGHIJKLMNPQRSTUVWXYZ). Chars 0, 1, O, L
   are not valid in Zotero keys. 10,236 items + 1,881 attachments fixed.

2. Converted all 30 CCLF IP Section freeform citations in
   aco/express/cclf.py to structured :pincite: directives:
     Before: CCLF IP Section 3.1 "Matching MBIs" (p.14):
     After:  :pincite:`VTWVB384 §3.1 p.14` — Matching MBIs:

Updated tests to verify pincite parsing instead of meta: tag extraction
from the now-converted docstrings.

fixes #302
2026-03-27 01:14:10 -04:00

480 lines
15 KiB
Python

"""Tests for bib.meta — docstring ↔ Zotero bidirectional mapping."""
from __future__ import annotations
import duckdb
from bib.meta import (
apply_column_comments,
collect_column_comments,
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):
"""CCLF functions now use :pincite: directives instead of bare CCLF IP Section refs."""
from aco.express.cclf import stg_beneficiary_xref
from bib.pincite import parse_pincites
doc = stg_beneficiary_xref.__doc__ or ""
pincites = parse_pincites(doc, "aco.express.cclf.stg_beneficiary_xref")
assert len(pincites) >= 2
keys = {p.item_key for p in pincites}
assert "VTWVB384" in keys
# ── 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"
def test_cclf_dedup(self):
def fn():
"""CCLF IP Section 2.2 (p.8):
Again CCLF IP Section 2.2 (p.8):"""
details = extract_meta_details(fn)
assert len(details) == 1
def test_cfr_dedup(self):
def fn():
"""42 CFR § 425.502 and again 42 CFR § 425.502"""
details = extract_meta_details(fn)
assert len(details) == 1
def test_fr_details(self):
def fn():
"""Published at 90 FR 86252."""
details = extract_meta_details(fn)
assert len(details) == 1
d = details[0]
assert d["source"] == "Federal Register"
assert d["title"] == "90 FR 86252"
assert d["page"] == "86252"
assert d["section"] == ""
def test_fr_dedup(self):
def fn():
"""90 FR 86252 and again 90 FR 86252"""
details = extract_meta_details(fn)
assert len(details) == 1
# ── 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_table_tag_fallback(self):
"""When no refs match, falls back to table: tag lookup."""
import narwhals as nw
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(
title="Core Encounter Spec",
tags=["table:test.out"],
)
key = store.create(item)
@nw.narwhalify
def fn(df):
"""CCLF IP Section 9.9 "Fake" (p.1):"""
return df
from aco.express.base import Expr
from aco.pipe.base import Pipeline
expr = Expr(name="test.out", fn=fn, refs=[])
pipeline = Pipeline(exprs=[expr])
report = tag_items_from_pipeline(pipeline, store)
tagged = {k: v for k, v in report.items() if v}
assert len(tagged) > 0
updated = store.get(key)
fn_tags = [t for t in updated.tags if t.startswith("fn:")]
assert len(fn_tags) > 0
def test_tags_matched_items(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(
key="VTWVB384",
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: tags (meta: tags replaced by :pincite: directives)
updated = store.get(key)
fn_tags = [t for t in updated.tags if t.startswith("fn:")]
assert len(fn_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
# ── generate_pipeline_bibliography ───────────────────────────────
class TestGeneratePipelineBibliography:
def test_returns_refs_for_tagged_exprs(self):
import narwhals as nw
from bib.item import Source
from bib.meta import generate_pipeline_bibliography
from bib.store import Store
store = Store(":memory:")
item = Source(
title="Test Spec",
tags=["fn:test.passthrough"],
institution="CMS",
date_published="2025-01-01",
)
store.create(item)
@nw.narwhalify
def fn(df):
return df
from aco.express.base import Expr
from aco.pipe.base import Pipeline
expr = Expr(name="test._passthrough", fn=fn)
pipeline = Pipeline(exprs=[expr])
result = generate_pipeline_bibliography(pipeline, store)
assert "test._passthrough" in result
assert "Test Spec" in result["test._passthrough"]
def test_empty_pipeline(self):
from bib.meta import generate_pipeline_bibliography
from bib.store import Store
store = Store(":memory:")
from aco.pipe.base import Pipeline
pipeline = Pipeline(exprs=[])
result = generate_pipeline_bibliography(pipeline, store)
assert result == {}
# ── collect_column_comments ──────────────────────────────────────
class TestCollectColumnComments:
def test_collects_col_tags(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(title="CCLF Spec")
key = store.create(item)
store.add_tag(
key,
Tag.col("core.encounter.encounter_id", "Unique encounter ID").label,
)
store.add_tag(
key,
Tag.col("core.encounter.admit_date", "Admission date").label,
)
comments = collect_column_comments(store)
assert comments["core.encounter.encounter_id"] == "Unique encounter ID"
assert comments["core.encounter.admit_date"] == "Admission date"
def test_empty_store_returns_empty(self):
from bib.store import Store
store = Store(":memory:")
assert collect_column_comments(store) == {}
def test_ignores_malformed_col_tags(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(title="Bad tags")
key = store.create(item)
# Tag without = separator
store.add_tag(key, "col:no-equals-sign")
comments = collect_column_comments(store)
assert comments == {}
# ── apply_column_comments ────────────────────────────────────────
class TestApplyColumnComments:
def test_applies_comments_to_duckdb(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(title="Spec")
key = store.create(item)
store.add_tag(
key,
Tag.col("s.t.col_a", "Column A description").label,
)
con = duckdb.connect(":memory:")
con.execute("CREATE SCHEMA s")
con.execute("CREATE TABLE s.t (col_a VARCHAR, col_b INTEGER)")
stmts = apply_column_comments(con, store)
assert len(stmts) == 1
assert "Column A description" in stmts[0]
# Verify comment was actually set
rows = con.execute(
"SELECT comment FROM duckdb_columns() "
"WHERE schema_name = 's' AND table_name = 't' "
"AND column_name = 'col_a'"
).fetchall()
assert rows[0][0] == "Column A description"
con.close()
def test_skips_invalid_column_refs(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(title="Bad ref")
key = store.create(item)
# Only two parts instead of three
store.add_tag(key, "col:schema.table=desc")
con = duckdb.connect(":memory:")
stmts = apply_column_comments(con, store)
assert stmts == []
con.close()
def test_skips_nonexistent_columns(self):
from bib.item import Source
from bib.store import Store
store = Store(":memory:")
item = Source(title="Spec")
key = store.create(item)
store.add_tag(
key,
Tag.col("s.t.nonexistent", "desc").label,
)
con = duckdb.connect(":memory:")
# Table doesn't exist — should not raise
stmts = apply_column_comments(con, store)
assert stmts == []
con.close()