Some checks failed
CI / lint (push) Successful in 30s
CI / notebooks-smoke (push) Successful in 1m25s
Infra CI / notebooks (push) Failing after 1m5s
Infra CI / zotero (push) Successful in 16s
Infra CI / docs (push) Successful in 1m32s
Infra CI / api (push) Successful in 1m5s
Infra CI / llm (push) Successful in 52s
Infra CI / mc (push) Successful in 13s
CI / lint (pull_request) Successful in 31s
CI / test (push) Successful in 17m29s
CI / notebooks-smoke (pull_request) Successful in 1m27s
Infra CI / notebooks (pull_request) Failing after 1m9s
Infra CI / zotero (pull_request) Successful in 14s
Infra CI / docs (pull_request) Successful in 13s
Infra CI / api (pull_request) Successful in 19s
Infra CI / llm (pull_request) Successful in 13s
Infra CI / mc (pull_request) Successful in 13s
CI / test (pull_request) Successful in 28m53s
I4: `stack pfs families` and `stack pfs lineage` opened a RW `duckdb_batch` connection even without `--write`, so a plain lookup contended for the DuckDB single-writer lock a notebook may be holding (#508-#514). Mirror the `elements --dry-run` shape: `_read()` when `write` is false, `_batch()` + `ensure_tables` only when true. A replica that hasn't had `--write` run yet (no `pfs.code_element`/ `code_event`/`code_family`) prints "no derived tables yet — run with --write" and exits 0 instead of raising. I9: `families --write` ran `read_elements`/`read_events` once per code (~2xN queries) inside the write lock. Added `read_all_elements`/ `read_all_events` to `pfs.codetables` — one full-table read each, grouped in Python, same per-code ordering as the existing readers. I6: `--all-payable` isn't viable as written (the loop isn't inverted in this slice per the controller's ruling) — help text now says "experimental: ~20 min of SQL before any model call" and a `log.warning` logs the target count when it's used. M3: the unknown-`--family` error listed every key in `FAMILIES` (~15k once `refresh_from` has run) — list only `HAND_FAMILIES`. Claude-Session: https://claude.ai/code/session_01Aum3pEMAM3yQVdFSdVe6Gc
182 lines
4.9 KiB
Python
182 lines
4.9 KiB
Python
"""pfs.codetables — DDL + writers for the code element/event/family tables."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import duckdb
|
|
import pytest
|
|
|
|
from pfs.codetables import (
|
|
ElementRow,
|
|
EventRow,
|
|
FamilyRow,
|
|
ReviewRow,
|
|
ensure_tables,
|
|
read_all_elements,
|
|
read_all_events,
|
|
read_elements,
|
|
read_events,
|
|
read_families,
|
|
write_elements,
|
|
write_events,
|
|
write_families,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def con():
|
|
c = duckdb.connect(":memory:")
|
|
ensure_tables(c)
|
|
yield c
|
|
c.close()
|
|
|
|
|
|
def _el(code="99490", value="consent", year=2015):
|
|
return ElementRow(
|
|
code, year, "activity", value, "", "Consent;", "DE2VH9PD", 1245, 67716, "fr"
|
|
)
|
|
|
|
|
|
class TestDDL:
|
|
def test_idempotent(self, con):
|
|
ensure_tables(con)
|
|
names = {
|
|
r[0]
|
|
for r in con.execute(
|
|
"SELECT table_name FROM information_schema.tables WHERE table_schema='pfs'"
|
|
).fetchall()
|
|
}
|
|
assert {
|
|
"code_element",
|
|
"code_element_review",
|
|
"code_event",
|
|
"code_family",
|
|
} <= names
|
|
|
|
|
|
class TestElements:
|
|
def test_write_replaces_per_code(self, con):
|
|
assert (
|
|
write_elements(
|
|
con,
|
|
"99490",
|
|
[_el(), _el(value="24-7-access")],
|
|
[ReviewRow("99490", "odd line", "activity", "", "DE2VH9PD", 1246)],
|
|
)
|
|
== 2
|
|
)
|
|
assert write_elements(con, "99490", [_el()], []) == 1
|
|
rows = read_elements(con, "99490")
|
|
assert [r.value for r in rows] == ["consent"]
|
|
assert (
|
|
con.execute(
|
|
"SELECT count(*) FROM pfs.code_element_review WHERE code='99490'"
|
|
).fetchone()[0]
|
|
== 0
|
|
)
|
|
|
|
def test_other_codes_untouched(self, con):
|
|
write_elements(con, "99490", [_el()], [])
|
|
write_elements(con, "G0556", [_el(code="G0556")], [])
|
|
write_elements(con, "99490", [], [])
|
|
assert read_elements(con, "99490") == []
|
|
assert len(read_elements(con, "G0556")) == 1
|
|
|
|
|
|
class TestReadAll:
|
|
def test_read_all_elements_matches_per_code_reader(self, con):
|
|
write_elements(
|
|
con, "99490", [_el(value="24-7-access"), _el(value="consent")], []
|
|
)
|
|
write_elements(con, "G0556", [_el(code="G0556")], [])
|
|
out = read_all_elements(con)
|
|
assert set(out) == {"99490", "G0556"}
|
|
assert out["99490"] == read_elements(con, "99490")
|
|
assert out["G0556"] == read_elements(con, "G0556")
|
|
|
|
def test_read_all_elements_empty(self, con):
|
|
assert read_all_elements(con) == {}
|
|
|
|
def test_read_all_events_matches_per_code_reader(self, con):
|
|
rows = [
|
|
EventRow(
|
|
"99439",
|
|
2021,
|
|
"replaces",
|
|
"G2058",
|
|
"99439",
|
|
"YBM4IZUS",
|
|
1578,
|
|
84639,
|
|
"fr",
|
|
True,
|
|
"",
|
|
),
|
|
EventRow("99439", 2021, "appeared", "", "", "", 0, 0, "rvu", True, ""),
|
|
]
|
|
write_events(con, "99439", rows)
|
|
write_events(
|
|
con,
|
|
"G2058",
|
|
[EventRow("G2058", 2020, "appeared", "", "", "", 0, 0, "rvu", True, "")],
|
|
)
|
|
out = read_all_events(con)
|
|
assert set(out) == {"99439", "G2058"}
|
|
assert out["99439"] == read_events(con, "99439")
|
|
assert out["G2058"] == read_events(con, "G2058")
|
|
|
|
def test_read_all_events_empty(self, con):
|
|
assert read_all_events(con) == {}
|
|
|
|
|
|
class TestEvents:
|
|
def test_roundtrip_sorted_by_year(self, con):
|
|
rows = [
|
|
EventRow(
|
|
"99439",
|
|
2021,
|
|
"replaces",
|
|
"G2058",
|
|
"99439",
|
|
"YBM4IZUS",
|
|
1578,
|
|
84639,
|
|
"fr",
|
|
True,
|
|
"",
|
|
),
|
|
EventRow("99439", 2021, "appeared", "", "", "", 0, 0, "rvu", True, ""),
|
|
]
|
|
assert write_events(con, "99439", rows) == 2
|
|
got = read_events(con, "99439")
|
|
assert [e.kind for e in got] == ["appeared", "replaces"]
|
|
assert got[1].anchored is True
|
|
|
|
|
|
class TestFamilies:
|
|
def test_full_replace(self, con):
|
|
write_families(
|
|
con,
|
|
[
|
|
FamilyRow(
|
|
"CCM", "Chronic Care Management", "99490", "base", 2015, None, "", 0
|
|
)
|
|
],
|
|
)
|
|
write_families(
|
|
con,
|
|
[
|
|
FamilyRow(
|
|
"CCM",
|
|
"Chronic Care Management",
|
|
"99439",
|
|
"add-on",
|
|
2021,
|
|
None,
|
|
"YBM4IZUS",
|
|
1578,
|
|
)
|
|
],
|
|
)
|
|
fams = read_families(con)
|
|
assert len(fams) == 1 and fams[0].code == "99439" and fams[0].role == "add-on"
|