functions
Pure helpers for the patient_level_eligibility step.
Patient-identity construction from the EHR cache (falling back to the
evaluation's SubjectIdentity), used by patient_level_eligibility_task, kept
apart from the task orchestration. No I/O.
Module
Functions
build_ehr_lookup
def build_ehr_lookup( ehr_patient_data: CacheAccessor | None,) ‑> dict[str, dict[str, typing.Any]]:Map bitfount_patient_id → EHR identity fields from the EHR cache.
Arguments
ehr_patient_data: Optional EHR cache accessor.
Returns
A lookup keyed by Bitfount patient ID (empty if no EHR data), each
value a {ehr_patient_id, name, mrns, processed_at, error} dict.
display_name_from_scan_name
def display_name_from_scan_name(scan_name: str) ‑> str:Format a scan-sourced patient name for display.
Imaging sources record the name in whatever form their vendor uses — DICOM
stores Family^Given^Middle^Prefix^Suffix, commonly padded to
SMITH^JANE^^^. That form reaches the patient-data API verbatim unless it
is formatted here, and SMITH^JANE^^^ is not a name anyone recognises.
Reduces the name to "Given Family". Returns the original string unchanged
when it cannot be parsed, so an unusual name is still shown rather than
replaced with something emptier.
Arguments
scan_name: The name as recorded on the scan.
Returns The display form of the name.
ehr_retrieved_at_for
def ehr_retrieved_at_for( bitfount_patient_id: str, ehr_lookup: dict[str, dict[str, Any]],) ‑> datetime.datetime | None:The value for one patient's patient_level_eligibility.ehr_retrieved_at.
Sourced from the served EHR row's own processed_at (via ehr_lookup,
from build_ehr_lookup) rather than a fresh timestamp: the point is when
the patient's EHR data was retrieved, which — under best-effort serving —
may be long before this run, not this run's own time.
A row whose error is set records a lookup that retrieved nothing — its
processed_at is the run that wrote the row, not a moment at which any EHR
data was retrieved. There is no retrieval time for such a patient, so this
reports None: cache/types/patient_level_eligibility/v2/schema.py already
declares NULL to mean "no EHR data at all", and reporting the write time
instead would read fresher than the truth for the one population the field
exists to flag. A row whose every countable fetch group failed carries
error too, and reports None on the same grounds — it holds demographics
but no clinical data for a verdict to rest on.
The lookup value comes off a CacheAccessor DataFrame, so it arrives as
either the stored ISO-8601 string or an already-parsed timestamp; both are
accepted. An unparseable value is dropped rather than stored, because the
column is typed and NULL already carries the right meaning for it.
Arguments
bitfount_patient_id: The patient's Bitfount ID.ehr_lookup: EHR identity lookup (frombuild_ehr_lookup).
Returns
The stored retrieval time, or None — no EHR accessor, no row for this
patient, a row recording a failed lookup, a row with no recorded
processed_at, or one whose recorded value cannot be read as a
timestamp. Every one of those is "not recorded".
identity_for
def identity_for( identity: SubjectIdentity, bitfount_patient_id: str, ehr_lookup: dict[str, dict[str, Any]], now: datetime, task_hash: str, run_id: str | None,) ‑> PatientRecord:Build a patient identity record from EHR data or the evaluation's identity.
The display name is resolved EHR name → the evaluation's identity.name →
the bare bitfount_patient_id. That last resort is an undesirable state
(a named-less patient) and emits a warning.
The EHR name is already split into parts by build_ehr_lookup; the
evaluation's name comes off the scan in its vendor's own form, so it goes
through display_name_from_scan_name first.
Arguments
identity: The subject identity carried on the evaluation (name/MRN fallback).bitfount_patient_id: The patient's ID, which the caller has already established is present. Taken as its own argument rather than read offidentity, whose own field is optional: aPatientRecordkeys on this, so there is no record to build without it, and passing it in puts that requirement in the signature instead of leaving this function to re-check what its caller has already checked.ehr_lookup: EHR identity lookup (frombuild_ehr_lookup).now: The write timestamp.task_hash: Provenance task hash.run_id: Provenance run ID.
Returns
A PatientRecord for the patient.