provinans / src /endopath /coverage.py
reversely's picture
Upload folder using huggingface_hub
6a78d3d verified
Raw
History Blame Contribute Delete
4.7 kB
"""Field coverage: a project's target dictionary and the record types that fulfil it (#237).
The coverage view (the Field coverage page) shows every field of a project's target dictionary, coloured by
the record type that sources it and metered by how full it is in the confirmed dataset. That mapping is
DB-backed here rather than hardcoded in the frontend, so a different project or dictionary is a different
format to review. The record types replace the old hardcoded source strings.
`seed_coverage` loads the TCGA-UCEC REDCap seed (`coverage_data`, generated and de-identified) into the DB
once. `build_coverage` reads it back as the API payload; the live fill is still computed in the browser
from `GET /api/dashboard` and `GET /api/longitudinal/cohort`, so this module stays a thin schema read.
"""
from __future__ import annotations
from sqlalchemy import Connection
from endopath import coverage_data, coverage_extractions, storage
def seed_coverage(conn: Connection, project: str = coverage_data.PROJECT_ID) -> None:
"""Seed the project's record types and target-dictionary coverage from the generated seed, once, then
load the populated record-type extractions. Each step is a no-op if already seeded."""
if not storage.has_coverage(conn, project):
for order, (record_type_id, name, blurb) in enumerate(coverage_data.RECORD_TYPES):
storage.upsert_record_type(
conn,
project=project,
record_type_id=record_type_id,
name=name,
source_class=record_type_id,
blurb=blurb,
sort_order=order,
)
for order, (name, label, section, record_type_id, fill_via, fill_key) in enumerate(
coverage_data.FIELDS
):
storage.upsert_coverage_field(
conn,
project=project,
dictionary_id=coverage_data.DICTIONARY_ID,
name=name,
label=label,
section=section,
record_type_id=record_type_id,
fill_via=fill_via,
fill_key=fill_key,
sort_order=order,
)
conn.commit()
seed_extractions(conn, project)
def seed_extractions(conn: Connection, project: str = coverage_extractions.PROJECT_ID) -> None:
"""Load each record type's committed, in-conversation sample into its extracted dictionary, once per
record type. A no-op for a record type that already carries extraction rows."""
for record_type_id, cases in coverage_extractions.RECORD_TYPE_EXTRACTIONS.items():
if storage.has_record_type_extractions(conn, project, record_type_id):
continue
for barcode, fields in cases.items():
for order, (field, (value, evidence)) in enumerate(fields.items()):
storage.upsert_record_type_extraction(
conn,
project=project,
record_type_id=record_type_id,
case_barcode=barcode,
field=field,
value=value,
evidence=evidence,
sort_order=order,
)
conn.commit()
def build_coverage(conn: Connection, project: str) -> dict:
"""The Field coverage payload for a project: its record types, every target-dictionary field with the
record type that fulfils it and its fill config, and each record type's populated sample extractions
(the extracted dictionary in action). Empty `record_types`/`fields` when unseeded."""
fields = [
{
"name": row["name"],
"label": row["label"],
"section": row["section"],
"source": row["record_type_id"],
"fill": {"via": row["fill_via"], "key": row["fill_key"]} if row["fill_via"] else None,
}
for row in storage.list_coverage_fields(conn, project)
]
record_types = storage.list_record_types(conn, project)
extractions: dict[str, list[dict]] = {}
for rt in record_types:
rows = storage.list_record_type_extractions(conn, project, rt["record_type_id"])
if rows:
extractions[rt["record_type_id"]] = [
{
"case": row["case_barcode"],
"field": row["field"],
"value": row["value"],
"evidence": row["evidence"],
}
for row in rows
]
return {
"dictionary_id": coverage_data.DICTIONARY_ID,
"record_types": record_types,
"fields": fields,
"extractions": extractions,
}