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