25
25
ZGROUP_JSON ,
26
26
ChunkCoords ,
27
27
ZarrFormat ,
28
+ _json_convert ,
28
29
)
29
30
from zarr .core .config import config
31
+ from zarr .core .metadata import ArrayMetadata , ArrayV3Metadata
30
32
from zarr .core .sync import SyncMixin , sync
31
33
from zarr .store import StoreLike , StorePath , make_store_path
32
34
from zarr .store .common import ensure_no_existing_node
@@ -77,18 +79,65 @@ def _parse_async_node(node: AsyncArray | AsyncGroup) -> Array | Group:
77
79
raise TypeError (f"Unknown node type, got { type (node )} " )
78
80
79
81
82
+ @dataclass (frozen = True )
83
+ class ConsolidatedMetadata :
84
+ metadata : dict [str , ArrayMetadata | GroupMetadata ]
85
+ kind : Literal ["inline" ] = "inline"
86
+ must_understand : Literal [False ] = False
87
+
88
+ def to_dict (self ) -> dict [str , JSON ]:
89
+ return {
90
+ "kind" : self .kind ,
91
+ "must_understand" : self .must_understand ,
92
+ "metadata" : {k : v .to_dict () for k , v in self .metadata .items ()},
93
+ }
94
+
95
+ @classmethod
96
+ def from_dict (cls , data : dict [str , JSON ]) -> ConsolidatedMetadata :
97
+ data = dict (data )
98
+ raw_metadata = data .get ("metadata" )
99
+ if not isinstance (raw_metadata , dict ):
100
+ raise TypeError ("Unexpected type for 'metadata'" )
101
+
102
+ elif not raw_metadata :
103
+ raise ValueError ("Must specify metadata" )
104
+
105
+ metadata : dict [str , ArrayMetadata | GroupMetadata ]
106
+ if raw_metadata :
107
+ metadata = {}
108
+ for k , v in raw_metadata .items ():
109
+ if not isinstance (v , dict ):
110
+ raise TypeError (f"Invalid value for metadata items. key={ k } , type={ type (v )} " )
111
+
112
+ node_type = v .get ("node_type" , None )
113
+ if node_type == "group" :
114
+ metadata [k ] = GroupMetadata .from_dict (v )
115
+ elif node_type == "array" :
116
+ metadata [k ] = ArrayV3Metadata .from_dict (v )
117
+ else :
118
+ raise ValueError (f"Invalid node_type: '{ node_type } '" )
119
+ # assert data["kind"] == "inline"
120
+ if data ["kind" ] != "inline" :
121
+ raise ValueError
122
+
123
+ if data ["must_understand" ] is not False :
124
+ raise ValueError
125
+ return cls (metadata = metadata )
126
+
127
+
80
128
@dataclass (frozen = True )
81
129
class GroupMetadata (Metadata ):
82
130
attributes : dict [str , Any ] = field (default_factory = dict )
83
131
zarr_format : ZarrFormat = 3
132
+ consolidated_metadata : ConsolidatedMetadata | None = None
84
133
node_type : Literal ["group" ] = field (default = "group" , init = False )
85
134
86
135
def to_buffer_dict (self , prototype : BufferPrototype ) -> dict [str , Buffer ]:
87
136
json_indent = config .get ("json_indent" )
88
137
if self .zarr_format == 3 :
89
138
return {
90
139
ZARR_JSON : prototype .buffer .from_bytes (
91
- json .dumps (self .to_dict (), indent = json_indent ).encode ()
140
+ json .dumps (self .to_dict (), default = _json_convert , indent = json_indent ).encode ()
92
141
)
93
142
}
94
143
else :
@@ -101,20 +150,33 @@ def to_buffer_dict(self, prototype: BufferPrototype) -> dict[str, Buffer]:
101
150
),
102
151
}
103
152
104
- def __init__ (self , attributes : dict [str , Any ] | None = None , zarr_format : ZarrFormat = 3 ):
153
+ def __init__ (
154
+ self ,
155
+ attributes : dict [str , Any ] | None = None ,
156
+ zarr_format : ZarrFormat = 3 ,
157
+ consolidated_metadata : ConsolidatedMetadata | None = None ,
158
+ ):
105
159
attributes_parsed = parse_attributes (attributes )
106
160
zarr_format_parsed = parse_zarr_format (zarr_format )
107
161
108
162
object .__setattr__ (self , "attributes" , attributes_parsed )
109
163
object .__setattr__ (self , "zarr_format" , zarr_format_parsed )
164
+ object .__setattr__ (self , "consolidated_metadata" , consolidated_metadata )
110
165
111
166
@classmethod
112
167
def from_dict (cls , data : dict [str , Any ]) -> GroupMetadata :
168
+ data = dict (data )
113
169
assert data .pop ("node_type" , None ) in ("group" , None )
170
+ consolidated_metadata = data .pop ("consolidated_metadata" , None )
171
+ if consolidated_metadata :
172
+ data ["consolidated_metadata" ] = ConsolidatedMetadata .from_dict (consolidated_metadata )
114
173
return cls (** data )
115
174
116
175
def to_dict (self ) -> dict [str , Any ]:
117
- return asdict (self )
176
+ result = asdict (replace (self , consolidated_metadata = None ))
177
+ if self .consolidated_metadata :
178
+ result ["consolidated_metadata" ] = self .consolidated_metadata .to_dict ()
179
+ return result
118
180
119
181
120
182
@dataclass (frozen = True )
@@ -497,7 +559,8 @@ async def members(
497
559
# as opposed to a prefix, in the store under the prefix associated with this group
498
560
# in which case `key` cannot be the name of a sub-array or sub-group.
499
561
logger .warning (
500
- "Object at %s is not recognized as a component of a Zarr hierarchy." , key
562
+ "Object at %s is not recognized as a component of a Zarr hierarchy." ,
563
+ key ,
501
564
)
502
565
503
566
async def contains (self , member : str ) -> bool :
0 commit comments