Skip to main content

config

Config for the patient enrichment step (v1).

Classes

EnrichmentSource

class EnrichmentSource(**data: Any):

One externally-supplied file and how to read it.

Every optional field's unused state is None, so a blanked template variable needs no _BLANK_TO_DEFAULT_FIELDS handling. The null-to-concrete fallbacks (patient_id_column, value_column) resolve at the use site rather than as field defaults, keeping the null-default convention intact.

Identity. A source states who each row is about one of two ways. Either it carries a ready-made BitfountPatientID (patient_id_column, or the canonically-named column when neither mode is configured), or it carries the name and date of birth the ID is derived from (given_name_column + family_name_column + dob_column). The second is the realistic one for a site export: the ID is an md5 over a Bitfount-private key, so a site cannot compute it. Derivation runs through bitfount.steps.patient_identity, the same code the imaging and EHR routes use, so a supplied row joins the patient it belongs to rather than minting a second one. _check_identity_shape rejects the two shapes that would silently empty the source: both modes at once, and a half-configured name/DOB trio.

Arguments

  • name: The logical source name. Used to code the facts this source produces, so it is part of the criteria surface.
  • file: The file to read, resolved relative to settings.paths.enrichment_dir. A path escaping that root is rejected — config names a file, never a location.
  • patient_id_column: The column holding a ready-made BitfountPatientID. Mutually exclusive with the name/DOB columns; None when the source states name and date of birth instead.
  • given_name_column: The column holding the patient's given name.
  • family_name_column: The column holding the patient's family name.
  • dob_column: The column holding the patient's date of birth, in any spelling pd.to_datetime accepts.
  • mrn_column: The column holding the site's own medical record number, if the source states one; None stores no MRN. Carried for operator diagnostics only — identity is the derived BitfountPatientID, never the MRN.
  • value_column: The column holding the measurement, for a source with a single one; None uses name. Mutually exclusive with value_columns.
  • value_columns: The columns holding measurements, for a source with several — each minting "<name>_<key>". Mutually exclusive with value_column.
  • laterality_column: The column holding the eye, if the source states one; None leaves every fact unlateralised.
  • measured_at_column: The column holding the measurement date, if the source states one; None leaves every fact undated.
  • code_system: The code system to stamp on this source's facts; None mints the Bitfount enrichment system.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Variables

  • static code_system : str | None
  • static dob_column : str | None
  • static family_name_column : str | None
  • static file : str
  • static given_name_column : str | None
  • static laterality_column : str | None
  • static measured_at_column : str | None
  • static model_config
  • static mrn_column : str | None
  • static name : str
  • static patient_id_column : str | None
  • static value_column : str | None
  • derives_patient_id : bool - Whether rows carry name/DOB parts rather than a ready-made ID.

    Set by configuring the name/DOB trio. A source configuring neither identity mode keeps the original default — a BitfountPatientID column read straight off the file — so the null-default convention holds and an existing source needs no change.

  • resolved_value_columns : list[EnrichmentValueColumn] - The value columns to read, whichever spelling declared them.

    A source declaring neither reads one column named for the source itself, which is the pre-existing default.

Methods


code_root_for

def code_root_for(    self, value_column: EnrichmentValueColumn,)> str:

The code root value_column's facts are addressed by.

A single-value source codes on its name alone, so an existing source's codes do not change when this field gains a list form. A multi-value source qualifies each column by its own key, since one code per source could not tell two measurements apart.

Arguments

  • value_column: The column to build a code root for.

Returns The code root.

EnrichmentValueColumn

class EnrichmentValueColumn(**data: Any):

One column of a source holding a measurement, and how to code it.

Arguments

  • column: The column to read the measurement from.
  • key: The suffix distinguishing this measurement from the source's others, minting the code "<source>_<key>"; None uses column. Set it when the site's own column name is not a name a criterion should have to spell — a criterion addresses bcva_cc_logmar, not VA_D_OD_cc_logMar.
  • unit: The unit every value in this column is expressed in, stamped onto facts whose cell does not carry a unit of its own; None leaves a plain cell unitless. A criterion bounding a value by UnitBound matches nothing without this, since a CSV cell of 0.18 states no unit anywhere.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Variables

  • static column : str
  • static key : str | None
  • static model_config
  • static unit : str | None
  • code_suffix : str - The suffix this column contributes to its facts' code.

PatientEnrichmentConfig

class PatientEnrichmentConfig(**data: Any):

Config for the patient enrichment step.

sources being None is the whole of the step's optionality: no sources means nothing is read, nothing is stored, and no criterion can be decided on supplied data. There is no separate enable flag and no empty-list sentinel.

Configuring a source is not a purely local change, and this is the paragraph to read before doing it on a live pod. Two effects reach reported eligibility, and neither is a defect:

A criterion's reported provenance follows the row. An observation criterion reads both Observations and Supplied Observations, so each row's evidence is stamped ehr or supplied according to which column decided that row (supplied when both did — see _merged_provenance). A report that previously said ehr for every observation criterion will say supplied for the rows a source actually supplied. That is the point of the feature, but it does mean stored evidence changes shape for a pod that starts supplying data.

A lateralised supplied criterion gates the scan verdict. A criterion with laterality.side != "either" is scan-grain, because the study eye is resolved per scan, so it is partitioned into scan_eligibility and can make scans ineligible. An unlateralised one is patient-grain and gates the patient verdict via patient_level_eligibility. See build_scan_evidence for why supplied criteria are partitioned by grain rather than provenance.

So: a source's first real ingest can change a pod's served verdicts, in the direction the criteria ask for. Configure it deliberately, not as a trial.

Arguments

  • sources: The files to ingest, or None to ingest nothing.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

Variables

  • static model_config