Coverage for openhcs/io/__init__.py: 46.7%

26 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-04 02:09 +0000

1""" 

2Storage backends package for openhcs. 

3 

4This package contains the storage backend implementations for openhcs. 

5""" 

6 

7import os 

8 

9# Essential imports (always available) 

10from .atomic import file_lock, atomic_write_json, atomic_update_json, FileLockError, FileLockTimeoutError 

11from .base import BackendBase, DataSink, DataSource, ReadOnlyBackend, StorageBackend, storage_registry, reset_memory_backend, ensure_storage_registry, get_backend 

12from .backend_registry import ( 

13 get_backend_instance, 

14 cleanup_backend_connections, cleanup_all_backends, STORAGE_BACKENDS 

15) 

16from .disk import DiskStorageBackend 

17from .filemanager import FileManager 

18from .memory import MemoryStorageBackend 

19from .metadata_writer import AtomicMetadataWriter, MetadataWriteError, get_metadata_path, get_subdirectory_name 

20from .metadata_migration import detect_legacy_format, migrate_legacy_metadata, migrate_plate_metadata 

21from .pipeline_migration import detect_legacy_pipeline, migrate_pipeline_file, load_pipeline_with_migration 

22from .streaming import StreamingBackend 

23 

24# GPU-heavy backend classes are imported lazily via __getattr__ below 

25# This prevents blocking imports of zarr (→ ome-zarr → dask → GPU libs) 

26# and streaming backends (→ napari/fiji) 

27 

28__all__ = [ 

29 'BackendBase', 

30 'DataSink', 

31 'DataSource', 

32 'ReadOnlyBackend', 

33 'StorageBackend', 

34 'StreamingBackend', 

35 'storage_registry', 

36 'reset_memory_backend', 

37 'ensure_storage_registry', 

38 'get_backend', 

39 'get_backend_instance', 

40 'cleanup_all_backends', 

41 'STORAGE_BACKENDS', 

42 'DiskStorageBackend', 

43 'MemoryStorageBackend', 

44 'NapariStreamingBackend', 

45 'FijiStreamingBackend', 

46 'ZarrStorageBackend', 

47 'FileManager', 

48 'file_lock', 

49 'atomic_write_json', 

50 'atomic_update_json', 

51 'FileLockError', 

52 'FileLockTimeoutError', 

53 'AtomicMetadataWriter', 

54 'MetadataWriteError', 

55 'get_metadata_path', 

56 'get_subdirectory_name', 

57 'detect_legacy_format', 

58 'migrate_legacy_metadata', 

59 'migrate_plate_metadata', 

60 'detect_legacy_pipeline', 

61 'migrate_pipeline_file', 

62 'load_pipeline_with_migration' 

63] 

64 

65 

66# Registry for lazy-loaded GPU-heavy backends 

67_LAZY_BACKEND_REGISTRY = { 

68 'NapariStreamingBackend': ('openhcs.io.napari_stream', 'NapariStreamingBackend'), 

69 'FijiStreamingBackend': ('openhcs.io.fiji_stream', 'FijiStreamingBackend'), 

70 'ZarrStorageBackend': ('openhcs.io.zarr', 'ZarrStorageBackend'), 

71} 

72 

73 

74def __getattr__(name): 

75 """ 

76 Lazy import of GPU-heavy backend classes. 

77 

78 This prevents blocking imports during `import openhcs.io` while 

79 still allowing code to import backend classes when needed. 

80 """ 

81 # Check if name is in lazy backend registry 

82 if name not in _LAZY_BACKEND_REGISTRY: 

83 raise AttributeError(f"module '{__name__}' has no attribute '{name}'") 

84 

85 # Subprocess runner mode - create placeholder 

86 if os.getenv('OPENHCS_SUBPROCESS_NO_GPU') == '1': 

87 class PlaceholderBackend: 

88 """Placeholder for subprocess runner mode.""" 

89 pass 

90 PlaceholderBackend.__name__ = name 

91 PlaceholderBackend.__qualname__ = name 

92 return PlaceholderBackend 

93 

94 # Normal mode - lazy import from registry 

95 module_path, class_name = _LAZY_BACKEND_REGISTRY[name] 

96 import importlib 

97 module = importlib.import_module(module_path) 

98 return getattr(module, class_name)