ngio 0.2.0a2__py3-none-any.whl → 0.2.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. ngio/__init__.py +4 -4
  2. ngio/common/__init__.py +12 -2
  3. ngio/common/_array_pipe.py +106 -0
  4. ngio/common/_axes_transforms.py +3 -2
  5. ngio/common/_dimensions.py +7 -0
  6. ngio/common/_masking_roi.py +158 -0
  7. ngio/common/_pyramid.py +16 -11
  8. ngio/common/_roi.py +74 -0
  9. ngio/common/_slicer.py +1 -2
  10. ngio/common/_zoom.py +5 -3
  11. ngio/hcs/__init__.py +2 -57
  12. ngio/hcs/plate.py +399 -0
  13. ngio/images/abstract_image.py +97 -28
  14. ngio/images/create.py +48 -29
  15. ngio/images/image.py +121 -57
  16. ngio/images/label.py +131 -86
  17. ngio/images/masked_image.py +259 -0
  18. ngio/images/omezarr_container.py +250 -77
  19. ngio/ome_zarr_meta/__init__.py +25 -13
  20. ngio/ome_zarr_meta/_meta_handlers.py +718 -69
  21. ngio/ome_zarr_meta/ngio_specs/__init__.py +8 -0
  22. ngio/ome_zarr_meta/ngio_specs/_channels.py +11 -0
  23. ngio/ome_zarr_meta/ngio_specs/_ngio_hcs.py +374 -2
  24. ngio/ome_zarr_meta/ngio_specs/_ngio_image.py +174 -113
  25. ngio/ome_zarr_meta/ngio_specs/_pixel_size.py +35 -3
  26. ngio/ome_zarr_meta/v04/__init__.py +17 -5
  27. ngio/ome_zarr_meta/v04/_v04_spec_utils.py +85 -12
  28. ngio/tables/__init__.py +2 -0
  29. ngio/tables/_validators.py +2 -4
  30. ngio/tables/backends/_anndata_utils.py +2 -1
  31. ngio/tables/backends/_anndata_v1.py +2 -1
  32. ngio/tables/backends/_json_v1.py +1 -1
  33. ngio/tables/tables_container.py +12 -2
  34. ngio/tables/v1/__init__.py +1 -2
  35. ngio/tables/v1/_feature_table.py +7 -5
  36. ngio/tables/v1/_generic_table.py +65 -11
  37. ngio/tables/v1/_roi_table.py +145 -27
  38. ngio/utils/__init__.py +3 -0
  39. ngio/utils/_datasets.py +4 -2
  40. ngio/utils/_fractal_fsspec_store.py +13 -0
  41. ngio/utils/_logger.py +3 -1
  42. ngio/utils/_zarr_utils.py +25 -2
  43. {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/METADATA +4 -1
  44. ngio-0.2.0b1.dist-info/RECORD +54 -0
  45. ngio/ome_zarr_meta/_generic_handlers.py +0 -320
  46. ngio/ome_zarr_meta/v04/_meta_handlers.py +0 -54
  47. ngio/tables/v1/_masking_roi_table.py +0 -175
  48. ngio-0.2.0a2.dist-info/RECORD +0 -53
  49. {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/WHEEL +0 -0
  50. {ngio-0.2.0a2.dist-info → ngio-0.2.0b1.dist-info}/licenses/LICENSE +0 -0
@@ -1,60 +1,400 @@
1
- from typing import Any, Generic, TypeVar
1
+ """Base class for handling OME-NGFF metadata in Zarr groups."""
2
+
3
+ from typing import Generic, Protocol, TypeVar
2
4
 
3
5
  from pydantic import ValidationError
4
6
 
5
- from ngio.ome_zarr_meta._generic_handlers import (
6
- ImageMetaHandler,
7
- LabelMetaHandler,
7
+ from ngio.ome_zarr_meta.ngio_specs import (
8
+ AxesSetup,
9
+ NgioImageMeta,
10
+ NgioLabelMeta,
11
+ NgioPlateMeta,
12
+ NgioWellMeta,
13
+ )
14
+ from ngio.ome_zarr_meta.v04 import (
15
+ ngio_to_v04_image_meta,
16
+ ngio_to_v04_label_meta,
17
+ ngio_to_v04_plate_meta,
18
+ ngio_to_v04_well_meta,
19
+ v04_to_ngio_image_meta,
20
+ v04_to_ngio_label_meta,
21
+ v04_to_ngio_plate_meta,
22
+ v04_to_ngio_well_meta,
8
23
  )
9
- from ngio.ome_zarr_meta.ngio_specs import AxesSetup
10
- from ngio.ome_zarr_meta.v04 import V04ImageMetaHandler, V04LabelMetaHandler
11
24
  from ngio.utils import (
12
- AccessModeLiteral,
13
25
  NgioValidationError,
14
26
  NgioValueError,
15
- StoreOrGroup,
16
27
  ZarrGroupHandler,
17
28
  )
18
29
 
19
- _Image_or_Label_Plugin = TypeVar(
20
- "_Image_or_Label_Plugin", ImageMetaHandler, LabelMetaHandler
30
+ ConverterError = ValidationError | Exception | None
31
+
32
+ ###########################################################################
33
+ #
34
+ # The code below implements a generic class for handling OME-Zarr metadata
35
+ # in Zarr groups.
36
+ #
37
+ ###########################################################################
38
+
39
+
40
+ class ImageMetaImporter(Protocol):
41
+ @staticmethod
42
+ def __call__(
43
+ metadata: dict,
44
+ axes_setup: AxesSetup | None = None,
45
+ allow_non_canonical_axes: bool = False,
46
+ strict_canonical_order: bool = True,
47
+ ) -> tuple[bool, NgioImageMeta | ConverterError]:
48
+ """Convert the metadata to a NgioImageMeta object.
49
+
50
+ Args:
51
+ metadata (dict): The metadata (typically from a Zarr group .attrs).
52
+ axes_setup (AxesSetup, optional): The axes setup.
53
+ This is used to map axes with non-canonical names.
54
+ allow_non_canonical_axes (bool, optional): Whether to allow non-canonical
55
+ axes.
56
+ strict_canonical_order (bool, optional): Whether to enforce a strict
57
+ canonical order.
58
+
59
+ Returns:
60
+ tuple[bool, NgioImageMeta | ConverterError]: A tuple with a boolean
61
+ indicating whether the conversion was successful and the
62
+ NgioImageMeta object or an error.
63
+
64
+ """
65
+ ...
66
+
67
+
68
+ class ImageMetaExporter(Protocol):
69
+ def __call__(self, metadata: NgioImageMeta) -> dict: ...
70
+
71
+
72
+ class LabelMetaImporter(Protocol):
73
+ @staticmethod
74
+ def __call__(
75
+ metadata: dict,
76
+ axes_setup: AxesSetup | None = None,
77
+ allow_non_canonical_axes: bool = False,
78
+ strict_canonical_order: bool = True,
79
+ ) -> tuple[bool, NgioLabelMeta | ConverterError]:
80
+ """Convert the metadata to a NgioLabelMeta object.
81
+
82
+ Args:
83
+ metadata (dict): The metadata (typically from a Zarr group .attrs).
84
+ axes_setup (AxesSetup, optional): The axes setup.
85
+ This is used to map axes with non-canonical names.
86
+ allow_non_canonical_axes (bool, optional): Whether to allow non-canonical
87
+ axes.
88
+ strict_canonical_order (bool, optional): Whether to enforce a strict
89
+ canonical order.
90
+
91
+ Returns:
92
+ tuple[bool, NgioLabelMeta | ConverterError]: A tuple with a boolean
93
+ indicating whether the conversion was successful and the
94
+ NgioLabelMeta object or an error.
95
+
96
+ """
97
+ ...
98
+
99
+
100
+ class LabelMetaExporter(Protocol):
101
+ def __call__(self, metadata: NgioLabelMeta) -> dict: ...
102
+
103
+
104
+ class WellMetaImporter(Protocol):
105
+ def __call__(
106
+ self, metadata: dict
107
+ ) -> tuple[bool, NgioWellMeta | ConverterError]: ...
108
+
109
+
110
+ class WellMetaExporter(Protocol):
111
+ def __call__(self, metadata: NgioWellMeta) -> dict: ...
112
+
113
+
114
+ class PlateMetaImporter(Protocol):
115
+ def __call__(
116
+ self, metadata: dict
117
+ ) -> tuple[bool, NgioPlateMeta | ConverterError]: ...
118
+
119
+
120
+ class PlateMetaExporter(Protocol):
121
+ def __call__(self, metadata: NgioPlateMeta) -> dict: ...
122
+
123
+
124
+ ###########################################################################
125
+ #
126
+ # Image and label metadata handlers
127
+ #
128
+ ###########################################################################
129
+
130
+ _image_meta = TypeVar("_image_meta", NgioImageMeta, NgioLabelMeta)
131
+ _image_meta_importer = TypeVar(
132
+ "_image_meta_importer", ImageMetaImporter, LabelMetaImporter
133
+ )
134
+ _image_meta_exporter = TypeVar(
135
+ "_image_meta_exporter", ImageMetaExporter, LabelMetaExporter
136
+ )
137
+
138
+
139
+ class GenericMetaHandler(
140
+ Generic[_image_meta, _image_meta_importer, _image_meta_exporter]
141
+ ):
142
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
143
+
144
+ def __init__(
145
+ self,
146
+ meta_importer: _image_meta_importer,
147
+ meta_exporter: _image_meta_exporter,
148
+ group_handler: ZarrGroupHandler,
149
+ axes_setup: AxesSetup | None = None,
150
+ allow_non_canonical_axes: bool = False,
151
+ strict_canonical_order: bool = True,
152
+ ):
153
+ """Initialize the handler.
154
+
155
+ Args:
156
+ meta_importer (MetaImporter): The metadata importer.
157
+ meta_exporter (MetaExporter): The metadata exporter.
158
+ group_handler (ZarrGroupHandler): The Zarr group handler.
159
+ axes_setup (AxesSetup, optional): The axes setup.
160
+ This is used to map axes with non-canonical names.
161
+ allow_non_canonical_axes (bool, optional): Whether to allow non-canonical
162
+ axes.
163
+ strict_canonical_order (bool, optional): Whether to enforce a strict
164
+ canonical order.
165
+ """
166
+ self._group_handler = group_handler
167
+ self._meta_importer = meta_importer
168
+ self._meta_exporter = meta_exporter
169
+ self._axes_setup = axes_setup
170
+ self._allow_non_canonical_axes = allow_non_canonical_axes
171
+ self._strict_canonical_order = strict_canonical_order
172
+
173
+ def _load_meta(self, return_error: bool = False):
174
+ """Load the metadata from the store."""
175
+ attrs = self._group_handler.load_attrs()
176
+ is_valid, meta_or_error = self._meta_importer(
177
+ metadata=attrs,
178
+ axes_setup=self._axes_setup,
179
+ allow_non_canonical_axes=self._allow_non_canonical_axes,
180
+ strict_canonical_order=self._strict_canonical_order,
181
+ )
182
+ if is_valid:
183
+ return meta_or_error
184
+
185
+ if return_error:
186
+ return meta_or_error
187
+
188
+ raise NgioValueError(f"Could not load metadata: {meta_or_error}")
189
+
190
+ def safe_load_meta(self) -> _image_meta | ConverterError:
191
+ """Load the metadata from the store."""
192
+ return self._load_meta(return_error=True)
193
+
194
+ def _write_meta(self, meta) -> None:
195
+ """Write the metadata to the store."""
196
+ _meta = self._meta_exporter(metadata=meta)
197
+ self._group_handler.write_attrs(_meta)
198
+
199
+ def write_meta(self, meta: _image_meta) -> None:
200
+ self._write_meta(meta)
201
+
202
+ @property
203
+ def meta(self) -> _image_meta:
204
+ """Return the metadata."""
205
+ raise NotImplementedError("This method should be implemented in a subclass.")
206
+
207
+
208
+ class ImageMetaHandler(
209
+ GenericMetaHandler[NgioImageMeta, ImageMetaImporter, ImageMetaExporter]
210
+ ):
211
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
212
+
213
+ @property
214
+ def meta(self) -> NgioImageMeta:
215
+ meta = self._load_meta()
216
+ if isinstance(meta, NgioImageMeta):
217
+ return meta
218
+ raise NgioValueError(f"Could not load metadata: {meta}")
219
+
220
+
221
+ class LabelMetaHandler(
222
+ GenericMetaHandler[NgioLabelMeta, LabelMetaImporter, LabelMetaExporter]
223
+ ):
224
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
225
+
226
+ @property
227
+ def meta(self) -> NgioLabelMeta:
228
+ meta = self._load_meta()
229
+ if isinstance(meta, NgioLabelMeta):
230
+ return meta
231
+ raise NgioValueError(f"Could not load metadata: {meta}")
232
+
233
+
234
+ ###########################################################################
235
+ #
236
+ # Well and plate metadata handlers
237
+ #
238
+ ###########################################################################
239
+
240
+ _hcs_meta = TypeVar("_hcs_meta", NgioWellMeta, NgioPlateMeta)
241
+ _hcs_meta_importer = TypeVar("_hcs_meta_importer", WellMetaImporter, PlateMetaImporter)
242
+ _hcs_meta_exporter = TypeVar("_hcs_meta_exporter", WellMetaExporter, PlateMetaExporter)
243
+
244
+
245
+ class GenericHCSMetaHandler(Generic[_hcs_meta, _hcs_meta_importer, _hcs_meta_exporter]):
246
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
247
+
248
+ def __init__(
249
+ self,
250
+ meta_importer: _hcs_meta_importer,
251
+ meta_exporter: _hcs_meta_exporter,
252
+ group_handler: ZarrGroupHandler,
253
+ ):
254
+ self._group_handler = group_handler
255
+ self._meta_importer = meta_importer
256
+ self._meta_exporter = meta_exporter
257
+
258
+ def _load_meta(self, return_error: bool = False):
259
+ """Load the metadata from the store."""
260
+ attrs = self._group_handler.load_attrs()
261
+ is_valid, meta_or_error = self._meta_importer(metadata=attrs)
262
+ if is_valid:
263
+ return meta_or_error
264
+
265
+ if return_error:
266
+ return meta_or_error
267
+
268
+ raise NgioValueError(f"Could not load metadata: {meta_or_error}")
269
+
270
+ def safe_load_meta(self) -> _hcs_meta | ConverterError:
271
+ """Load the metadata from the store."""
272
+ return self._load_meta(return_error=True)
273
+
274
+ def _write_meta(self, meta) -> None:
275
+ _meta = self._meta_exporter(metadata=meta)
276
+ self._group_handler.write_attrs(_meta)
277
+
278
+ def write_meta(self, meta: _hcs_meta) -> None:
279
+ self._write_meta(meta)
280
+
281
+ @property
282
+ def meta(self) -> _hcs_meta:
283
+ raise NotImplementedError("This method should be implemented in a subclass.")
284
+
285
+
286
+ class WellMetaHandler(
287
+ GenericHCSMetaHandler[NgioWellMeta, WellMetaImporter, WellMetaExporter]
288
+ ):
289
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
290
+
291
+ @property
292
+ def meta(self) -> NgioWellMeta:
293
+ meta = self._load_meta()
294
+ if isinstance(meta, NgioWellMeta):
295
+ return meta
296
+ raise NgioValueError(f"Could not load metadata: {meta}")
297
+
298
+
299
+ class PlateMetaHandler(
300
+ GenericHCSMetaHandler[NgioPlateMeta, PlateMetaImporter, PlateMetaExporter]
301
+ ):
302
+ """Generic class for handling OME-Zarr metadata in Zarr groups."""
303
+
304
+ @property
305
+ def meta(self) -> NgioPlateMeta:
306
+ meta = self._load_meta()
307
+ if isinstance(meta, NgioPlateMeta):
308
+ return meta
309
+ raise NgioValueError(f"Could not load metadata: {meta}")
310
+
311
+
312
+ ###########################################################################
313
+ #
314
+ # Metadata importer/exporter registration & builder classes
315
+ #
316
+ ###########################################################################
317
+
318
+
319
+ _meta_exporter = TypeVar(
320
+ "_meta_exporter",
321
+ ImageMetaExporter,
322
+ LabelMetaExporter,
323
+ WellMetaExporter,
324
+ PlateMetaExporter,
325
+ )
326
+ _meta_importer = TypeVar(
327
+ "_meta_importer",
328
+ ImageMetaImporter,
329
+ LabelMetaImporter,
330
+ WellMetaImporter,
331
+ PlateMetaImporter,
21
332
  )
22
333
 
23
334
 
24
- class _ImplementedMetaHandlers(Generic[_Image_or_Label_Plugin]):
25
- """This class is a singleton that manages the available image handler plugins."""
335
+ class _ImporterExporter(Generic[_meta_importer, _meta_exporter]):
336
+ def __init__(
337
+ self,
338
+ version: str,
339
+ importer: _meta_importer,
340
+ exporter: _meta_exporter,
341
+ ):
342
+ self.importer = importer
343
+ self.exporter = exporter
344
+ self.version = version
345
+
346
+
347
+ ImageImporterExporter = _ImporterExporter[ImageMetaImporter, ImageMetaExporter]
348
+ LabelImporterExporter = _ImporterExporter[LabelMetaImporter, LabelMetaExporter]
349
+ WellImporterExporter = _ImporterExporter[WellMetaImporter, WellMetaExporter]
350
+ PlateImporterExporter = _ImporterExporter[PlateMetaImporter, PlateMetaExporter]
351
+
352
+ _importer_exporter = TypeVar(
353
+ "_importer_exporter",
354
+ ImageImporterExporter,
355
+ LabelImporterExporter,
356
+ WellImporterExporter,
357
+ PlateImporterExporter,
358
+ )
359
+ _image_handler = TypeVar("_image_handler", ImageMetaHandler, LabelMetaHandler)
360
+ _hcs_handler = TypeVar("_hcs_handler", WellMetaHandler, PlateMetaHandler)
361
+
26
362
 
363
+ class ImplementedMetaImporterExporter:
27
364
  _instance = None
28
- _implemented_handlers: dict[str, Any]
365
+ _image_ie: dict[str, ImageImporterExporter]
366
+ _label_ie: dict[str, LabelImporterExporter]
367
+ _well_ie: dict[str, WellImporterExporter]
368
+ _plate_ie: dict[str, PlateImporterExporter]
29
369
 
30
370
  def __new__(cls):
31
371
  """Create a new instance of the class if it does not exist."""
32
372
  if cls._instance is None:
33
373
  cls._instance = super().__new__(cls)
34
- cls._instance._implemented_handlers = {}
374
+ cls._image_ie = {}
375
+ cls._label_ie = {}
376
+ cls._well_ie = {}
377
+ cls._plate_ie = {}
35
378
  return cls._instance
36
379
 
37
- def available_handlers(self) -> list[str]:
38
- """Get the available image handler versions.
39
-
40
- The versions are returned in descending order.
41
- such that the latest version is the first in the list and the fist to be
42
- checked.
43
- """
44
- return list(reversed(self._implemented_handlers.keys()))
45
-
46
- def find_meta_handler(
380
+ def _find_image_handler(
47
381
  self,
48
382
  group_handler: ZarrGroupHandler,
49
383
  axes_setup: AxesSetup | None = None,
50
384
  allow_non_canonical_axes: bool = False,
51
385
  strict_canonical_order: bool = True,
52
- ) -> _Image_or_Label_Plugin:
53
- """Try to get a handler for the given store based on the metadata version."""
386
+ _ie_name: str = "_image_ie",
387
+ _handler: type[_image_handler] = ImageMetaHandler,
388
+ ) -> _image_handler:
389
+ """Get an image metadata handler."""
54
390
  _errors = {}
55
391
 
56
- for version, handler in reversed(self._implemented_handlers.items()):
57
- handler = handler(
392
+ dict_ie = self.__getattribute__(_ie_name)
393
+
394
+ for ie in reversed(dict_ie.values()):
395
+ handler = _handler(
396
+ meta_importer=ie.importer,
397
+ meta_exporter=ie.exporter,
58
398
  group_handler=group_handler,
59
399
  axes_setup=axes_setup,
60
400
  allow_non_canonical_axes=allow_non_canonical_axes,
@@ -62,81 +402,390 @@ class _ImplementedMetaHandlers(Generic[_Image_or_Label_Plugin]):
62
402
  )
63
403
  meta = handler.safe_load_meta()
64
404
  if isinstance(meta, ValidationError):
65
- _errors[version] = meta
405
+ _errors[ie.version] = meta
66
406
  continue
67
407
  return handler
68
408
 
69
409
  raise NgioValidationError(
70
- f"Could not load OME-Zarr metadata from any known version. "
71
- f"Errors: {_errors}"
410
+ f"Could not load metadata from any known version. Errors: {_errors}"
72
411
  )
73
412
 
74
- def get_handler(
413
+ def find_image_handler(
75
414
  self,
76
- version: str,
77
415
  group_handler: ZarrGroupHandler,
78
416
  axes_setup: AxesSetup | None = None,
79
417
  allow_non_canonical_axes: bool = False,
80
418
  strict_canonical_order: bool = True,
81
- ) -> _Image_or_Label_Plugin:
82
- """Get a handler for a specific version."""
83
- if version not in self._implemented_handlers:
419
+ ) -> ImageMetaHandler:
420
+ """Get an image metadata handler."""
421
+ return self._find_image_handler(
422
+ group_handler=group_handler,
423
+ axes_setup=axes_setup,
424
+ allow_non_canonical_axes=allow_non_canonical_axes,
425
+ strict_canonical_order=strict_canonical_order,
426
+ _ie_name="_image_ie",
427
+ _handler=ImageMetaHandler,
428
+ )
429
+
430
+ def get_image_meta_handler(
431
+ self,
432
+ group_handler: ZarrGroupHandler,
433
+ version: str,
434
+ axes_setup: AxesSetup | None = None,
435
+ allow_non_canonical_axes: bool = False,
436
+ strict_canonical_order: bool = True,
437
+ ) -> ImageMetaHandler:
438
+ """Get an image metadata handler."""
439
+ if version not in self._image_ie:
84
440
  raise NgioValueError(f"Image handler for version {version} does not exist.")
85
- return self._implemented_handlers[version](
441
+
442
+ image_ie = self._image_ie[version]
443
+ return ImageMetaHandler(
444
+ meta_importer=image_ie.importer,
445
+ meta_exporter=image_ie.exporter,
446
+ group_handler=group_handler,
447
+ axes_setup=axes_setup,
448
+ allow_non_canonical_axes=allow_non_canonical_axes,
449
+ strict_canonical_order=strict_canonical_order,
450
+ )
451
+
452
+ def _register(
453
+ self,
454
+ version: str,
455
+ importer: _importer_exporter,
456
+ overwrite: bool = False,
457
+ _ie_name: str = "_image_ie",
458
+ ):
459
+ """Register an importer/exporter."""
460
+ ie_dict = self.__getattribute__(_ie_name)
461
+ if version in ie_dict and not overwrite:
462
+ raise NgioValueError(
463
+ f"Importer/exporter for version {version} already exists. "
464
+ "Use 'overwrite=True' to overwrite."
465
+ )
466
+ ie_dict[version] = importer
467
+
468
+ def register_image_ie(
469
+ self,
470
+ version: str,
471
+ importer: ImageMetaImporter,
472
+ exporter: ImageMetaExporter,
473
+ overwrite: bool = False,
474
+ ):
475
+ """Register an importer/exporter."""
476
+ importer_exporter = ImageImporterExporter(
477
+ version=version, importer=importer, exporter=exporter
478
+ )
479
+ self._register(
480
+ version=version,
481
+ importer=importer_exporter,
482
+ overwrite=overwrite,
483
+ _ie_name="_image_ie",
484
+ )
485
+
486
+ def find_label_handler(
487
+ self,
488
+ group_handler: ZarrGroupHandler,
489
+ axes_setup: AxesSetup | None = None,
490
+ allow_non_canonical_axes: bool = False,
491
+ strict_canonical_order: bool = True,
492
+ ) -> LabelMetaHandler:
493
+ """Get a label metadata handler."""
494
+ return self._find_image_handler(
86
495
  group_handler=group_handler,
87
496
  axes_setup=axes_setup,
88
497
  allow_non_canonical_axes=allow_non_canonical_axes,
89
498
  strict_canonical_order=strict_canonical_order,
499
+ _ie_name="_label_ie",
500
+ _handler=LabelMetaHandler,
501
+ )
502
+
503
+ def get_label_meta_handler(
504
+ self,
505
+ group_handler: ZarrGroupHandler,
506
+ version: str,
507
+ axes_setup: AxesSetup | None = None,
508
+ allow_non_canonical_axes: bool = False,
509
+ strict_canonical_order: bool = True,
510
+ ) -> LabelMetaHandler:
511
+ """Get a label metadata handler."""
512
+ if version not in self._label_ie:
513
+ raise NgioValueError(f"Label handler for version {version} does not exist.")
514
+
515
+ label_ie = self._label_ie[version]
516
+ return LabelMetaHandler(
517
+ meta_importer=label_ie.importer,
518
+ meta_exporter=label_ie.exporter,
519
+ group_handler=group_handler,
520
+ axes_setup=axes_setup,
521
+ allow_non_canonical_axes=allow_non_canonical_axes,
522
+ strict_canonical_order=strict_canonical_order,
523
+ )
524
+
525
+ def register_label_ie(
526
+ self,
527
+ version: str,
528
+ importer: LabelMetaImporter,
529
+ exporter: LabelMetaExporter,
530
+ overwrite: bool = False,
531
+ ):
532
+ """Register an importer/exporter."""
533
+ importer_exporter = LabelImporterExporter(
534
+ version=version, importer=importer, exporter=exporter
535
+ )
536
+ self._register(
537
+ version=version,
538
+ importer=importer_exporter,
539
+ overwrite=overwrite,
540
+ _ie_name="_label_ie",
541
+ )
542
+
543
+ def _find_hcs_handler(
544
+ self,
545
+ group_handler: ZarrGroupHandler,
546
+ _ie_name: str = "_well_ie",
547
+ _handler: type[_hcs_handler] = WellMetaHandler,
548
+ ) -> _hcs_handler:
549
+ """Get a handler for a HCS metadata."""
550
+ _errors = {}
551
+
552
+ dict_ie = self.__getattribute__(_ie_name)
553
+
554
+ for ie in reversed(dict_ie.values()):
555
+ handler = _handler(
556
+ meta_importer=ie.importer,
557
+ meta_exporter=ie.exporter,
558
+ group_handler=group_handler,
559
+ )
560
+ meta = handler.safe_load_meta()
561
+ if isinstance(meta, ValidationError):
562
+ _errors[ie.version] = meta
563
+ continue
564
+ return handler
565
+
566
+ raise NgioValidationError(
567
+ f"Could not load metadata from any known version. Errors: {_errors}"
568
+ )
569
+
570
+ def find_well_handler(
571
+ self,
572
+ group_handler: ZarrGroupHandler,
573
+ ) -> WellMetaHandler:
574
+ """Get a well metadata handler."""
575
+ return self._find_hcs_handler(
576
+ group_handler=group_handler,
577
+ _ie_name="_well_ie",
578
+ _handler=WellMetaHandler,
579
+ )
580
+
581
+ def get_well_meta_handler(
582
+ self,
583
+ group_handler: ZarrGroupHandler,
584
+ version: str,
585
+ ) -> WellMetaHandler:
586
+ """Get a well metadata handler."""
587
+ if version not in self._well_ie:
588
+ raise NgioValueError(f"Well handler for version {version} does not exist.")
589
+
590
+ well_ie = self._well_ie[version]
591
+ return WellMetaHandler(
592
+ meta_importer=well_ie.importer,
593
+ meta_exporter=well_ie.exporter,
594
+ group_handler=group_handler,
595
+ )
596
+
597
+ def register_well_ie(
598
+ self,
599
+ version: str,
600
+ importer: WellMetaImporter,
601
+ exporter: WellMetaExporter,
602
+ overwrite: bool = False,
603
+ ):
604
+ """Register an importer/exporter."""
605
+ importer_exporter = WellImporterExporter(
606
+ version=version, importer=importer, exporter=exporter
607
+ )
608
+ self._register(
609
+ version=version,
610
+ importer=importer_exporter,
611
+ overwrite=overwrite,
612
+ _ie_name="_well_ie",
613
+ )
614
+
615
+ def find_plate_handler(
616
+ self,
617
+ group_handler: ZarrGroupHandler,
618
+ ) -> PlateMetaHandler:
619
+ """Get a plate metadata handler."""
620
+ return self._find_hcs_handler(
621
+ group_handler=group_handler,
622
+ _ie_name="_plate_ie",
623
+ _handler=PlateMetaHandler,
624
+ )
625
+
626
+ def get_plate_meta_handler(
627
+ self,
628
+ group_handler: ZarrGroupHandler,
629
+ version: str,
630
+ ) -> PlateMetaHandler:
631
+ """Get a plate metadata handler."""
632
+ if version not in self._plate_ie:
633
+ raise NgioValueError(f"Plate handler for version {version} does not exist.")
634
+
635
+ plate_ie = self._plate_ie[version]
636
+ return PlateMetaHandler(
637
+ meta_importer=plate_ie.importer,
638
+ meta_exporter=plate_ie.exporter,
639
+ group_handler=group_handler,
90
640
  )
91
641
 
92
- def add_handler(
93
- self, key: str, handler: type[_Image_or_Label_Plugin], overwrite: bool = False
642
+ def register_plate_ie(
643
+ self,
644
+ version: str,
645
+ importer: PlateMetaImporter,
646
+ exporter: PlateMetaExporter,
647
+ overwrite: bool = False,
94
648
  ):
95
- """Register a new handler."""
96
- if key in self._implemented_handlers and not overwrite:
97
- raise NgioValueError(f"Image handler for version {key} already exists.")
98
- self._implemented_handlers[key] = handler
649
+ """Register an importer/exporter."""
650
+ importer_exporter = PlateImporterExporter(
651
+ version=version, importer=importer, exporter=exporter
652
+ )
653
+ self._register(
654
+ version=version,
655
+ importer=importer_exporter,
656
+ overwrite=overwrite,
657
+ _ie_name="_plate_ie",
658
+ )
99
659
 
100
660
 
101
- class ImplementedImageMetaHandlers(_ImplementedMetaHandlers[ImageMetaHandler]):
102
- def __init__(self):
103
- super().__init__()
661
+ ###########################################################################
662
+ #
663
+ # Register metadata importers/exporters
664
+ #
665
+ ###########################################################################
104
666
 
105
667
 
106
- ImplementedImageMetaHandlers().add_handler("0.4", V04ImageMetaHandler)
668
+ ImplementedMetaImporterExporter().register_image_ie(
669
+ version="0.4",
670
+ importer=v04_to_ngio_image_meta,
671
+ exporter=ngio_to_v04_image_meta,
672
+ )
673
+ ImplementedMetaImporterExporter().register_label_ie(
674
+ version="0.4",
675
+ importer=v04_to_ngio_label_meta,
676
+ exporter=ngio_to_v04_label_meta,
677
+ )
678
+ ImplementedMetaImporterExporter().register_well_ie(
679
+ version="0.4", importer=v04_to_ngio_well_meta, exporter=ngio_to_v04_well_meta
680
+ )
681
+ ImplementedMetaImporterExporter().register_plate_ie(
682
+ version="0.4", importer=v04_to_ngio_plate_meta, exporter=ngio_to_v04_plate_meta
683
+ )
107
684
 
108
685
 
109
- class ImplementedLabelMetaHandlers(_ImplementedMetaHandlers[LabelMetaHandler]):
110
- def __init__(self):
111
- super().__init__()
686
+ ###########################################################################
687
+ #
688
+ # Public functions to avoid direct access to the importer/exporter
689
+ # registration methods
690
+ #
691
+ ###########################################################################
112
692
 
113
693
 
114
- ImplementedLabelMetaHandlers().add_handler("0.4", V04LabelMetaHandler)
694
+ def find_image_meta_handler(
695
+ group_handler: ZarrGroupHandler,
696
+ axes_setup: AxesSetup | None = None,
697
+ allow_non_canonical_axes: bool = False,
698
+ strict_canonical_order: bool = True,
699
+ ) -> ImageMetaHandler:
700
+ """Open an image metadata handler."""
701
+ return ImplementedMetaImporterExporter().find_image_handler(
702
+ group_handler=group_handler,
703
+ axes_setup=axes_setup,
704
+ allow_non_canonical_axes=allow_non_canonical_axes,
705
+ strict_canonical_order=strict_canonical_order,
706
+ )
115
707
 
116
708
 
117
- def open_image_meta_handler(
118
- store: StoreOrGroup,
119
- cache: bool = False,
120
- mode: AccessModeLiteral = "a",
709
+ def get_image_meta_handler(
710
+ group_handler: ZarrGroupHandler,
711
+ version: str,
121
712
  axes_setup: AxesSetup | None = None,
122
713
  allow_non_canonical_axes: bool = False,
123
714
  strict_canonical_order: bool = True,
124
715
  ) -> ImageMetaHandler:
125
- """Open the metadata of an OME-Zarr image.
126
-
127
- Args:
128
- store: The Zarr store or group where the model is
129
- cache: Whether to cache the metadata.
130
- mode: The store access mode.
131
- axes_setup: The axes setup. This is used to map axes with
132
- a non-canonical name to a canonical name.
133
- allow_non_canonical_axes: Whether to allow non-canonical axes.
134
- strict_canonical_order: Whether to enforce strict canonical order.
135
- """
136
- zarr_group_handler = ZarrGroupHandler(store, cache, mode)
137
- return ImplementedImageMetaHandlers().find_meta_handler(
138
- zarr_group_handler,
716
+ """Open an image metadata handler."""
717
+ return ImplementedMetaImporterExporter().get_image_meta_handler(
718
+ group_handler=group_handler,
719
+ version=version,
720
+ axes_setup=axes_setup,
721
+ allow_non_canonical_axes=allow_non_canonical_axes,
722
+ strict_canonical_order=strict_canonical_order,
723
+ )
724
+
725
+
726
+ def find_label_meta_handler(
727
+ group_handler: ZarrGroupHandler,
728
+ axes_setup: AxesSetup | None = None,
729
+ allow_non_canonical_axes: bool = False,
730
+ strict_canonical_order: bool = True,
731
+ ) -> LabelMetaHandler:
732
+ """Open a label metadata handler."""
733
+ return ImplementedMetaImporterExporter().find_label_handler(
734
+ group_handler=group_handler,
139
735
  axes_setup=axes_setup,
140
736
  allow_non_canonical_axes=allow_non_canonical_axes,
141
737
  strict_canonical_order=strict_canonical_order,
142
738
  )
739
+
740
+
741
+ def get_label_meta_handler(
742
+ group_handler: ZarrGroupHandler,
743
+ version: str,
744
+ axes_setup: AxesSetup | None = None,
745
+ allow_non_canonical_axes: bool = False,
746
+ strict_canonical_order: bool = True,
747
+ ) -> LabelMetaHandler:
748
+ """Open a label metadata handler."""
749
+ return ImplementedMetaImporterExporter().get_label_meta_handler(
750
+ group_handler=group_handler,
751
+ version=version,
752
+ axes_setup=axes_setup,
753
+ allow_non_canonical_axes=allow_non_canonical_axes,
754
+ strict_canonical_order=strict_canonical_order,
755
+ )
756
+
757
+
758
+ def find_well_meta_handler(group_handler: ZarrGroupHandler) -> WellMetaHandler:
759
+ """Open a well metadata handler."""
760
+ return ImplementedMetaImporterExporter().find_well_handler(
761
+ group_handler=group_handler,
762
+ )
763
+
764
+
765
+ def get_well_meta_handler(
766
+ group_handler: ZarrGroupHandler,
767
+ version: str,
768
+ ) -> WellMetaHandler:
769
+ """Open a well metadata handler."""
770
+ return ImplementedMetaImporterExporter().get_well_meta_handler(
771
+ group_handler=group_handler,
772
+ version=version,
773
+ )
774
+
775
+
776
+ def find_plate_meta_handler(group_handler: ZarrGroupHandler) -> PlateMetaHandler:
777
+ """Open a plate metadata handler."""
778
+ return ImplementedMetaImporterExporter().find_plate_handler(
779
+ group_handler=group_handler
780
+ )
781
+
782
+
783
+ def get_plate_meta_handler(
784
+ group_handler: ZarrGroupHandler,
785
+ version: str,
786
+ ) -> PlateMetaHandler:
787
+ """Open a plate metadata handler."""
788
+ return ImplementedMetaImporterExporter().get_plate_meta_handler(
789
+ group_handler=group_handler,
790
+ version=version,
791
+ )