"""Abstract interfaces for fungal colony image operations.
Defines the base contracts that power the processing pipeline: enhancers, detectors,
refiners, grid operations, and measurement classes. Implement these to add new steps
tailored to agar plate imaging, building on `MeasurementInfo`, `MeasureFeatures`,
`ImageOperation`, `GridOperation`, and the prefab pipeline foundation.
"""
import importlib as _importlib
from typing import TYPE_CHECKING as _TYPE_CHECKING
from typing import Any as _Any
#: Re-exports that pull in the image core: ``PrefabPipeline`` imports the pipeline, and
#: ``DetectionMode``/``register_detection_mode`` import ``phenotypic._core``, whose
#: ``__init__`` loads the whole image handler chain. Resolving them on first access keeps
#: every ``phenotypic.abc_.*`` import free of the core. It also breaks the cycle
#: ``analysis.abc_._model_fitter`` -> ``abc_.plotting`` -> this ``__init__`` -> pipeline
#: core -> ``_model_fitter``. Defined before the eager imports below, so an import that
#: re-enters this package mid-initialisation still resolves them.
_LAZY_ATTRS: dict[str, str] = {
"PrefabPipeline": "phenotypic.abc_._prefab_pipeline",
"DetectionMode": "phenotypic._core._image_parts.detection_modes",
"register_detection_mode": "phenotypic._core._image_parts.detection_modes",
}
[docs]
def __getattr__(name: str) -> _Any:
"""Resolve a core-dependent re-export on first access and cache it on the package."""
module_name = _LAZY_ATTRS.get(name)
if module_name is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
value = getattr(_importlib.import_module(module_name), name)
globals()[name] = value
return value
def __dir__() -> list[str]:
# ``globals().get`` rather than a bare ``__all__``: this function sits above the eager
# imports for the same reason ``__getattr__`` does, so it is callable in a window where
# ``__all__`` has not been assigned yet. A bare reference raises ``NameError`` there.
return sorted(set(globals()) | set(globals().get("__all__", ())))
if _TYPE_CHECKING:
from phenotypic._core._image_parts.detection_modes import (
DetectionMode,
register_detection_mode,
)
from ._prefab_pipeline import PrefabPipeline
from phenotypic.schema import MeasurementInfo # noqa: E402
from phenotypic.sdk_ import FootprintMixin # noqa: E402
from ._measure_features import MeasureFeatures # noqa: E402
from ._image_operation import ImageOperation # noqa: E402
from ._image_enhancer import ImageEnhancer # noqa: E402
from ._image_denoiser import ImageDenoiser # noqa: E402
from ._enhance_markers import ( # noqa: E402
FocusEdge,
FocusBlob,
Smoothing,
BackgroundSubtraction,
MorphologicalFiltering,
ContrastAdjustment,
)
from ._image_corrector import ImageCorrector # noqa: E402
from ._object_detector import ObjectDetector # noqa: E402
from ._object_refiner import ObjectRefiner # noqa: E402
from ._threshold_detector import ThresholdDetector # noqa: E402
from ._gpu_detector import GpuDetector # noqa: E402
from ._grid_operation import GridOperation # noqa: E402
from ._grid_corrector import GridCorrector # noqa: E402
from ._grid_object_refiner import GridObjectRefiner # noqa: E402
from ._grid_measure import GridMeasureFeatures # noqa: E402
from ._grid_finder import GridFinder # noqa: E402
from ._base_operation import BaseOperation # noqa: E402
from ._grid_object_detector import GridObjectDetector # noqa: E402
from ._post_measurement import PostMeasurement # noqa: E402
__all__ = [
"MeasureFeatures",
"ImageOperation",
"ImageEnhancer",
"ImageDenoiser",
"FocusEdge",
"FocusBlob",
"Smoothing",
"BackgroundSubtraction",
"MorphologicalFiltering",
"ContrastAdjustment",
"ImageCorrector",
"ObjectDetector",
"ObjectRefiner",
"ThresholdDetector",
"GpuDetector",
"GridOperation",
"GridFinder",
"GridCorrector",
"GridObjectRefiner",
"GridMeasureFeatures",
"BaseOperation",
"MeasurementInfo",
"GridObjectDetector",
"PrefabPipeline",
"FootprintMixin",
"PostMeasurement",
"DetectionMode",
"register_detection_mode",
]