22
33import json
44import os
5- from typing import Any , Dict , Optional
5+ from collections .abc import Mapping
6+ from typing import Any
67from urllib .parse import urlparse
78
89import s3fs
910import zarr
11+ from fsspec .implementations .local import LocalFileSystem
12+ from s3fs import S3FileSystem
13+
14+ from eopf_geozarr .types import S3Credentials , S3FsOptions
1015
1116
1217def normalize_s3_path (s3_path : str ) -> str :
@@ -88,7 +93,7 @@ def parse_s3_path(s3_path: str) -> tuple[str, str]:
8893 return bucket , key
8994
9095
91- def get_s3_storage_options (s3_path : str , ** s3_kwargs : Any ) -> Dict [ str , Any ] :
96+ def get_s3_storage_options (s3_path : str , ** s3_kwargs : Any ) -> S3FsOptions :
9297 """
9398 Get storage options for S3 access with xarray.
9499
@@ -105,7 +110,7 @@ def get_s3_storage_options(s3_path: str, **s3_kwargs: Any) -> Dict[str, Any]:
105110 Storage options dictionary for xarray
106111 """
107112 # Set up default S3 configuration
108- default_s3_kwargs = {
113+ default_s3_kwargs : S3FsOptions = {
109114 "anon" : False , # Use credentials
110115 "use_ssl" : True ,
111116 "client_kwargs" : {
@@ -121,12 +126,12 @@ def get_s3_storage_options(s3_path: str, **s3_kwargs: Any) -> Dict[str, Any]:
121126 client_kwargs ["endpoint_url" ] = os .environ ["AWS_ENDPOINT_URL" ]
122127
123128 # Merge with user-provided kwargs
124- s3_config = {** default_s3_kwargs , ** s3_kwargs }
129+ s3_config : S3FsOptions = {** default_s3_kwargs , ** s3_kwargs } # type: ignore[typeddict-item]
125130
126131 return s3_config
127132
128133
129- def get_storage_options (path : str , ** kwargs : Any ) -> Optional [ Dict [ str , Any ]] :
134+ def get_storage_options (path : str , ** kwargs : Any ) -> S3FsOptions | None :
130135 """
131136 Get storage options for any URL type, leveraging fsspec as the abstraction layer.
132137
@@ -202,7 +207,7 @@ def create_s3_store(s3_path: str, **s3_kwargs: Any) -> str:
202207
203208
204209def write_s3_json_metadata (
205- s3_path : str , metadata : Dict [str , Any ], ** s3_kwargs : Any
210+ s3_path : str , metadata : Mapping [str , Any ], ** s3_kwargs : Any
206211) -> None :
207212 """
208213 Write JSON metadata directly to S3.
@@ -220,7 +225,7 @@ def write_s3_json_metadata(
220225 Additional keyword arguments for s3fs.S3FileSystem
221226 """
222227 # Set up default S3 configuration
223- default_s3_kwargs = {
228+ default_s3_kwargs : S3FsOptions = {
224229 "anon" : False ,
225230 "use_ssl" : True ,
226231 "asynchronous" : False , # Force synchronous mode
@@ -245,7 +250,7 @@ def write_s3_json_metadata(
245250 f .write (json_content )
246251
247252
248- def read_s3_json_metadata (s3_path : str , ** s3_kwargs : Any ) -> Dict [str , Any ]:
253+ def read_s3_json_metadata (s3_path : str , ** s3_kwargs : Any ) -> dict [str , Any ]:
249254 """
250255 Read JSON metadata from S3.
251256
@@ -262,7 +267,7 @@ def read_s3_json_metadata(s3_path: str, **s3_kwargs: Any) -> Dict[str, Any]:
262267 Parsed JSON metadata
263268 """
264269 # Set up default S3 configuration
265- default_s3_kwargs = {
270+ default_s3_kwargs : S3FsOptions = {
266271 "anon" : False ,
267272 "use_ssl" : True ,
268273 "asynchronous" : False , # Force synchronous mode
@@ -284,7 +289,7 @@ def read_s3_json_metadata(s3_path: str, **s3_kwargs: Any) -> Dict[str, Any]:
284289 with fs .open (s3_path , "r" ) as f :
285290 content = f .read ()
286291
287- result : Dict [str , Any ] = json .loads (content )
292+ result : dict [str , Any ] = json .loads (content )
288293 return result
289294
290295
@@ -304,7 +309,7 @@ def s3_path_exists(s3_path: str, **s3_kwargs: Any) -> bool:
304309 bool
305310 True if the path exists
306311 """
307- default_s3_kwargs = {
312+ default_s3_kwargs : S3FsOptions = {
308313 "anon" : False ,
309314 "use_ssl" : True ,
310315 "asynchronous" : False , # Force synchronous mode
@@ -351,7 +356,7 @@ def open_s3_zarr_group(s3_path: str, mode: str = "r", **s3_kwargs: Any) -> zarr.
351356 )
352357
353358
354- def get_s3_credentials_info () -> Dict [ str , Optional [ str ]] :
359+ def get_s3_credentials_info () -> S3Credentials :
355360 """
356361 Get information about available S3 credentials.
357362
@@ -372,7 +377,7 @@ def get_s3_credentials_info() -> Dict[str, Optional[str]]:
372377 }
373378
374379
375- def validate_s3_access (s3_path : str , ** s3_kwargs : Any ) -> tuple [bool , Optional [ str ] ]:
380+ def validate_s3_access (s3_path : str , ** s3_kwargs : Any ) -> tuple [bool , str | None ]:
376381 """
377382 Validate that we can access the S3 path.
378383
@@ -389,9 +394,9 @@ def validate_s3_access(s3_path: str, **s3_kwargs: Any) -> tuple[bool, Optional[s
389394 Tuple of (success, error_message)
390395 """
391396 try :
392- bucket , key = parse_s3_path (s3_path )
397+ bucket , _ = parse_s3_path (s3_path )
393398
394- default_s3_kwargs = {
399+ default_s3_kwargs : S3FsOptions = {
395400 "anon" : False ,
396401 "use_ssl" : True ,
397402 "asynchronous" : False , # Force synchronous mode
@@ -419,7 +424,7 @@ def validate_s3_access(s3_path: str, **s3_kwargs: Any) -> tuple[bool, Optional[s
419424 return False , str (e )
420425
421426
422- def get_filesystem (path : str , ** kwargs : Any ) -> Any :
427+ def get_filesystem (path : str , ** kwargs : Any ) -> LocalFileSystem | S3FileSystem :
423428 """
424429 Get the appropriate fsspec filesystem for any path type.
425430
@@ -435,18 +440,17 @@ def get_filesystem(path: str, **kwargs: Any) -> Any:
435440 fsspec.AbstractFileSystem
436441 Filesystem instance
437442 """
438- import fsspec
439443
440444 if is_s3_path (path ):
441445 # Get S3 storage options and use them for fsspec
442446 storage_options = get_s3_storage_options (path , ** kwargs )
443- return fsspec . filesystem ( "s3" , ** storage_options )
447+ return S3FileSystem ( ** storage_options )
444448 else :
445449 # For local paths, use the local filesystem
446- return fsspec . filesystem ( "file" )
450+ return LocalFileSystem ( ** kwargs )
447451
448452
449- def write_json_metadata (path : str , metadata : Dict [str , Any ], ** kwargs : Any ) -> None :
453+ def write_json_metadata (path : str , metadata : dict [str , Any ], ** kwargs : Any ) -> None :
450454 """
451455 Write JSON metadata to any path type using fsspec.
452456
@@ -473,7 +477,7 @@ def write_json_metadata(path: str, metadata: Dict[str, Any], **kwargs: Any) -> N
473477 f .write (json_content )
474478
475479
476- def read_json_metadata (path : str , ** kwargs : Any ) -> Dict [str , Any ]:
480+ def read_json_metadata (path : str , ** kwargs : Any ) -> dict [str , Any ]:
477481 """
478482 Read JSON metadata from any path type using fsspec.
479483
@@ -494,7 +498,7 @@ def read_json_metadata(path: str, **kwargs: Any) -> Dict[str, Any]:
494498 with fs .open (path , "r" ) as f :
495499 content = f .read ()
496500
497- result : Dict [str , Any ] = json .loads (content )
501+ result : dict [str , Any ] = json .loads (content )
498502 return result
499503
500504
0 commit comments