protocols
Structural protocols for objects passed into step tasks.
These Protocols describe the minimal interface that the DAG runner must satisfy when constructing and passing resource-like objects to Prefect tasks. Concrete implementations do not need to inherit from these — structural (duck-type) compatibility is sufficient.
Sub-modules
model
ModelResourceProtocol — any object that can load a Bitfount model.
ehr
EHRDataResource — concrete resource that queries an EHR provider
(NextGen or FHIR R4) and returns EHRPatientResource records.
EHRFetchOptions — which extra per-patient data to fetch alongside it.
Module
Submodules
- bitfount.steps.protocols.ehr - EHR data resource protocol for step tasks.
- bitfount.steps.protocols.hub_model_resource - Concrete ModelResourceProtocol backed by the Bitfount Hub.
- bitfount.steps.protocols.model - Model resource protocol for step tasks.
Classes
EHRDataResource
class EHRDataResource( hub: BitfountHub, ehr_config: EHRConfig | None = None, ehr_secrets: RefreshableJWT | None = None,):Resource to allow connection to the EHR.
This is init with EHR configuration from the pod_config. Tasks can obtain a patient-specific querier either via Patient ID, or by providing first name + last name + DOB.
Construct the resource for a single EHR provider.
Picks one of two querier backends based on ehr_config:
NextGenEHRConfig selects the
NextGen path (which authenticates against the Hub session), any
other config whose provider ends in "r4" selects the
FHIR R4 path. Anything else raises ValueError.
Arguments
hub: Bitfount Hub instance, used by the NextGen path to obtain a SMART-on-FHIR session.ehr_config: Provider configuration loaded from the pod config.ehr_secrets: Externally-supplied JWT secrets for the FHIR R4 path. Not needed forSMARTBackendEHRConfig, which carries its own auth on the config object. May beNoneonly when the config is SMART Backend, or whenallow_no_ehr_secretsis set for a genuinely unauthenticated server.
Raises
ValueError: Ifehr_configisNone, ifbase_urlis missing on a FHIR R4 config, if the provider value is unrecognised, or if a FHIR R4 config has no usable credentials andallow_no_ehr_secretsis not set.
Methods
get_patient_info_by_id
def get_patient_info_by_id( self, patient_id: str, *, fetch_options: EHRFetchOptions = EHRFetchOptions(fetch_appointments=False, observation_codes=None, observation_categories=None),) ‑> EHRPatientResource:Returns EHR querier for this patient.
The querier class is selected by self.querier_type. Within each
class, the construction method is chosen by the patient details variant:
EHRIDPatientDetails builds via from_patient_id (no demographic
search), and NameDOBPatientDetails builds via from_patient_query.
Arguments
patient_id: The EHR system's patient ID.fetch_options: Forwarded to_get_patient_resource; seeEHRFetchOptions.
get_patient_info_by_name_dob
def get_patient_info_by_name_dob( self, given_name: str | None, family_name: str | None, patient_dob: str | date, *, fetch_options: EHRFetchOptions = EHRFetchOptions(fetch_appointments=False, observation_codes=None, observation_categories=None),) ‑> EHRPatientResource:Look up a single patient by demographic search.
Routes the call to the active querier backend
(NextGenPatientQuerier or FHIRR4PatientQuerier) and
normalises the response into an EHRPatientResource.
Arguments
given_name: Patient's first/given name.family_name: Patient's last/family name.patient_dob: Date of birth, either as adateor an ISO-format string the backend can parse.fetch_options: Forwarded to_get_patient_resource; seeEHRFetchOptions.
Returns
The materialised EHRPatientResource. Code lists may be
empty (or None on a GetPatientInfoError from the backend).
Raises
NoMatchingPatientError: Propagated from the backend when no patient matches the supplied demographics.ValueError: Ifself.querier_typeis set to an unsupported value.
get_patient_lister
def get_patient_lister(self) ‑> BaseEHRPatientLister:Build a paginated patient-ID lister for the active EHR backend.
Routes the call to the active lister backend
(NextGenPatientLister or FHIRR4PatientLister) via the
unified from_ehr_backend entrypoint — each implementation
cherry-picks the kwargs it needs and ignores the rest, mirroring
the dispatch shape of get_patient_info_by_name_dob.
EHRFetchOptions
class EHRFetchOptions( fetch_appointments: bool = False, observation_codes: Sequence[tuple[str | None, str]] | None = None, observation_categories: Sequence[str] | None = None,):Which extra per-patient EHR data to fetch, beyond the unfiltered code lists.
Condition/Procedure codes are always fetched unfiltered and matched against criteria locally afterwards — cheap, and every backend supports an unfiltered fetch. These three don't work that way, each for its own reason, which is why they must be requested up front rather than filtered afterwards:
fetch_appointmentsgates an extra round-trip (previous appointments/encounters, next appointment) most flows don't need.observation_codes/observation_categories: Observations must be searched by an explicit code or category — at least one major FHIR backend (Epic) rejects an Observation search with neither.
Variables
- static
fetch_appointments : bool
- static
observation_categories : collections.abc.Sequence[str] | None
- static
observation_codes : collections.abc.Sequence[tuple[str | None, str]] | None
ModelResourceProtocol
class ModelResourceProtocol(*args, **kwargs):An object that can load a Bitfount model ready for inference.
Ancestors
Methods
load_model
def load_model( self, model_ref: Any, *, datastructure: DataStructure, schema: BitfountSchema, batch_size: int | None,) ‑> Any:Load and return a model instance ready for inference.