@@ -125,6 +125,57 @@ def get_s3_storage_options(s3_path: str, **s3_kwargs) -> Dict[str, Any]:
125125 return s3_config
126126
127127
128+ def get_storage_options (path : str , ** kwargs ) -> Optional [Dict [str , Any ]]:
129+ """
130+ Get storage options for any URL type, leveraging fsspec as the abstraction layer.
131+
132+ This function eliminates the need for if/else branching by returning appropriate
133+ storage options based on the URL protocol.
134+
135+ Parameters
136+ ----------
137+ path : str
138+ Path or URL (local path, s3://, etc.)
139+ **kwargs
140+ Additional keyword arguments for the storage backend
141+
142+ Returns
143+ -------
144+ Optional[Dict[str, Any]]
145+ Storage options dictionary for xarray/zarr, or None for local paths
146+ """
147+ if is_s3_path (path ):
148+ return get_s3_storage_options (path , ** kwargs )
149+ # For local paths, return None (no storage options needed)
150+ # Future protocols (gcs://, azure://, etc.) can be added here
151+ return None
152+
153+
154+ def normalize_path (path : str ) -> str :
155+ """
156+ Normalize any path type (local or remote URL).
157+
158+ This function handles path normalization for all filesystem types,
159+ ensuring proper path formatting and removing issues like double slashes.
160+
161+ Parameters
162+ ----------
163+ path : str
164+ Path to normalize
165+
166+ Returns
167+ -------
168+ str
169+ Normalized path
170+ """
171+ if is_s3_path (path ):
172+ return normalize_s3_path (path )
173+ else :
174+ # For local paths, normalize by removing double slashes and cleaning up
175+ import os .path
176+ return os .path .normpath (path )
177+
178+
128179def create_s3_store (s3_path : str , ** s3_kwargs ) -> str :
129180 """
130181 Create an S3 path with storage options for Zarr operations.
@@ -346,3 +397,123 @@ def validate_s3_access(s3_path: str, **s3_kwargs) -> tuple[bool, Optional[str]]:
346397
347398 except Exception as e :
348399 return False , str (e )
400+
401+
402+ def get_filesystem (path : str , ** kwargs ):
403+ """
404+ Get the appropriate fsspec filesystem for any path type.
405+
406+ Parameters
407+ ----------
408+ path : str
409+ Path or URL (local path, s3://, etc.)
410+ **kwargs
411+ Additional keyword arguments for the filesystem
412+
413+ Returns
414+ -------
415+ fsspec.AbstractFileSystem
416+ Filesystem instance
417+ """
418+ import fsspec
419+
420+ if is_s3_path (path ):
421+ # Get S3 storage options and use them for fsspec
422+ storage_options = get_s3_storage_options (path , ** kwargs )
423+ return fsspec .filesystem ('s3' , ** storage_options )
424+ else :
425+ # For local paths, use the local filesystem
426+ return fsspec .filesystem ('file' )
427+
428+
429+ def write_json_metadata (path : str , metadata : Dict [str , Any ], ** kwargs ) -> None :
430+ """
431+ Write JSON metadata to any path type using fsspec.
432+
433+ Parameters
434+ ----------
435+ path : str
436+ Path where to write the JSON file (local path or URL)
437+ metadata : dict
438+ Metadata dictionary to write as JSON
439+ **kwargs
440+ Additional keyword arguments for the filesystem
441+ """
442+ fs = get_filesystem (path , ** kwargs )
443+
444+ # Ensure parent directory exists for local paths
445+ if not is_s3_path (path ):
446+ parent_dir = os .path .dirname (path )
447+ if parent_dir :
448+ fs .makedirs (parent_dir , exist_ok = True )
449+
450+ # Write JSON content using fsspec
451+ json_content = json .dumps (metadata , indent = 2 )
452+ with fs .open (path , "w" ) as f :
453+ f .write (json_content )
454+
455+
456+ def read_json_metadata (path : str , ** kwargs ) -> Dict [str , Any ]:
457+ """
458+ Read JSON metadata from any path type using fsspec.
459+
460+ Parameters
461+ ----------
462+ path : str
463+ Path to the JSON file (local path or URL)
464+ **kwargs
465+ Additional keyword arguments for the filesystem
466+
467+ Returns
468+ -------
469+ dict
470+ Parsed JSON metadata
471+ """
472+ fs = get_filesystem (path , ** kwargs )
473+
474+ with fs .open (path , "r" ) as f :
475+ content = f .read ()
476+
477+ return json .loads (content )
478+
479+
480+ def path_exists (path : str , ** kwargs ) -> bool :
481+ """
482+ Check if a path exists using fsspec.
483+
484+ Parameters
485+ ----------
486+ path : str
487+ Path to check (local path or URL)
488+ **kwargs
489+ Additional keyword arguments for the filesystem
490+
491+ Returns
492+ -------
493+ bool
494+ True if the path exists
495+ """
496+ fs = get_filesystem (path , ** kwargs )
497+ return fs .exists (path )
498+
499+
500+ def open_zarr_group (path : str , mode : str = "r" , ** kwargs ) -> zarr .Group :
501+ """
502+ Open a Zarr group from any path type using unified storage options.
503+
504+ Parameters
505+ ----------
506+ path : str
507+ Path to the Zarr group (local path or URL)
508+ mode : str, default "r"
509+ Access mode ("r", "r+", "w", "a")
510+ **kwargs
511+ Additional keyword arguments for the storage backend
512+
513+ Returns
514+ -------
515+ zarr.Group
516+ Zarr group
517+ """
518+ storage_options = get_storage_options (path , ** kwargs )
519+ return zarr .open_group (path , mode = mode , zarr_format = 3 , storage_options = storage_options )
0 commit comments