1818
1919from __future__ import annotations
2020
21+ from collections .abc import Iterable , Sequence
2122import concurrent .futures
2223import copy
2324import functools
2728import math
2829import os
2930import sys
30- from typing import Any , Callable , Dict , Iterable , List , Literal , Optional , Sequence , Tuple , Union
31+ from typing import Any , Callable , Literal , Union
3132from urllib import parse
3233import warnings
3334
5960#
6061# The 'int' case let's users specify `io_chunks=-1`, which means to load the
6162# data as a single chunk.
62- Chunks = Union [int , Dict [Any , Any ], Literal ['auto' ], None ]
63+ Chunks = Union [int , dict [Any , Any ], Literal ['auto' ], None ]
6364
6465
6566_BUILTIN_DTYPES = {
8081
8182
8283# Used in ext_test.py.
83- def _check_request_limit (chunks : Dict [str , int ], dtype_size : int , limit : int ):
84+ def _check_request_limit (chunks : dict [str , int ], dtype_size : int , limit : int ):
8485 """Checks that the actual number of bytes exceeds the limit."""
8586 index , width , height = chunks ['index' ], chunks ['width' ], chunks ['height' ]
8687 # Add one for the mask byte (Earth Engine bytes-per-pixel accounting).
@@ -104,25 +105,25 @@ class EarthEngineStore(common.AbstractDataStore):
104105 """Read-only Data Store for Google Earth Engine."""
105106
106107 # "Safe" default chunks that won't exceed the request limit.
107- PREFERRED_CHUNKS : Dict [str , int ] = {
108+ PREFERRED_CHUNKS : dict [str , int ] = {
108109 'index' : 48 ,
109110 'width' : 256 ,
110111 'height' : 256 ,
111112 }
112113
113- GETITEM_KWARGS : Dict [str , int ] = {
114+ GETITEM_KWARGS : dict [str , int ] = {
114115 'max_retries' : 6 ,
115116 'initial_delay' : 500 ,
116117 }
117118
118- SCALE_UNITS : Dict [str , int ] = {
119+ SCALE_UNITS : dict [str , int ] = {
119120 'degree' : 1 ,
120121 'metre' : 10_000 ,
121122 'meter' : 10_000 ,
122123 'm' : 10_000 ,
123124 }
124125
125- DIMENSION_NAMES : Dict [str , Tuple [str , str ]] = {
126+ DIMENSION_NAMES : dict [str , tuple [str , str ]] = {
126127 'degree' : ('lon' , 'lat' ),
127128 'metre' : ('X' , 'Y' ),
128129 'meter' : ('X' , 'Y' ),
@@ -149,20 +150,20 @@ def open(
149150 mode : Literal ['r' ] = 'r' ,
150151 chunk_store : Chunks = None ,
151152 n_images : int = - 1 ,
152- crs : Optional [ str ] = None ,
153- scale : Optional [ float ] = None ,
154- projection : Optional [ ee .Projection ] = None ,
155- geometry : ee .Geometry | Tuple [float , float , float , float ] | None = None ,
156- primary_dim_name : Optional [ str ] = None ,
157- primary_dim_property : Optional [ str ] = None ,
158- mask_value : Optional [ float ] = None ,
153+ crs : str | None = None ,
154+ scale : float | None = None ,
155+ projection : ee .Projection | None = None ,
156+ geometry : ee .Geometry | tuple [float , float , float , float ] | None = None ,
157+ primary_dim_name : str | None = None ,
158+ primary_dim_property : str | None = None ,
159+ mask_value : float | None = None ,
159160 request_byte_limit : int = REQUEST_BYTE_LIMIT ,
160- ee_init_kwargs : Optional [ Dict [ str , Any ]] = None ,
161+ ee_init_kwargs : dict [ str , Any ] | None = None ,
161162 ee_init_if_necessary : bool = False ,
162- executor_kwargs : Optional [ Dict [ str , Any ]] = None ,
163- getitem_kwargs : Optional [ Dict [ str , int ]] = None ,
163+ executor_kwargs : dict [ str , Any ] | None = None ,
164+ getitem_kwargs : dict [ str , int ] | None = None ,
164165 fast_time_slicing : bool = False ,
165- ) -> ' EarthEngineStore' :
166+ ) -> EarthEngineStore :
166167 if mode != 'r' :
167168 raise ValueError (
168169 f'mode { mode !r} is invalid: data can only be read from Earth Engine.'
@@ -192,18 +193,18 @@ def __init__(
192193 image_collection : ee .ImageCollection ,
193194 chunks : Chunks = None ,
194195 n_images : int = - 1 ,
195- crs : Optional [ str ] = None ,
196- scale : Union [ float , int , None ] = None ,
197- projection : Optional [ ee .Projection ] = None ,
198- geometry : ee .Geometry | Tuple [float , float , float , float ] | None = None ,
199- primary_dim_name : Optional [ str ] = None ,
200- primary_dim_property : Optional [ str ] = None ,
201- mask_value : Optional [ float ] = None ,
196+ crs : str | None = None ,
197+ scale : float | int | None = None ,
198+ projection : ee .Projection | None = None ,
199+ geometry : ee .Geometry | tuple [float , float , float , float ] | None = None ,
200+ primary_dim_name : str | None = None ,
201+ primary_dim_property : str | None = None ,
202+ mask_value : float | None = None ,
202203 request_byte_limit : int = REQUEST_BYTE_LIMIT ,
203- ee_init_kwargs : Optional [ Dict [ str , Any ]] = None ,
204+ ee_init_kwargs : dict [ str , Any ] | None = None ,
204205 ee_init_if_necessary : bool = False ,
205- executor_kwargs : Optional [ Dict [ str , Any ]] = None ,
206- getitem_kwargs : Optional [ Dict [ str , int ]] = None ,
206+ executor_kwargs : dict [ str , Any ] | None = None ,
207+ getitem_kwargs : dict [ str , int ] | None = None ,
207208 fast_time_slicing : bool = False ,
208209 ):
209210 self .ee_init_kwargs = ee_init_kwargs
@@ -279,7 +280,7 @@ def __init__(
279280 self .mask_value = mask_value
280281
281282 @functools .cached_property
282- def get_info (self ) -> Dict [str , Any ]:
283+ def get_info (self ) -> dict [str , Any ]:
283284 """Make all getInfo() calls to EE at once."""
284285
285286 rpcs = [
@@ -330,12 +331,12 @@ def get_info(self) -> Dict[str, Any]:
330331 return dict (zip ((name for name , _ in rpcs ), info ))
331332
332333 @property
333- def image_collection_properties (self ) -> Tuple [ List [str ], List [str ]]:
334+ def image_collection_properties (self ) -> tuple [ list [str ], list [str ]]:
334335 system_ids , primary_coord = self .get_info ['properties' ]
335336 return (system_ids , primary_coord )
336337
337338 @property
338- def image_ids (self ) -> List [str ]:
339+ def image_ids (self ) -> list [str ]:
339340 image_ids , _ = self .image_collection_properties
340341 return image_ids
341342
@@ -347,7 +348,7 @@ def _max_itemsize(self) -> int:
347348 @classmethod
348349 def _auto_chunks (
349350 cls , dtype_bytes : int , request_byte_limit : int = REQUEST_BYTE_LIMIT
350- ) -> Dict [str , int ]:
351+ ) -> dict [str , int ]:
351352 """Given the data type size and request limit, calculate optimal chunks."""
352353 # Taking the data type number of bytes into account, let's try to have the
353354 # height and width follow round numbers (powers of two) and allocate the
@@ -374,8 +375,8 @@ def _auto_chunks(
374375 return {'index' : index , 'width' : width , 'height' : height }
375376
376377 def _assign_index_chunks (
377- self , input_chunk_store : Dict [Any , Any ]
378- ) -> Dict [Any , Any ]:
378+ self , input_chunk_store : dict [Any , Any ]
379+ ) -> dict [Any , Any ]:
379380 """Assigns values of 'index', 'width', and 'height' to `self.chunks`.
380381
381382 This method first attempts to retrieve values for 'index', 'width',
@@ -416,7 +417,7 @@ def _assign_preferred_chunks(self) -> Chunks:
416417 chunks [y_dim_name ] = self .chunks ['height' ]
417418 return chunks
418419
419- def transform (self , xs : float , ys : float ) -> Tuple [float , float ]:
420+ def transform (self , xs : float , ys : float ) -> tuple [float , float ]:
420421 transformer = pyproj .Transformer .from_crs (
421422 self .crs .geodetic_crs , self .crs , always_xy = True
422423 )
@@ -539,22 +540,29 @@ def image_to_array(
539540 data = np .where (data == current_mask_value , np .nan , data )
540541 return data
541542
542- @functools .lru_cache ()
543+ @functools .lru_cache
543544 def _band_attrs (self , band_name : str ) -> types .BandInfo :
544545 try :
545- return next (( b for b in self ._img_info ['bands' ] if b ['id' ] == band_name ) )
546+ return next (b for b in self ._img_info ['bands' ] if b ['id' ] == band_name )
546547 except StopIteration as e :
547548 raise ValueError (f'Band { band_name !r} not found.' ) from e
548549
549- @functools .lru_cache ()
550- def _bands (self ) -> List [str ]:
550+ @functools .lru_cache
551+ def _bands (self ) -> list [str ]:
551552 return [b ['id' ] for b in self ._img_info ['bands' ]]
552553
553- def _make_attrs_valid (self , attrs : Dict [str , Any ]) -> Dict [
554+ def _make_attrs_valid (self , attrs : dict [str , Any ]) -> dict [
554555 str ,
555- Union [
556- str , int , float , complex , np .ndarray , np .number , List [Any ], Tuple [Any ]
557- ],
556+ (
557+ str
558+ | int
559+ | float
560+ | complex
561+ | np .ndarray
562+ | np .number
563+ | list [Any ]
564+ | tuple [Any ] # pylint: disable=g-one-element-tuple
565+ ),
558566 ]:
559567 return {
560568 key : (
@@ -590,7 +598,7 @@ def get_dimensions(self) -> utils.Frozen[str, int]:
590598 def get_attrs (self ) -> utils .Frozen [Any , Any ]:
591599 return utils .FrozenDict (self ._props )
592600
593- def _get_primary_coordinates (self ) -> List [Any ]:
601+ def _get_primary_coordinates (self ) -> list [Any ]:
594602 """Gets the primary dimension coordinate values from an ImageCollection."""
595603 _ , primary_coords = self .image_collection_properties
596604
@@ -607,8 +615,8 @@ def _get_primary_coordinates(self) -> List[Any]:
607615 return primary_coords
608616
609617 def _get_tile_from_ee (
610- self , tile_and_band : Tuple [ Tuple [int , int , int ], str ]
611- ) -> Tuple [int , np .ndarray [Any , np .dtype ]]:
618+ self , tile_and_band : tuple [ tuple [int , int , int ], str ]
619+ ) -> tuple [int , np .ndarray [Any , np .dtype ]]:
612620 """Get a numpy array from EE for a specific bounding box (a 'tile')."""
613621 (tile_index , tile_coords_start , tile_coords_end ), band_id = tile_and_band
614622 bbox = self .project (
@@ -644,8 +652,8 @@ def _process_coordinate_data(
644652
645653 def _determine_bounds (
646654 self ,
647- geometry : ee .Geometry | Tuple [float , float , float , float ] | None = None ,
648- ) -> Tuple [float , float , float , float ]:
655+ geometry : ee .Geometry | tuple [float , float , float , float ] | None = None ,
656+ ) -> tuple [float , float , float , float ]:
649657 if geometry is None :
650658 try :
651659 x_min_0 , y_min_0 , x_max_0 , y_max_0 = self .crs .area_of_use .bounds
@@ -757,7 +765,7 @@ def _parse_dtype(data_type: types.DataType):
757765 return np .dtype (dt )
758766
759767
760- def _ee_bounds_to_bounds (bounds : Dict [str , Any ]) -> types .Bounds :
768+ def _ee_bounds_to_bounds (bounds : dict [str , Any ]) -> types .Bounds :
761769 coords = np .array (bounds ['coordinates' ], dtype = np .float64 )[0 ]
762770 x_min , y_min , x_max , y_max = (
763771 min (coords [:, 0 ]),
@@ -818,8 +826,8 @@ def __getitem__(self, key: indexing.ExplicitIndexer) -> np.typing.ArrayLike:
818826 )
819827
820828 def _key_to_slices (
821- self , key : Tuple [ Union [ int , slice ] , ...]
822- ) -> Tuple [ Tuple [slice , ...], Tuple [int , ...]]:
829+ self , key : tuple [ int | slice , ...]
830+ ) -> tuple [ tuple [slice , ...], tuple [int , ...]]:
823831 """Convert all key indexes to slices.
824832
825833 If any keys are integers, convert them to a slice (i.e. with a range of 1
@@ -889,7 +897,7 @@ def reduce_bands(x, acc):
889897 return target_image
890898
891899 def _raw_indexing_method (
892- self , key : Tuple [ Union [ int , slice ] , ...]
900+ self , key : tuple [ int | slice , ...]
893901 ) -> np .typing .ArrayLike :
894902 key , squeeze_axes = self ._key_to_slices (key )
895903
@@ -955,8 +963,8 @@ def _raw_indexing_method(
955963 return out
956964
957965 def _make_tile (
958- self , tile_index : Tuple [types .TileIndex , types .BBox3d ]
959- ) -> Tuple [types .TileIndex , np .ndarray ]:
966+ self , tile_index : tuple [types .TileIndex , types .BBox3d ]
967+ ) -> tuple [types .TileIndex , np .ndarray ]:
960968 """Get a numpy array from EE for a specific 3D bounding box (a 'tile')."""
961969 tile_idx , (istart , iend , * bbox ) = tile_index
962970 target_image = self ._slice_collection (slice (istart , iend ))
@@ -966,7 +974,7 @@ def _make_tile(
966974
967975 def _tile_indexes (
968976 self , index_range : slice , bbox : types .BBox
969- ) -> Iterable [Tuple [types .TileIndex , types .BBox3d ]]:
977+ ) -> Iterable [tuple [types .TileIndex , types .BBox3d ]]:
970978 """Calculate indexes to break up a (3D) bounding box into chunks."""
971979 tstep = self ._apparent_chunks ['index' ]
972980 wstep = self ._apparent_chunks ['width' ]
@@ -988,7 +996,7 @@ def _tile_indexes(
988996class EarthEngineBackendEntrypoint (backends .BackendEntrypoint ):
989997 """Backend for Earth Engine."""
990998
991- def _parse (self , filename_or_obj : Union [ str , os .PathLike [Any ] ]) -> str :
999+ def _parse (self , filename_or_obj : str | os .PathLike [Any ]) -> str :
9921000 parsed = parse .urlparse (str (filename_or_obj ))
9931001 if parsed .scheme and parsed .scheme != 'ee' :
9941002 raise ValueError (
@@ -998,7 +1006,7 @@ def _parse(self, filename_or_obj: Union[str, os.PathLike[Any]]) -> str:
9981006 return f'{ parsed .netloc } { parsed .path } '
9991007
10001008 def guess_can_open (
1001- self , filename_or_obj : Union [ str , os .PathLike [Any ], ee .ImageCollection ]
1009+ self , filename_or_obj : str | os .PathLike [Any ] | ee .ImageCollection
10021010 ) -> bool : # type: ignore
10031011 """Returns True if the candidate is a valid ImageCollection."""
10041012 if isinstance (filename_or_obj , ee .ImageCollection ):
@@ -1013,28 +1021,28 @@ def guess_can_open(
10131021
10141022 def open_dataset (
10151023 self ,
1016- filename_or_obj : Union [ str , os .PathLike [Any ], ee .ImageCollection ] ,
1017- drop_variables : Optional [ Tuple [ str , ...]] = None ,
1018- io_chunks : Optional [ Any ] = None ,
1024+ filename_or_obj : str | os .PathLike [Any ] | ee .ImageCollection ,
1025+ drop_variables : tuple [ str , ...] | None = None ,
1026+ io_chunks : Any | None = None ,
10191027 n_images : int = - 1 ,
10201028 mask_and_scale : bool = True ,
10211029 decode_times : bool = True ,
1022- decode_timedelta : Optional [ bool ] = None ,
1023- use_cftime : Optional [ bool ] = None ,
1030+ decode_timedelta : bool | None = None ,
1031+ use_cftime : bool | None = None ,
10241032 concat_characters : bool = True ,
10251033 decode_coords : bool = True ,
1026- crs : Optional [ str ] = None ,
1027- scale : Union [ float , int , None ] = None ,
1028- projection : Optional [ ee .Projection ] = None ,
1029- geometry : ee .Geometry | Tuple [float , float , float , float ] | None = None ,
1030- primary_dim_name : Optional [ str ] = None ,
1031- primary_dim_property : Optional [ str ] = None ,
1032- ee_mask_value : Optional [ float ] = None ,
1034+ crs : str | None = None ,
1035+ scale : float | int | None = None ,
1036+ projection : ee .Projection | None = None ,
1037+ geometry : ee .Geometry | tuple [float , float , float , float ] | None = None ,
1038+ primary_dim_name : str | None = None ,
1039+ primary_dim_property : str | None = None ,
1040+ ee_mask_value : float | None = None ,
10331041 request_byte_limit : int = REQUEST_BYTE_LIMIT ,
10341042 ee_init_if_necessary : bool = False ,
1035- ee_init_kwargs : Optional [ Dict [ str , Any ]] = None ,
1036- executor_kwargs : Optional [ Dict [ str , Any ]] = None ,
1037- getitem_kwargs : Optional [ Dict [ str , int ]] = None ,
1043+ ee_init_kwargs : dict [ str , Any ] | None = None ,
1044+ executor_kwargs : dict [ str , Any ] | None = None ,
1045+ getitem_kwargs : dict [ str , int ] | None = None ,
10381046 fast_time_slicing : bool = False ,
10391047 ) -> xarray .Dataset : # type: ignore
10401048 """Open an Earth Engine ImageCollection as an Xarray Dataset.
@@ -1170,8 +1178,8 @@ def open_dataset(
11701178
11711179
11721180def _parse_ee_init_kwargs (
1173- ee_init_kwargs : Optional [ Dict [ str , Any ]] ,
1174- ) -> Dict [str , Any ]:
1181+ ee_init_kwargs : dict [ str , Any ] | None ,
1182+ ) -> dict [str , Any ]:
11751183 """Parses Earth Engine Initialize kwargs.
11761184
11771185 Generate credentials if credentials_function is specified.
0 commit comments