Coverage for openhcs/processing/backends/experimental_analysis/format_registry_service.py: 25.9%
67 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"""
2Format registry service for automatic discovery and management.
4This module provides automatic discovery of microscope format registries
5following OpenHCS generic solution principles.
6"""
8from typing import Dict, List, Optional, Type
9from pathlib import Path
11from .format_registry import (
12 MicroscopeFormatRegistryBase,
13 FormatDetectionError,
14 MICROSCOPE_FORMAT_REGISTRIES
15)
18class FormatRegistryService:
19 """
20 Service for automatic discovery and access to microscope format registries.
22 Following OpenHCS generic solution principles, this service automatically
23 discovers all format registry implementations without hardcoded imports.
24 """
26 _registry_cache: Optional[Dict[str, Type[MicroscopeFormatRegistryBase]]] = None
27 _instance_cache: Optional[Dict[str, MicroscopeFormatRegistryBase]] = None
29 @classmethod
30 def _discover_registries(cls) -> Dict[str, Type[MicroscopeFormatRegistryBase]]:
31 """
32 Get all format registry classes from auto-registered dict.
34 Returns:
35 Dictionary mapping format names to registry classes
36 """
37 if cls._registry_cache is not None:
38 return cls._registry_cache
40 # Registries auto-discovered on first access to MICROSCOPE_FORMAT_REGISTRIES
41 cls._registry_cache = MICROSCOPE_FORMAT_REGISTRIES.copy()
42 return cls._registry_cache
46 @classmethod
47 def get_all_format_registries(cls) -> Dict[str, Type[MicroscopeFormatRegistryBase]]:
48 """
49 Get all discovered format registry classes.
51 Returns:
52 Dictionary mapping format names to registry classes
53 """
54 return cls._discover_registries()
56 @classmethod
57 def get_registry_class_for_format(cls, format_name: str) -> Type[MicroscopeFormatRegistryBase]:
58 """
59 Get registry class for specific format.
61 Args:
62 format_name: Name of the microscope format
64 Returns:
65 Registry class for the format
67 Raises:
68 FormatDetectionError: If format is not supported
69 """
70 registries = cls.get_all_format_registries()
72 if format_name not in registries:
73 available_formats = list(registries.keys())
74 raise FormatDetectionError(
75 f"Unsupported format '{format_name}'. Available formats: {available_formats}"
76 )
78 return registries[format_name]
80 @classmethod
81 def get_registry_instance_for_format(cls, format_name: str) -> MicroscopeFormatRegistryBase:
82 """
83 Get registry instance for specific format.
85 Args:
86 format_name: Name of the microscope format
88 Returns:
89 Registry instance for the format
91 Raises:
92 FormatDetectionError: If format is not supported
93 """
94 if cls._instance_cache is None:
95 cls._instance_cache = {}
97 if format_name not in cls._instance_cache:
98 registry_class = cls.get_registry_class_for_format(format_name)
99 cls._instance_cache[format_name] = registry_class()
101 return cls._instance_cache[format_name]
103 @classmethod
104 def detect_format_from_file(cls, file_path: str) -> str:
105 """
106 Automatically detect microscope format from file.
108 Args:
109 file_path: Path to the results file
111 Returns:
112 Detected format name
114 Raises:
115 FormatDetectionError: If format cannot be detected
116 """
117 file_path_obj = Path(file_path)
119 if not file_path_obj.exists():
120 raise FormatDetectionError(f"File not found: {file_path}")
122 registries = cls.get_all_format_registries()
124 # Try each registry to see which one can handle the file
125 for format_name, registry_class in registries.items():
126 try:
127 registry_instance = cls.get_registry_instance_for_format(format_name)
129 # Check if file extension is supported
130 if file_path_obj.suffix in registry_instance.SUPPORTED_EXTENSIONS:
131 # Try to read and process a small sample
132 try:
133 raw_df = registry_instance.read_results(file_path)
134 features = registry_instance.extract_features(raw_df)
136 # If we can extract features, this format works
137 if features:
138 return format_name
140 except Exception:
141 # This format doesn't work, try next one
142 continue
144 except Exception:
145 # Skip this registry if it fails
146 continue
148 # If no format worked, raise error
149 available_formats = list(registries.keys())
150 raise FormatDetectionError(
151 f"Could not detect format for file {file_path}. "
152 f"Available formats: {available_formats}"
153 )
155 @classmethod
156 def get_supported_formats(cls) -> List[str]:
157 """
158 Get list of all supported format names.
160 Returns:
161 List of supported format names
162 """
163 registries = cls.get_all_format_registries()
164 return list(registries.keys())
166 @classmethod
167 def get_supported_extensions(cls) -> Dict[str, List[str]]:
168 """
169 Get mapping of formats to their supported file extensions.
171 Returns:
172 Dictionary mapping format names to supported extensions
173 """
174 registries = cls.get_all_format_registries()
175 extensions_map = {}
177 for format_name, registry_class in registries.items():
178 registry_instance = cls.get_registry_instance_for_format(format_name)
179 extensions_map[format_name] = list(registry_instance.SUPPORTED_EXTENSIONS)
181 return extensions_map
183 @classmethod
184 def clear_cache(cls):
185 """Clear registry and instance caches (useful for testing)."""
186 cls._registry_cache = None
187 cls._instance_cache = None