@@ -131,6 +131,30 @@ def _parse_async_node(
131
131
raise TypeError (f"Unknown node type, got { type (node )} " )
132
132
133
133
134
+ async def _get_zarr_version (store_path : StorePath ) -> Literal [2 , 3 ]:
135
+ """
136
+ Guess Zarr format from present metadata files in a Store.
137
+ """
138
+ (
139
+ zarr_json_bytes ,
140
+ zgroup_bytes ,
141
+ ) = await asyncio .gather (
142
+ (store_path / ZARR_JSON ).exists (),
143
+ (store_path / ZGROUP_JSON ).exists (),
144
+ )
145
+ if zarr_json_bytes and zgroup_bytes :
146
+ # warn and favor v3
147
+ msg = f"Both zarr.json (Zarr format 3) and .zgroup (Zarr format 2) metadata objects exist at { store_path } . Zarr format 3 will be used."
148
+ warnings .warn (msg , category = ZarrUserWarning , stacklevel = 1 )
149
+ if not zarr_json_bytes and not zgroup_bytes :
150
+ raise FileNotFoundError (f"could not find zarr.json or .zgroup objects in { store_path } " )
151
+ # set zarr_format based on which keys were found
152
+ if zarr_json_bytes :
153
+ return 3
154
+ else :
155
+ return 2
156
+
157
+
134
158
@dataclass (frozen = True )
135
159
class ConsolidatedMetadata :
136
160
"""
@@ -512,6 +536,14 @@ async def open(
512
536
to load consolidated metadata from a non-default key.
513
537
"""
514
538
store_path = await make_store_path (store )
539
+ # Guess zarr_format if not passed explicitly
540
+ if zarr_format is None :
541
+ zarr_format = await _get_zarr_version (store_path )
542
+ return await cls .open (
543
+ store = store , zarr_format = zarr_format , use_consolidated = use_consolidated
544
+ )
545
+ assert zarr_format is not None
546
+
515
547
if not store_path .store .supports_consolidated_metadata :
516
548
# Fail if consolidated metadata was requested but the Store doesn't support it
517
549
if use_consolidated :
@@ -523,12 +555,11 @@ async def open(
523
555
# if use_consolidated was None (optional), the Store dictates it doesn't want consolidation
524
556
use_consolidated = False
525
557
526
- consolidated_key = ZMETADATA_V2_JSON
527
-
528
- if (zarr_format == 2 or zarr_format is None ) and isinstance (use_consolidated , str ):
529
- consolidated_key = use_consolidated
530
-
531
558
if zarr_format == 2 :
559
+ consolidated_key = ZMETADATA_V2_JSON
560
+ if isinstance (use_consolidated , str ):
561
+ consolidated_key = use_consolidated
562
+
532
563
paths = [store_path / ZGROUP_JSON , store_path / ZATTRS_JSON ]
533
564
if use_consolidated or use_consolidated is None :
534
565
paths .append (store_path / consolidated_key )
@@ -545,43 +576,6 @@ async def open(
545
576
else :
546
577
maybe_consolidated_metadata_bytes = None
547
578
548
- elif zarr_format == 3 :
549
- zarr_json_bytes = await (store_path / ZARR_JSON ).get ()
550
- if zarr_json_bytes is None :
551
- raise FileNotFoundError (store_path )
552
- elif zarr_format is None :
553
- (
554
- zarr_json_bytes ,
555
- zgroup_bytes ,
556
- zattrs_bytes ,
557
- maybe_consolidated_metadata_bytes ,
558
- ) = await asyncio .gather (
559
- (store_path / ZARR_JSON ).get (),
560
- (store_path / ZGROUP_JSON ).get (),
561
- (store_path / ZATTRS_JSON ).get (),
562
- (store_path / str (consolidated_key )).get (),
563
- )
564
- if zarr_json_bytes is not None and zgroup_bytes is not None :
565
- # warn and favor v3
566
- msg = f"Both zarr.json (Zarr format 3) and .zgroup (Zarr format 2) metadata objects exist at { store_path } . Zarr format 3 will be used."
567
- warnings .warn (msg , category = ZarrUserWarning , stacklevel = 1 )
568
- if zarr_json_bytes is None and zgroup_bytes is None :
569
- raise FileNotFoundError (
570
- f"could not find zarr.json or .zgroup objects in { store_path } "
571
- )
572
- # set zarr_format based on which keys were found
573
- if zarr_json_bytes is not None :
574
- zarr_format = 3
575
- else :
576
- zarr_format = 2
577
- else :
578
- msg = f"Invalid value for 'zarr_format'. Expected 2, 3, or None. Got '{ zarr_format } '." # type: ignore[unreachable]
579
- raise MetadataValidationError (msg )
580
-
581
- if zarr_format == 2 :
582
- # this is checked above, asserting here for mypy
583
- assert zgroup_bytes is not None
584
-
585
579
if use_consolidated and maybe_consolidated_metadata_bytes is None :
586
580
# the user requested consolidated metadata, but it was missing
587
581
raise ValueError (consolidated_key )
@@ -594,9 +588,11 @@ async def open(
594
588
return cls ._from_bytes_v2 (
595
589
store_path , zgroup_bytes , zattrs_bytes , maybe_consolidated_metadata_bytes
596
590
)
597
- else :
598
- # V3 groups are comprised of a zarr.json object
599
- assert zarr_json_bytes is not None
591
+
592
+ elif zarr_format == 3 :
593
+ zarr_json_bytes = await (store_path / ZARR_JSON ).get ()
594
+ if zarr_json_bytes is None :
595
+ raise FileNotFoundError (store_path )
600
596
if not isinstance (use_consolidated , bool | None ):
601
597
raise TypeError ("use_consolidated must be a bool or None for Zarr format 3." )
602
598
@@ -605,6 +601,9 @@ async def open(
605
601
zarr_json_bytes ,
606
602
use_consolidated = use_consolidated ,
607
603
)
604
+ else :
605
+ msg = f"Invalid value for 'zarr_format'. Expected 2, 3, or None. Got '{ zarr_format } '." # type: ignore[unreachable]
606
+ raise MetadataValidationError (msg )
608
607
609
608
@classmethod
610
609
def _from_bytes_v2 (
0 commit comments