v2
scan_metadata record, v2 — canonical aliases.
v2 is v1's table, with scan_datetime normalised. There is no schema change
at all: the ORM, the record and the store are v1's, re-exported rather than
copied.
Copying them was the first shape and it was wrong. A version package that
duplicates its predecessor freezes that predecessor as it was on the day it was
copied, so every later change to v1 — new columns, new helpers, a reworded
reason string — silently fails to reach anyone reading through v2. v1 gained a
reasons module and a reworked store within weeks of this being written, and a
copied v2 would have reverted both for its consumers.
What v2 adds is migrations.upgrade, a data migration that rewrites the column
into one comparable spelling. A version is the only thing the migration engine
will hang that on, which is why v2 exists at all.
The record registry requires ORM, Record and store on a version package
and does not care where they come from, so re-exporting satisfies it. Both
versions therefore name one ORM class and one table — deliberately, since they
describe the same table.
Module
Submodules
- bitfount.cache.types.scan_metadata.v2.migrations - Migration for
scan_metadatav1 -> v2: normalisescan_datetime.
Functions
upgrade
def upgrade(op: Operations) ‑> None:Rewrite every scan_datetime into ISO-8601 UTC (see the module docstring).
Idempotent: a row already in the target spelling normalises to itself and is not rewritten, so replaying the hop by hand is safe.
Arguments
op: The bound Alembic operations handle; its connection is the one the caller's per-hop transaction runs in, so the rewrite commits or rolls back with the version bump.
Classes
ORM
class ORM(**kwargs):SQLAlchemy model for the scan_metadata cache table.
Stores vendor-normalized, header-only per-scan metadata (laterality, geometry, patient demographics, device) extracted from ophthalmology files without any pixel decode or model inference. One row per acquisition series.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in kwargs.
Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.
Ancestors
Variables
-
dataset_identifier : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
date_of_birth : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
dimensions_mm_depth : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
dimensions_mm_height : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
dimensions_mm_width : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
file_path : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
first_name : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
fixation : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
gender : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
last_name : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
laterality : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
manufacturer : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
num_bscans : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
patient_key : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
processed_at : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
protocol : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
reason : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
resolutions_mm_depth : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
resolutions_mm_height : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
resolutions_mm_width : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
run_id : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
scan_datetime : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
scanner_model : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
series_description : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
series_index : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
size_height : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
size_width : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
slo_dimensions_mm_height : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
slo_dimensions_mm_width : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
slo_size_height : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
slo_size_width : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
source_file_hash : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
-
tags : Union[sqlalchemy.orm.attributes.InstrumentedAttribute[+_T_co], +_T_co]
Record
class Record(**data: Any):Record of a single stored row from the scan_metadata table (one per scan).
Extends NormalizedScanFields with the composite primary key
(file_path, series_index) and the control/provenance columns.
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.
Ancestors
Variables
- static
dataset_identifier : str | None
- static
file_path : str
- static
model_config
- static
processed_at : datetime.datetime
- static
reason : str | None
- static
run_id : str | None
- static
series_index : int
- static
source_file_hash : str | None
- static
tags : dict[str, typing.Any] | None