protocol
Data-access seam for the patient-data API.
Defines the PatientDataRepository Protocol the API depends on. The
cache-backed implementation lives in repository.py.
Classes
PatientDataRepository
class PatientDataRepository(*args, **kwargs):Read-facade over patient-eligibility data.
Methods speak the API's vocabulary (trial/project and patient IDs) and
return pydantic response models. Implementations hide any underlying
storage detail (e.g. the cache's task_hash keying).
Ancestors
Subclasses
Methods
get_eligibility_counts
def get_eligibility_counts( self, trial_ids: list[str],) ‑> dict[str, EligibilityCounts]:Return eligibility counts keyed by trial (project) ID.
Arguments
trial_ids: The trial (project) IDs to return counts for.
Returns A mapping of each requested trial ID to its status counts.
get_eligibility_evidence
def get_eligibility_evidence( self, bitfount_patient_id: str, project_id: str,) ‑> EligibilityEvidence | None:Return eligibility evidence for a patient on a trial, or None.
Arguments
bitfount_patient_id: The Bitfount patient ID.project_id: The trial (project) ID.
Returns The eligibility evidence, or None if the (patient, trial) pair is not found.
get_patient
def get_patient( self, bitfount_patient_id: str,) ‑> PatientSummary | None:Return a single patient summary, or None if not found.
Arguments
bitfount_patient_id: The Bitfount patient ID.
Returns The patient summary, or None if no patient with that ID exists.
get_scan_image
def get_scan_image( self, *, scan_id: str | None, path: str | None, modality: str | None, laterality: str | None, width: int | None, refresh: bool, include_masks: bool = False, include_vectors: bool = False, segmentation_classes: list[str] | None = None,) ‑> bytes:Resolve a scan reference and return its frames as a WebP ZIP.
Resolves scan_id/path to a validated file (the allowlist check),
then renders the file to a ZIP of scaled WebP frames.
Arguments
scan_id: The scan identifier, or None (exactly one of scan_id/path).path: An explicit, allowlisted file path, or None.modality: Optional series selector for multi-series files.laterality: Optional "L"/"R" series selector.width: Optional output width (px); None uses the configured default.refresh: When True, bypass and overwrite any cached archive.include_masks: Whether the archive should carry a rendered mask PNG per segmentation class. Callers pass an already-resolved value (resolving the query params into a selection is the route's job, not this seam's).include_vectors: Whether the served index should carry each class's raw drawable instances. Also already-resolved.segmentation_classes: Optional class-name filter, applied only when an overlay output was requested. A name that matches no class the model produced yields no output for it, never an error.
Returns
The application/zip archive bytes: frame_NNN.webp per frame, a
manifest.json, and — when an overlay output was requested and
segmentation is available — a segmentations.json index, plus one
masks/ PNG per class when include_masks is True.
Raises
ScanNotFoundError: The reference does not resolve to an authorised file, or the scan-image feature is not enabled.ScanRequestError: Bad inputs, non-positive width, or undecodable file.
list_patients
def list_patients( self, *, search: str | None = None, eligible_trials: list[str] | None = None, page: int = 1, page_size: int = 50,) ‑> PatientList:Return one page of patients, filtered and searched server-side.
Arguments
search: Case-insensitive substring matched against a patient's name or EHR id;None/blank matches everyone.eligible_trials: If given, restrict to patients eligible for any of these trials (union). Each returned patient'seligible_trialslist stays complete regardless of the filter.page: 1-indexed page number.page_size: Number of items per page.
Returns
A PatientList whose items are the requested page and whose
total is the count of all matching patients before pagination.
resolve_scan_path
def resolve_scan_path(self, *, scan_id: str | None, path: str | None) ‑> str | None:Resolve a scan reference to a validated absolute file path.
Exactly one of scan_id/path must be supplied. A scan_id is looked
up in the scan_eligibility store; an explicit path is accepted only if
its real path matches a stored scan's file_path (allowlist), which
blocks path traversal and symlink escape.
Arguments
scan_id: The scan identifier to resolve, or None.path: An explicit filesystem path to validate, or None.
Returns The validated absolute (real) path, or None if unknown/unauthorised.
Raises
ValueError: If not exactly one ofscan_id/pathis supplied.