Skip to content

Commit a130612

Browse files
author
Xee authors
committed
Add Python 3.8 support.
Fixes [#76](#76). PiperOrigin-RevId: 582869103
1 parent cfc2ba1 commit a130612

5 files changed

Lines changed: 43 additions & 36 deletions

File tree

.github/workflows/ci-build.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ jobs:
3030
strategy:
3131
fail-fast: false
3232
matrix:
33-
python-version: ["3.9", "3.10", "3.11"]
33+
python-version: [
34+
"3.8",
35+
"3.9",
36+
"3.10",
37+
"3.11",
38+
"3.12",
39+
]
3440
permissions:
3541
id-token: write # This is required for requesting the JWT.
3642
steps:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "xee"
33
dynamic = ["version"]
44
description = "A Google Earth Engine extension for Xarray."
55
readme = "README.md"
6-
requires-python = ">=3.9"
6+
requires-python = ">=3.8"
77
license = {text = "Apache-2.0"}
88
authors = [
99
{name = "Google LLC", email = "noreply@google.com"},

xee/ext.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import math
2525
import os
2626
import sys
27-
from typing import Any, Iterable, Literal, Optional, Union
27+
from typing import Any, Dict, List, Iterable, Literal, Optional, Tuple, Union
2828
from urllib import parse
2929
import warnings
3030

@@ -56,7 +56,7 @@
5656
#
5757
# The 'int' case let's users specify `io_chunks=-1`, which means to load the
5858
# data as a single chunk.
59-
Chunks = Union[int, dict[Any, Any], Literal['auto'], None]
59+
Chunks = Union[int, Dict[Any, Any], Literal['auto'], None]
6060

6161

6262
_BUILTIN_DTYPES = {
@@ -72,7 +72,7 @@
7272
REQUEST_BYTE_LIMIT = 2**20 * 48 # 48 MBs
7373

7474

75-
def _check_request_limit(chunks: dict[str, int], dtype_size: int, limit: int):
75+
def _check_request_limit(chunks: Dict[str, int], dtype_size: int, limit: int):
7676
"""Checks that the actual number of bytes exceeds the limit."""
7777
index, width, height = chunks['index'], chunks['width'], chunks['height']
7878
actual_bytes = index * width * height * dtype_size
@@ -95,19 +95,19 @@ class EarthEngineStore(common.AbstractDataStore):
9595
"""Read-only Data Store for Google Earth Engine."""
9696

9797
# "Safe" default chunks that won't exceed the request limit.
98-
PREFERRED_CHUNKS: dict[str, int] = {
98+
PREFERRED_CHUNKS: Dict[str, int] = {
9999
'index': 48,
100100
'width': 512,
101101
'height': 256,
102102
}
103103

104-
SCALE_UNITS: dict[str, int] = {
104+
SCALE_UNITS: Dict[str, int] = {
105105
'degree': 1,
106106
'metre': 10_000,
107107
'meter': 10_000,
108108
}
109109

110-
DIMENSION_NAMES: dict[str, tuple[str, str]] = {
110+
DIMENSION_NAMES: Dict[str, Tuple[str, str]] = {
111111
'degree': ('lon', 'lat'),
112112
'metre': ('X', 'Y'),
113113
'meter': ('X', 'Y'),
@@ -254,7 +254,7 @@ def __init__(
254254
self.mask_value = mask_value
255255

256256
@functools.cached_property
257-
def get_info(self) -> dict[str, Any]:
257+
def get_info(self) -> Dict[str, Any]:
258258
"""Make all getInfo() calls to EE at once."""
259259

260260
rpcs = [
@@ -296,12 +296,12 @@ def get_info(self) -> dict[str, Any]:
296296
return dict(zip((name for name, _ in rpcs), info))
297297

298298
@property
299-
def image_collection_properties(self) -> tuple[list[str], list[str]]:
299+
def image_collection_properties(self) -> Tuple[List[str], List[str]]:
300300
system_ids, primary_coord = self.get_info['properties']
301301
return (system_ids, primary_coord)
302302

303303
@property
304-
def image_ids(self) -> list[str]:
304+
def image_ids(self) -> List[str]:
305305
image_ids, _ = self.image_collection_properties
306306
return image_ids
307307

@@ -313,7 +313,7 @@ def _max_itemsize(self) -> int:
313313
@classmethod
314314
def _auto_chunks(
315315
cls, dtype_bytes: int, request_byte_limit: int = REQUEST_BYTE_LIMIT
316-
) -> dict[str, int]:
316+
) -> Dict[str, int]:
317317
"""Given the data type size and request limit, calculate optimal chunks."""
318318
# Taking the data type number of bytes into account, let's try to have the
319319
# height and width follow round numbers (powers of two) and allocate the
@@ -338,8 +338,8 @@ def _auto_chunks(
338338
return {'index': index, 'width': width, 'height': height}
339339

340340
def _assign_index_chunks(
341-
self, input_chunk_store: dict[Any, Any]
342-
) -> dict[Any, Any]:
341+
self, input_chunk_store: Dict[Any, Any]
342+
) -> Dict[Any, Any]:
343343
"""Assigns values of 'index', 'width', and 'height' to `self.chunks`.
344344
345345
This method first attempts to retrieve values for 'index', 'width',
@@ -380,7 +380,7 @@ def _assign_preferred_chunks(self) -> Chunks:
380380
chunks[y_dim_name] = self.chunks['height']
381381
return chunks
382382

383-
def transform(self, xs: float, ys: float) -> tuple[float, float]:
383+
def transform(self, xs: float, ys: float) -> Tuple[float, float]:
384384
transformer = pyproj.Transformer.from_crs(
385385
self.crs.geodetic_crs, self.crs, always_xy=True
386386
)
@@ -478,13 +478,13 @@ def _band_attrs(self, band_name: str) -> types.BandInfo:
478478
raise ValueError(f'Band {band_name!r} not found.') from e
479479

480480
@functools.lru_cache()
481-
def _bands(self) -> list[str]:
481+
def _bands(self) -> List[str]:
482482
return [b['id'] for b in self._img_info['bands']]
483483

484-
def _make_attrs_valid(self, attrs: dict[str, Any]) -> dict[
484+
def _make_attrs_valid(self, attrs: Dict[str, Any]) -> Dict[
485485
str,
486486
Union[
487-
str, int, float, complex, np.ndarray, np.number, list[Any], tuple[Any]
487+
str, int, float, complex, np.ndarray, np.number, List[Any], Tuple[Any]
488488
],
489489
]:
490490
return {
@@ -520,7 +520,7 @@ def get_dimensions(self) -> utils.Frozen[str, int]:
520520
def get_attrs(self) -> utils.Frozen[Any, Any]:
521521
return utils.FrozenDict(self._props)
522522

523-
def _get_primary_coordinates(self) -> list[Any]:
523+
def _get_primary_coordinates(self) -> List[Any]:
524524
"""Gets the primary dimension coordinate values from an ImageCollection."""
525525
_, primary_coords = self.image_collection_properties
526526

@@ -654,8 +654,8 @@ def __getitem__(self, key: indexing.ExplicitIndexer) -> np.typing.ArrayLike:
654654
)
655655

656656
def _key_to_slices(
657-
self, key: tuple[Union[int, slice], ...]
658-
) -> tuple[tuple[slice, ...], tuple[int, ...]]:
657+
self, key: Tuple[Union[int, slice], ...]
658+
) -> Tuple[Tuple[slice, ...], Tuple[int, ...]]:
659659
"""Convert all key indexes to slices.
660660
661661
If any keys are integers, convert them to a slice (i.e. with a range of 1
@@ -712,7 +712,7 @@ def reduce_bands(x, acc):
712712
return target_image
713713

714714
def _raw_indexing_method(
715-
self, key: tuple[Union[int, slice], ...]
715+
self, key: Tuple[Union[int, slice], ...]
716716
) -> np.typing.ArrayLike:
717717
key, squeeze_axes = self._key_to_slices(key)
718718

@@ -777,8 +777,8 @@ def _raw_indexing_method(
777777
return out
778778

779779
def _make_tile(
780-
self, tile_index: tuple[types.TileIndex, types.BBox3d]
781-
) -> tuple[types.TileIndex, np.ndarray]:
780+
self, tile_index: Tuple[types.TileIndex, types.BBox3d]
781+
) -> Tuple[types.TileIndex, np.ndarray]:
782782
"""Get a numpy array from EE for a specific 3D bounding box (a 'tile')."""
783783
tile_idx, (istart, iend, *bbox) = tile_index
784784
target_image = self._slice_collection(slice(istart, iend))
@@ -788,7 +788,7 @@ def _make_tile(
788788

789789
def _tile_indexes(
790790
self, index_range: slice, bbox: types.BBox
791-
) -> Iterable[tuple[types.TileIndex, types.BBox3d]]:
791+
) -> Iterable[Tuple[types.TileIndex, types.BBox3d]]:
792792
"""Calculate indexes to break up a (3D) bounding box into chunks."""
793793
tstep = self._apparent_chunks['index']
794794
wstep = self._apparent_chunks['width']
@@ -836,7 +836,7 @@ def guess_can_open(
836836
def open_dataset(
837837
self,
838838
filename_or_obj: Union[str, os.PathLike[Any], ee.ImageCollection],
839-
drop_variables: Optional[tuple[str, ...]] = None,
839+
drop_variables: Optional[Tuple[str, ...]] = None,
840840
io_chunks: Optional[Any] = None,
841841
n_images: int = -1,
842842
mask_and_scale: bool = True,

xee/micro_benchmarks.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import os
2323
import tempfile
2424
import timeit
25+
from typing import List
2526

2627
from absl import app
2728
import numpy as np
@@ -70,7 +71,7 @@ def open_and_write() -> None:
7071
ds.to_zarr(os.path.join(tmpdir, 'imerg.zarr'))
7172

7273

73-
def main(_: list[str]) -> None:
74+
def main(_: List[str]) -> None:
7475
print('Initializing EE...')
7576
init_ee_for_tests()
7677
print(f'[{REPEAT} time(s) with {LOOPS} loop(s) each.]')

xee/types.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
# limitations under the License.
1414
# ==============================================================================
1515
"""Type definitions for Earth Engine concepts (and others)."""
16-
from typing import Union, TypedDict
16+
from typing import Dict, List, Tuple, Union, TypedDict
1717

18-
TileIndex = tuple[int, int, int]
18+
TileIndex = Tuple[int, int, int]
1919
# x_min, y_min, x_max, y_max
20-
Bounds = tuple[float, float, float, float]
20+
Bounds = Tuple[float, float, float, float]
2121
# x_start, y_start, x_stop, y_stop
22-
BBox = tuple[int, int, int, int]
22+
BBox = Tuple[int, int, int, int]
2323
# index_start, index_stop, x_start, y_start, x_stop, y_stop
24-
BBox3d = tuple[int, int, int, int, int, int]
25-
Grid = dict[str, Union[dict[str, Union[float, str]], str, float]]
24+
BBox3d = Tuple[int, int, int, int, int, int]
25+
Grid = Dict[str, Union[Dict[str, Union[float, str]], str, float]]
2626

2727

2828
class DataType(TypedDict):
@@ -34,14 +34,14 @@ class DataType(TypedDict):
3434

3535
class BandInfo(TypedDict):
3636
crs: str
37-
crs_transform: list[int] # len: 6, gdal order
37+
crs_transform: List[int] # len: 6, gdal order
3838
data_type: DataType
39-
dimensions: list[int] # len: 2
39+
dimensions: List[int] # len: 2
4040
id: str
4141

4242

4343
class ImageInfo(TypedDict):
4444
type: str
45-
bands: list[BandInfo]
45+
bands: List[BandInfo]
4646
id: str
4747
version: int

0 commit comments

Comments
 (0)