11"""Common utilities for GeoZarr data API."""
22
3+ from __future__ import annotations
4+
35import io
46import urllib
57import urllib .request
68from dataclasses import dataclass
7- from typing import Annotated , Any , Mapping , Self , TypeGuard , TypeVar
9+ from typing import Annotated , Any , Mapping , NotRequired , Self , TypeGuard , TypeVar
810from urllib .error import URLError
911
1012from cf_xarray .utils import parse_cf_standard_name_table
1113from pydantic import AfterValidator , BaseModel , Field , model_validator
1214from pydantic .experimental .missing_sentinel import MISSING
13- from typing_extensions import Final , Literal , Protocol , runtime_checkable
15+ from typing_extensions import Final , Literal , Protocol , TypedDict , runtime_checkable
1416
1517from eopf_geozarr .data_api .geozarr .projjson import ProjJSON
16- from eopf_geozarr .data_api .geozarr .types import ResamplingMethod
1718
1819
1920@dataclass (frozen = True )
@@ -28,6 +29,35 @@ class UNSET_TYPE:
2829GEO_PROJ_VERSION : Final = "0.1"
2930
3031
32+ class ZarrConventionMetadata (BaseModel ):
33+ uuid : str | MISSING = MISSING
34+ schema_url : str | MISSING = MISSING
35+ spec_url : str | MISSING = MISSING
36+ name : str | MISSING = MISSING
37+ description : str | MISSING = MISSING
38+
39+ @model_validator (mode = "after" )
40+ def ensure_identifiable (self ) -> Self :
41+ if (
42+ self .uuid is MISSING
43+ and self .schema_url is MISSING
44+ and self .spec_url is MISSING
45+ ):
46+ raise ValueError (
47+ "At least one of uuid, schema_url, or spec_url must be provided."
48+ )
49+
50+ return self
51+
52+
53+ class ZarrConventionMetadataJSON (TypedDict ):
54+ uuid : NotRequired [str ]
55+ schema_url : NotRequired [str ]
56+ name : NotRequired [str ]
57+ description : NotRequired [str ]
58+ spec_url : NotRequired [str ]
59+
60+
3161class ProjAttrs (BaseModel , extra = "allow" ):
3262 """
3363 Zarr attributes for coordinate reference system (CRS) encoding.
@@ -220,57 +250,6 @@ def array_dimensions(self) -> tuple[str, ...]: ...
220250 attributes : BaseDataArrayAttrs
221251
222252
223- class TileMatrixLimit (BaseModel ):
224- """"""
225-
226- tileMatrix : str
227- minTileCol : int
228- minTileRow : int
229- maxTileCol : int
230- maxTileRow : int
231-
232-
233- class TileMatrix (BaseModel ):
234- id : str
235- scaleDenominator : float
236- cellSize : float
237- pointOfOrigin : tuple [float , float ]
238- tileWidth : int
239- tileHeight : int
240- matrixWidth : int
241- matrixHeight : int
242-
243-
244- class TileMatrixSet (BaseModel ):
245- id : str
246- title : str | None = None
247- crs : str | None = None
248- supportedCRS : str | None = None
249- orderedAxes : tuple [str , str ] | None = None
250- tileMatrices : tuple [TileMatrix , ...]
251-
252-
253- class TMSMultiscales (BaseModel , extra = "allow" ):
254- """
255- Multiscale metadata for a GeoZarr dataset based on the OGC TileMatrixSet standard
256-
257- Attributes
258- ----------
259- tile_matrix_set : str
260- The tile matrix set identifier for the multiscale dataset.
261- resampling_method : ResamplingMethod
262- The name of the resampling method for the multiscale dataset.
263- tile_matrix_set_limits : dict[str, TileMatrixSetLimits] | None, optional
264- The tile matrix set limits for the multiscale dataset.
265- """
266-
267- tile_matrix_set : TileMatrixSet
268- resampling_method : ResamplingMethod
269- # TODO: ensure that the keys match tile_matrix_set.tileMatrices[$index].id
270- # TODO: ensure that the keys match the tileMatrix attribute
271- tile_matrix_limits : dict [str , TileMatrixLimit ] | None = None
272-
273-
274253class DatasetAttrs (BaseModel , extra = "allow" ):
275254 """
276255 Attributes for a GeoZarr dataset.
@@ -295,25 +274,15 @@ def check_grid_mapping(model: TDataSetLike) -> TDataSetLike:
295274 """
296275 if model .members is not None :
297276 for name , member in model .members .items ():
298- if member .attributes .grid_mapping not in model .members :
277+ if (
278+ hasattr (member .attributes , "grid_mapping" )
279+ and isinstance (member .attributes .grid_mapping , str )
280+ and member .attributes .grid_mapping not in model .members
281+ ):
299282 msg = f"Grid mapping variable '{ member .attributes .grid_mapping } ' declared by { name } was not found in dataset members"
300283 raise ValueError (msg )
301284 return model
302285
303286
304- class MultiscaleGroupAttrs (BaseModel , extra = "allow" ):
305- """
306- Attributes for Multiscale GeoZarr dataset.
307-
308- A Multiscale dataset is a collection of Dataet
309-
310- Attributes
311- ----------
312- multiscales: MultiscaleAttrs
313- """
314-
315- multiscales : TMSMultiscales
316-
317-
318287def is_none (data : object ) -> TypeGuard [None ]:
319288 return data is None
0 commit comments