querier
Provides a high-level abstraction for extracting patient info from FHIR R4 APIs.
Classes
FHIRR4GetPatientInfoError
class FHIRR4GetPatientInfoError(*args, **kwargs):Could not retrieve patient info.
Ancestors
Subclasses
FHIRR4MedicationsUnsupportedError
class FHIRR4MedicationsUnsupportedError(*args, **kwargs):No medication-related resource type is supported by this server.
A distinct subclass of FHIRR4GetPatientInfoError so a caller (or future
monitoring/retry logic) can tell "this server structurally does not
support any medication resource" apart from a genuine transient fetch
failure — even though both currently degrade the same way in
get_patient_code_states (medication_codes=None).
FHIRR4PatientLister
class FHIRR4PatientLister( *, fhir_client: FHIRClient, list_resource_ids: list[str] | None = None, ehr_provider: EHRProvider | None = None,):Provides paginated patient ID listing from a FHIR R4 /Patient endpoint.
Also supports listing patients via one or more pre-configured FHIR
List resources (see list_resource_ids), for EHRs (e.g. Epic) that
reject an unfiltered /Patient search.
Ancestors
Static methods
from_ehr_backend
def from_ehr_backend( *, fhir_client: FHIRClient | None = None, list_resource_ids: list[str] | None = None, ehr_provider: EHRProvider | None = None, **kwargs: Any,) ‑> FHIRR4PatientLister:Build a FHIRR4PatientLister from a unified set of EHR backend kwargs.
Arguments
fhir_client: FHIRClient instance wrapping the/Patientendpoint.list_resource_ids: Optional FHIRListresource identifiers (system|valuetokens). When set, patient enumeration is scoped to these pre-configured Lists instead of an unfiltered/Patientsearch.ehr_provider: The active EHR provider, to handle quirks of different FHIR implementations.**kwargs: Ignored. Accepted so callers (e.g.EHRDataResource) can pass a unified set of kwargs across NextGen and FHIR R4 backends without filtering by backend.
Raises
ValueError: Iffhir_clientis not supplied.
Methods
get_patient_ids_page
def get_patient_ids_page(self, page_size: int = 25) ‑> list[str]:Return the next page of patient IDs.
If list_resource_ids was supplied at construction, patient IDs
are served by resolving those FHIR List resources (see
_get_patient_ids_page_from_lists). Otherwise, falls back to the
unfiltered /Patient search-bundle pagination below, unchanged.
Raises
FHIRR4HTTPError: If the request fails with an HTTP error after the FHIR client has exhausted its retries.FHIRR4APIError: If the request fails with a generic API error.FHIRR4OperationOutcomeError: If the server returns an OperationOutcome.FHIRR4AuthenticationError: If authentication fails.
Surfacing these (rather than returning an empty list) ensures a transient failure mid-listing fails the task instead of being mistaken for the end of pagination.
FHIRR4PatientQuerier
class FHIRR4PatientQuerier( patient_id: str, *, fhir_client: FHIRClient, fhir_patient_info: RetrievedPatientDetailsJSON | None = None, ehr_provider: str | None = None, patient_dict: dict[str, Any] | None = None,):Provides query/data extraction methods for a given patient.
This class is a higher-level abstraction than the direct API interactions, providing methods for extracting/munging data from the API responses.
NOTE: This querier is used by all FHIR R4 providers. The "generic r4" provider serves as the baseline FHIR R4 implementation that adheres strictly to the FHIR standard without any provider-specific customizations. If provider-specific elements (e.g., Epic-specific) are added to this class or its methods, ensure that "generic r4" continues to work as the baseline standard FHIR R4 provider.
Arguments
patient_id: The patient ID this querier corresponds to.fhir_client: FHIRClient instance.fhir_patient_info: FHIR Patient Info with contact details.ehr_provider: The EHR provider e.g. "nextech", "epic", "generic r4"patient_dict: Optional patient details. If we've created this class with from_patient_query, we'll store the obtained patient_dict for later reference.
Ancestors
Static methods
from_mrn
def from_mrn( mrn: str, *, fhir_client: FHIRClient, ehr_provider: EHRProvider | None = None,) ‑> FHIRR4PatientQuerier:Build a FHIRR4PatientQuerier from MRN.
Arguments
mrn: Medical Record Numberfhir_client: FHIRClient instanceehr_provider: The EHR provider
Returns FHIRR4PatientQuerier for the target patient.
Raises
NoMatchingFHIRR4PatientError: No patient matching the MRN could be foundNonSpecificFHIRR4PatientError: Multiple patients match the MRNNoFHIRR4PatientIDError: Patient matching the MRN was found, but no patient ID was associated
from_patient_id
def from_patient_id( patient_id: str, *, fhir_client: FHIRClient | None = None, ehr_provider: EHRProvider | None = None, **kwargs: dict[str, Any],) ‑> FHIRR4PatientQuerier:Build a FHIRR4PatientQuerier directly from a known patient ID.
Unlike from_patient_query/from_mrn, this does not search for the
patient by demographics; the patient ID is already known. The /Patient
endpoint is queried by ID to retrieve contact details; if that lookup
returns nothing, NoMatchingFHIRR4PatientError is raised so the
caller can skip the patient rather than issuing further queries with
no confirmed patient context.
Arguments
patient_id: The known patient ID.fhir_client: FHIRClient instance.ehr_provider: The EHR provider.**kwargs: Ignored. Accepted so callers (e.g.EHRDataResource) can pass a unified set of kwargs across NextGen and FHIR R4 backends without filtering by querier type.
Returns FHIRR4PatientQuerier for the target patient.
Raises
NoMatchingFHIRR4PatientError: No patient record could be retrieved for the given ID.
from_patient_query
def from_patient_query( patient_dob: str | date, given_name: str | None = None, family_name: str | None = None, *, fhir_client: FHIRClient | None = None, ehr_provider: EHRProvider | None = None, **kwargs: dict[str, Any],) ‑> FHIRR4PatientQuerier:Build a FHIRR4PatientQuerier from patient query details.
Arguments
patient_dob: Patient date of birth.given_name: Patient given name.family_name: Patient family name.fhir_client: FHIRClient instanceehr_provider: The EHR provider**kwargs: Ignored. Accepted so callers (e.g.EHRDataResource) can pass a unified set of kwargs across NextGen and FHIR R4 backends without filtering by querier type.
Returns NextGenPatientQuerier for the target patient.
Raises
NoMatchingFHIRR4PatientError: No patients matching the name/dob criteria could be foundNonSpecificFHIRR4PatientError: Multiple patients match the criteria, could not determine the correct oneNoFHIRR4PatientIDError: Patient matching the criteria was found, but no patient ID was associated
get_patient_response_by_mrn
def get_patient_response_by_mrn( fhir_client: FHIRClient, mrn: str,) ‑> dict[str, typing.Any] | None:Get JSON response from /Patient endpoint given an MRN.
Arguments
fhir_client: FHIRClient instancemrn: Medical Record Number
Returns Patient resource dict if found, None otherwise
get_patient_response_by_name
def get_patient_response_by_name( fhir_client: FHIRClient, patient_dob: str | date, given_name: str | None = None, family_name: str | None = None,) ‑> dict[str, typing.Any] | None:Get JSON response from /Patient endpoint given name and DOB.
Methods
download_all_documents
def download_all_documents( self, save_path: Path,) ‑> tuple[list[DownloadedEHRDocumentInfo], list[FailedEHRDocumentInfo]]:Inherited from:
BaseEHRQuerier.download_all_documents :
Download PDF documents for the current patient.
Arguments
save_path: Documents path for the PDF documents to be saved.
download_documents_batch
def download_documents_batch( self, save_path: Path, batch_document_infos: list[EHRDocumentInfo],) ‑> tuple[list[DownloadedEHRDocumentInfo], list[FailedEHRDocumentInfo]]:Downloads a batch of documents.
Returns A tuple containing:
- list of info of documents that were successfully downloaded.
- list of info of documents that could not be downloaded.
get_document_infos
def get_document_infos( self,) ‑> collections.abc.Iterable[list[EHRDocumentInfo]]:Yields document items related to this patient.
get_next_appointment
def get_next_appointment(self) ‑> datetime.date | None:Get the next appointment date for the patient.
Falls back to encounters if appointments are not available or empty.
Returns The next appointment date for the patient from today, or None if they have no future appointment. Any cancelled or errored appointments are ignored.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient information.
get_patient_allergies
def get_patient_allergies(self) ‑> list[Allergy]:Get allergy/intolerance information for this patient.
Fetched unfiltered (no code list to search by): allergy lists are
small enough per patient to fetch whole and match against a
criteria_tree leaf's own code/system afterwards. code
(AllergyIntolerance's own top-level CodeableConcept, 0..1) and
each reaction[].substance (also a CodeableConcept, 0..*) can
each carry more than one coding. One Allergy is returned per
FHIR resource, with codings holding every coding on its own
code and each AllergyReaction.substance_codings holding every
coding on that reaction's substance — not one entry per coding,
so the same clinical fact is never stored more than once. A code
with no coding at all still leaves code_system/code_code/
code_display and codings empty — AllergyIntolerance.code is
0..1, so a resource may carry no coded diagnosis and rely
entirely on reaction[].substance instead.
Returns A list of Allergy objects relevant for the patient, sorted by date.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient allergy information.
get_patient_associated_medical_practitioner
def get_patient_associated_medical_practitioner(self) ‑> str | None:Retrieve an associated medical practitioner for the patient.
This prefers a practitioner referenced on the Patient resource via
generalPractitioner. If none is available there, it falls back to
the practitioner on the latest appointment or encounter.
Returns The practitioner's name, or None if no associated practitioner can be resolved.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient encounter information.
get_patient_code_states
def get_patient_code_states( self, *, include_medications: bool = False,) ‑> PatientCodeDetails:Get information of Conditions, Procedures, and (optionally) Medications.
Sugar method that combines get_patient_conditions(), get_patient_procedures(), and — when requested — get_patient_medications(), returning a pre-constructed PatientCodeDetails container.
Arguments
include_medications: When True, also fetches medications (4 extra HTTP round-trips against MedicationRequest/Statement/ Dispense/Administration). Defaults to False so the many existing callers that only readcondition_codes/procedure_codesdo not pay for a fetch whose result they never consume.
Returns
A PatientCodeDetails instance detailing the presence or absence of the
provided Conditions, Procedures, and Medications for the patient.
medication_codes is None when include_medications is False,
the same as a fetch that was never attempted.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve condition information.
get_patient_conditions
def get_patient_conditions( self, statuses_filter: list[ClinicalStatus] | None = None, code_types_filter: list[CodeSystems] | None = None,) ‑> list[Condition]:Get conditions related to this patient.
Arguments
statuses_filter: If provided, returns only conditions of that status e.g. ['active','recurrence']code_types_filter: If provided, returns only conditions with codes of a specific code system (ICD10, Snomed) e.g. ["icd10"]
Returns A list of Condition objects relevant for the patient, detailing its status and dates, sorted by condition onset date.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient condition information.
get_patient_devices
def get_patient_devices(self) ‑> list[Device]:Get device information for this patient.
Fetched unfiltered (no code list to search by): device lists are
small enough per patient to fetch whole and match against a
criteria_tree leaf's own code/system afterwards. type
(Device's own top-level CodeableConcept, 0..1) can itself
carry more than one coding; codings holds every one of them. One
Device is returned per FHIR resource. A type with no coding at
all (or absent entirely) still leaves code_system/code_code/
code_display and codings empty.
Returns
A list of Device objects relevant for the patient, sorted by
code for deterministic output (FHIR R4 Device has no field
meaning "when this became relevant to the patient" to sort by).
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient device information.
get_patient_medications
def get_patient_medications(self) ‑> list[Medication]:Get medication-related information for this patient.
This method queries MedicationRequest, MedicationStatement,
MedicationDispense, and MedicationAdministration in sequence.
This matches every other resource type this querier fetches. A
server may support only some of these four resource types. If so,
that server still gives us whatever it has. The whole call does
not fail just because one of the four resource types is absent.
Returns A list of Medication objects for the patient, sorted by date.
Raises
FHIRR4MedicationsUnsupportedError: Every resource type came backUNSUPPORTED. None processed, and none errored. This exception is aFHIRR4GetPatientInfoErrorsubclass. It is the only case that means "this server structurally does not support medications".FHIRR4GetPatientInfoError: At least one resource type genuinely failed (a network error or a deserialisation error), and none processed successfully. This result is too uncertain to report as the more specific "unsupported" signal above.
get_patient_observations
def get_patient_observations( self, codes: Sequence[tuple[str | None, str]],) ‑> list[Observation]:Get Observation resources matching any of the given codes.
Arguments
codes:(code_system, code)pairs to search for.code_systemis a short name fromCODE_SYSTEM_TO_IDENTIFIER(e.g."loinc","snomed");Nonematches the code value across any system.
Returns Observations for the patient matching any of the given codes, should be sorted by date (newest first).
Raises
FHIRR4GetPatientInfoError: If unable to retrieve Observation information for the patient.
get_patient_observations_by_category
def get_patient_observations_by_category( self, categories: Sequence[str],) ‑> list[Observation]:Get Observation resources matching any of the given categories.
Arguments
categories: Core FHIR observation-category values to search for (e.g.["laboratory", "vital-signs"]).
Returns Observations for the patient matching any of the given categories, sorted by date (newest first).
Raises
FHIRR4GetPatientInfoError: If unable to retrieve Observation information for the patient.
get_patient_procedures
def get_patient_procedures( self, statuses_filter: list[ProcedureStatus] | None = None, code_types_filter: list[CodeSystems] | None = None,) ‑> list[Procedure]:Get information of procedure codes this patient has.
Arguments
statuses_filter: If provided, returns only procedures of that status e.g. ['completed', 'in-progress']code_types_filter: If provided, returns only conditions with codes of a specific code system (CPT4, Snomed) e.g. ["cpt4", "snomed"]
Returns A list of Procedure objects relevant for the patient, detailing its status and dates, sorted by procedure date.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient procedures information.
get_patient_response_by_id
def get_patient_response_by_id(self) ‑> dict[str, typing.Any] | None:Get JSON response from /Patient endpoint given a Patient ID.
get_previous_appointment_details
def get_previous_appointment_details( self, include_maybe_attended: bool = True,) ‑> list[EHRAppointmentEncounter]:Get list of previous appointments for the patient.
Returns A list of EHRAppointmentEncounter for the patient, sorted chronologically (oldest first), or an empty list if they have no previous appointments.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient information.
get_previous_encounter_details
def get_previous_encounter_details( self, include_maybe_attended: bool = True,) ‑> list[EHRAppointmentEncounter]:Get list of previous encounters for the patient.
Returns A list of EHRAppointmentEncounter for the patient, sorted chronologically (oldest first), or an empty list if they have no previous appointments.
Raises
FHIRR4GetPatientInfoError: If unable to retrieve patient information.
get_visual_acuity
def get_visual_acuity(self) ‑> Observation | None:Get Visual Acuity observation for a patient.
produce_json_dump
def produce_json_dump( self, save_path: Path, elements_to_dump: Container[str] = frozenset({'procedures', 'medications', 'conditions', 'chart', 'appointments', 'patientInfo', 'encounters'}),) ‑> bitfount.externals.ehr.fhir_r4.querier._FHIRR4PatientJSONDump:Produce a JSON dump of patient information for the target patient.
Saves the JSON dump out to file and the contents can be controlled by
elements_to_dump.
The following options are recognised:
- "patientInfo": /Patient
- "appointments":
/Appointment(not always available) - "conditions":
/Conditions - "encounters":
/Encounters - "medications":
/MedicationRequest - "procedures":
/Procedures
Arguments
save_path: The file location to save the JSON dump to.elements_to_dump: Collection of elements to include in the dump. See above for what options can be included.
Returns The assembled JSON dump. Elements that could not be retrieved (or that the server does not support) are omitted, so callers can inspect the result to decide whether the dump contains anything meaningful.