Coverage for openhcs/processing/backends/lib_registry/scikit_image_registry.py: 84.6%
39 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 02:09 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 02:09 +0000
1"""
2Clean Scikit-Image Registry Implementation
4Implements clean abstraction with internal library-specific logic.
5All scikit-image-specific details (array compliance, channel_axis, etc.)
6are handled internally without leaking into the ABC.
7"""
8from __future__ import annotations
10import numpy as np
11from typing import Tuple, List
13from openhcs.constants import MemoryType
14from openhcs.core.utils import optional_import
15from .unified_registry import LibraryRegistryBase, RuntimeTestingRegistryBase
17skimage = optional_import("skimage")
20class SkimageRegistry(RuntimeTestingRegistryBase):
21 """Clean scikit-image registry with internal array compliance logic."""
23 # Registry name for auto-registration
24 _registry_name = 'skimage'
26 # Library-specific exclusions (uses common ones)
27 EXCLUSIONS = LibraryRegistryBase.COMMON_EXCLUSIONS
29 # Modules to scan for functions
30 MODULES_TO_SCAN = ['filters', 'morphology', 'segmentation', 'feature',
31 'measure', 'transform', 'restoration', 'exposure']
33 # Memory type for this registry
34 MEMORY_TYPE = MemoryType.NUMPY.value
36 # Float dtype for this registry
37 FLOAT_DTYPE = np.float32
39 def __init__(self):
40 super().__init__("skimage")
42 # ===== ESSENTIAL ABC METHODS =====
43 def get_library_version(self) -> str:
44 return skimage.__version__
46 def is_library_available(self) -> bool:
47 return skimage is not None
49 def get_library_object(self):
50 return skimage
52 def get_module_patterns(self) -> List[str]:
53 """Get module patterns for scikit-image."""
54 return ['skimage']
56 def get_display_name(self) -> str:
57 """Get proper display name for scikit-image."""
58 return 'scikit-image'
60 # ===== HOOK IMPLEMENTATIONS =====
61 def _create_array(self, shape: Tuple[int, ...], dtype):
62 return np.random.rand(*shape).astype(dtype)
64 def _check_first_parameter(self, first_param, func_name: str) -> bool:
65 return (first_param.annotation in [np.ndarray, "np.ndarray", "ndarray"] or
66 first_param.name.lower() in {'image', 'input', 'array', 'img'})
68 def _preprocess_input(self, image, func_name: str):
69 return image # No preprocessing needed for scikit-image
71 def _postprocess_output(self, result, original_image, func_name: str):
72 # ProcessingContract system handles dimensional behavior - no categorization needed
73 return result
75 # ===== LIBRARY-SPECIFIC IMPLEMENTATIONS =====
76 def _generate_function_name(self, name: str, module_name: str) -> str:
77 """Generate function name with module prefix."""
78 return f"{module_name}.{name}"
80 def _stack_2d_results(self, func, test_3d):
81 """Stack 2D results using NumPy."""
82 return np.stack([func(test_3d[z]) for z in range(test_3d.shape[0])])
84 def _arrays_close(self, arr1, arr2):
85 """Compare arrays using NumPy."""
86 return np.allclose(arr1, arr2, rtol=1e-5, atol=1e-8)