Source code for phenotypic.schema._rembi

"""REMBI module taxonomy for classifying metadata columns.

REMBI (Recommended Metadata for Biological Images; Sarkans et al. 2021) groups
bioimage provenance into modules. Each metadata enum declares its module via
``MeasurementInfo.rembi_module()``; measurement/locator enums fall back to
``ANALYZED_DATA``. Definition order is the canonical manifest/section order.

Import-light: stdlib only (see schema package load-order rule).
"""
from __future__ import annotations

from enum import Enum
from functools import lru_cache


[docs] class REMBI_MODULE(str, Enum): """REMBI metadata modules. Definition order is canonical.""" STUDY = "Study" BIOSAMPLE = "Biosample" SPECIMEN_PREP = "SpecimenPreparation" IMAGE_ACQUISITION = "ImageAcquisition" IMAGE_DATA = "ImageData" ANALYZED_DATA = "AnalyzedData" UNCATEGORIZED = "Uncategorized"
[docs] @lru_cache(maxsize=1) def header_to_module() -> "dict[str, REMBI_MODULE]": """Map every known column header to its REMBI module. Walks every ``MeasurementInfo`` subclass exported from ``phenotypic.schema`` and reads each member's ``resolved_rembi_module``. Cached (``lru_cache``): the mapping derives entirely from the import-time schema enums, which are fixed once the package is imported, so there is no staleness concern and the hot-path callers (manifest builder + metadata accessor) skip the walk on every call after the first. The returned dict is read-only by contract; callers must not mutate it (mirrors :func:`_label_to_category`). """ from . import __all__ as _names from . import _measurement_info as _mi import phenotypic.schema as _schema out: "dict[str, REMBI_MODULE]" = {} for name in _names: obj = getattr(_schema, name) if (isinstance(obj, type) and issubclass(obj, _mi.MeasurementInfo) and obj is not _mi.MeasurementInfo and list(obj)): for member in obj: out[member.value] = member.resolved_rembi_module return out