rio-tiler 8.0.4__py3-none-any.whl → 8.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rio_tiler/io/rasterio.py CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  import contextlib
4
4
  import warnings
5
- from typing import Any, Callable, Dict, List, Optional, Sequence, Union, cast
5
+ from collections.abc import Callable
6
+ from typing import Any, cast
6
7
 
7
8
  import attr
8
9
  import numpy
@@ -34,7 +35,7 @@ from rio_tiler.errors import (
34
35
  from rio_tiler.expression import parse_expression
35
36
  from rio_tiler.io.base import BaseReader
36
37
  from rio_tiler.models import BandStatistics, ImageData, Info, PointData
37
- from rio_tiler.types import BBox, Indexes, NumType, RIOResampling
38
+ from rio_tiler.types import BBox, Indexes, RIOResampling
38
39
  from rio_tiler.utils import (
39
40
  CRS_to_uri,
40
41
  _validate_shape_input,
@@ -73,14 +74,14 @@ class Reader(BaseReader):
73
74
 
74
75
  """
75
76
 
76
- input: str = attr.ib()
77
- dataset: Union[DatasetReader, DatasetWriter, MemoryFile, WarpedVRT] = attr.ib(
77
+ input: str | None = attr.ib()
78
+ dataset: DatasetReader | DatasetWriter | MemoryFile | WarpedVRT | None = attr.ib(
78
79
  default=None
79
80
  )
80
81
 
81
82
  tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
82
83
 
83
- colormap: Dict = attr.ib(default=None)
84
+ colormap: dict | None = attr.ib(default=None)
84
85
 
85
86
  options: reader.Options = attr.ib()
86
87
 
@@ -214,14 +215,14 @@ class Reader(BaseReader):
214
215
  def statistics(
215
216
  self,
216
217
  categorical: bool = False,
217
- categories: Optional[List[float]] = None,
218
- percentiles: Optional[List[int]] = None,
219
- hist_options: Optional[Dict] = None,
218
+ categories: list[float] | None = None,
219
+ percentiles: list[int] | None = None,
220
+ hist_options: dict | None = None,
220
221
  max_size: int = 1024,
221
- indexes: Optional[Indexes] = None,
222
- expression: Optional[str] = None,
222
+ indexes: Indexes | None = None,
223
+ expression: str | None = None,
223
224
  **kwargs: Any,
224
- ) -> Dict[str, BandStatistics]:
225
+ ) -> dict[str, BandStatistics]:
225
226
  """Return bands statistics from a dataset.
226
227
 
227
228
  Args:
@@ -254,9 +255,9 @@ class Reader(BaseReader):
254
255
  tile_y: int,
255
256
  tile_z: int,
256
257
  tilesize: int = 256,
257
- indexes: Optional[Indexes] = None,
258
- expression: Optional[str] = None,
259
- buffer: Optional[float] = None,
258
+ indexes: Indexes | None = None,
259
+ expression: str | None = None,
260
+ buffer: float | None = None,
260
261
  **kwargs: Any,
261
262
  ) -> ImageData:
262
263
  """Read a Web Map tile from a Dataset.
@@ -296,14 +297,14 @@ class Reader(BaseReader):
296
297
  def part(
297
298
  self,
298
299
  bbox: BBox,
299
- dst_crs: Optional[CRS] = None,
300
+ dst_crs: CRS | None = None,
300
301
  bounds_crs: CRS = WGS84_CRS,
301
- indexes: Optional[Union[int, Sequence]] = None,
302
- expression: Optional[str] = None,
303
- max_size: Optional[int] = None,
304
- height: Optional[int] = None,
305
- width: Optional[int] = None,
306
- buffer: Optional[float] = None,
302
+ indexes: Indexes | None = None,
303
+ expression: str | None = None,
304
+ max_size: int | None = None,
305
+ height: int | None = None,
306
+ width: int | None = None,
307
+ buffer: float | None = None,
307
308
  **kwargs: Any,
308
309
  ) -> ImageData:
309
310
  """Read part of a Dataset.
@@ -359,11 +360,11 @@ class Reader(BaseReader):
359
360
 
360
361
  def preview(
361
362
  self,
362
- indexes: Optional[Indexes] = None,
363
- expression: Optional[str] = None,
363
+ indexes: Indexes | None = None,
364
+ expression: str | None = None,
364
365
  max_size: int = 1024,
365
- height: Optional[int] = None,
366
- width: Optional[int] = None,
366
+ height: int | None = None,
367
+ width: int | None = None,
367
368
  **kwargs: Any,
368
369
  ) -> ImageData:
369
370
  """Return a preview of a Dataset.
@@ -394,8 +395,8 @@ class Reader(BaseReader):
394
395
  lon: float,
395
396
  lat: float,
396
397
  coord_crs: CRS = WGS84_CRS,
397
- indexes: Optional[Indexes] = None,
398
- expression: Optional[str] = None,
398
+ indexes: Indexes | None = None,
399
+ expression: str | None = None,
399
400
  **kwargs: Any,
400
401
  ) -> PointData:
401
402
  """Read a pixel value from a Dataset.
@@ -435,15 +436,15 @@ class Reader(BaseReader):
435
436
 
436
437
  def feature(
437
438
  self,
438
- shape: Dict,
439
- dst_crs: Optional[CRS] = None,
439
+ shape: dict,
440
+ dst_crs: CRS | None = None,
440
441
  shape_crs: CRS = WGS84_CRS,
441
- indexes: Optional[Indexes] = None,
442
- expression: Optional[str] = None,
443
- max_size: Optional[int] = None,
444
- height: Optional[int] = None,
445
- width: Optional[int] = None,
446
- buffer: Optional[NumType] = None,
442
+ indexes: Indexes | None = None,
443
+ expression: str | None = None,
444
+ max_size: int | None = None,
445
+ height: int | None = None,
446
+ width: int | None = None,
447
+ buffer: float | None = None,
447
448
  **kwargs: Any,
448
449
  ) -> ImageData:
449
450
  """Read part of a Dataset defined by a geojson feature.
@@ -514,8 +515,8 @@ class Reader(BaseReader):
514
515
 
515
516
  def read(
516
517
  self,
517
- indexes: Optional[Indexes] = None,
518
- expression: Optional[str] = None,
518
+ indexes: Indexes | None = None,
519
+ expression: str | None = None,
519
520
  **kwargs: Any,
520
521
  ) -> ImageData:
521
522
  """Read the Dataset.
@@ -560,7 +561,7 @@ class LocalTileMatrixSet:
560
561
  minzoom: int = attr.ib(init=False, default=0)
561
562
  maxzoom: int = attr.ib(init=False)
562
563
 
563
- rasterio_crs: CRS = attr.ib(init=False, default=None)
564
+ rasterio_crs: CRS | None = attr.ib(init=False, default=None)
564
565
 
565
566
  @maxzoom.default
566
567
  def _maxzoom(self):
@@ -594,7 +595,7 @@ class ImageReader(Reader):
594
595
 
595
596
  tms: TileMatrixSet = attr.ib(init=False)
596
597
 
597
- crs: CRS = attr.ib(init=False, default=None)
598
+ crs: CRS | None = attr.ib(init=False, default=None)
598
599
  transform: Affine = attr.ib(init=False)
599
600
 
600
601
  def __attrs_post_init__(self):
@@ -635,14 +636,13 @@ class ImageReader(Reader):
635
636
  tile_y: int,
636
637
  tile_z: int,
637
638
  tilesize: int = 256,
638
- indexes: Optional[Indexes] = None,
639
- expression: Optional[str] = None,
640
- out_dtype: Optional[Union[str, numpy.dtype]] = None,
639
+ indexes: Indexes | None = None,
640
+ expression: str | None = None,
641
+ out_dtype: str | numpy.dtype | None = None,
641
642
  resampling_method: RIOResampling = "nearest",
642
643
  unscale: bool = False,
643
- post_process: Optional[
644
- Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
645
- ] = None,
644
+ post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
645
+ | None = None,
646
646
  ) -> ImageData:
647
647
  """Read a Web Map tile from an Image.
648
648
 
@@ -682,17 +682,16 @@ class ImageReader(Reader):
682
682
  def part( # type: ignore
683
683
  self,
684
684
  bbox: BBox,
685
- indexes: Optional[Union[int, Sequence]] = None,
686
- expression: Optional[str] = None,
687
- max_size: Optional[int] = None,
688
- height: Optional[int] = None,
689
- width: Optional[int] = None,
690
- out_dtype: Optional[Union[str, numpy.dtype]] = None,
685
+ indexes: Indexes | None = None,
686
+ expression: str | None = None,
687
+ max_size: int | None = None,
688
+ height: int | None = None,
689
+ width: int | None = None,
690
+ out_dtype: str | numpy.dtype | None = None,
691
691
  resampling_method: RIOResampling = "nearest",
692
692
  unscale: bool = False,
693
- post_process: Optional[
694
- Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
695
- ] = None,
693
+ post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
694
+ | None = None,
696
695
  ) -> ImageData:
697
696
  """Read part of an Image.
698
697
 
@@ -744,14 +743,13 @@ class ImageReader(Reader):
744
743
  self,
745
744
  x: float,
746
745
  y: float,
747
- indexes: Optional[Indexes] = None,
748
- expression: Optional[str] = None,
749
- out_dtype: Optional[Union[str, numpy.dtype]] = None,
746
+ indexes: Indexes | None = None,
747
+ expression: str | None = None,
748
+ out_dtype: str | numpy.dtype | None = None,
750
749
  resampling_method: RIOResampling = "nearest",
751
750
  unscale: bool = False,
752
- post_process: Optional[
753
- Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
754
- ] = None,
751
+ post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
752
+ | None = None,
755
753
  ) -> PointData:
756
754
  """Read a pixel value from an Image.
757
755
 
@@ -793,18 +791,17 @@ class ImageReader(Reader):
793
791
 
794
792
  def feature( # type: ignore
795
793
  self,
796
- shape: Dict,
797
- indexes: Optional[Indexes] = None,
798
- expression: Optional[str] = None,
799
- max_size: Optional[int] = None,
800
- height: Optional[int] = None,
801
- width: Optional[int] = None,
802
- out_dtype: Optional[Union[str, numpy.dtype]] = None,
794
+ shape: dict,
795
+ indexes: Indexes | None = None,
796
+ expression: str | None = None,
797
+ max_size: int | None = None,
798
+ height: int | None = None,
799
+ width: int | None = None,
800
+ out_dtype: str | numpy.dtype | None = None,
803
801
  resampling_method: RIOResampling = "nearest",
804
802
  unscale: bool = False,
805
- post_process: Optional[
806
- Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
807
- ] = None,
803
+ post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
804
+ | None = None,
808
805
  ) -> ImageData:
809
806
  """Read part of an Image defined by a geojson feature."""
810
807
  bbox = featureBounds(shape)
rio_tiler/io/stac.py CHANGED
@@ -3,18 +3,8 @@
3
3
  import json
4
4
  import os
5
5
  import warnings
6
- from typing import (
7
- Any,
8
- Dict,
9
- Iterator,
10
- List,
11
- Optional,
12
- Sequence,
13
- Set,
14
- Tuple,
15
- Type,
16
- Union,
17
- )
6
+ from collections.abc import Iterator, Sequence
7
+ from typing import Any
18
8
  from urllib.parse import urlparse
19
9
 
20
10
  import attr
@@ -111,7 +101,7 @@ def aws_get_object(
111
101
  LRUCache(maxsize=512),
112
102
  key=lambda filepath, **kargs: hashkey(filepath, json.dumps(kargs)),
113
103
  )
114
- def fetch(filepath: str, **kwargs: Any) -> Dict:
104
+ def fetch(filepath: str, **kwargs: Any) -> dict:
115
105
  """Fetch STAC items.
116
106
 
117
107
  A LRU cache is set on top of this function.
@@ -142,11 +132,11 @@ def fetch(filepath: str, **kwargs: Any) -> Dict:
142
132
 
143
133
  def _get_assets(
144
134
  stac_item: pystac.Item,
145
- include: Optional[Set[str]] = None,
146
- exclude: Optional[Set[str]] = None,
147
- include_asset_types: Optional[Set[str]] = None,
148
- exclude_asset_types: Optional[Set[str]] = None,
149
- ) -> Iterator:
135
+ include: set[str] | None = None,
136
+ exclude: set[str] | None = None,
137
+ include_asset_types: set[str] | None = None,
138
+ exclude_asset_types: set[str] | None = None,
139
+ ) -> Iterator[str]:
150
140
  """Get valid asset list.
151
141
 
152
142
  Args:
@@ -183,7 +173,7 @@ def _get_assets(
183
173
  yield asset
184
174
 
185
175
 
186
- def _to_pystac_item(item: Union[None, Dict, pystac.Item]) -> Union[None, pystac.Item]:
176
+ def _to_pystac_item(item: dict | pystac.Item | None) -> pystac.Item | None:
187
177
  """Attr converter to convert to Dict to pystac.Item
188
178
 
189
179
  Args:
@@ -193,7 +183,7 @@ def _to_pystac_item(item: Union[None, Dict, pystac.Item]) -> Union[None, pystac.
193
183
  pystac.Item: pystac STAC item object.
194
184
 
195
185
  """
196
- if isinstance(item, Dict):
186
+ if isinstance(item, dict):
197
187
  return pystac.Item.from_dict(item)
198
188
 
199
189
  return item
@@ -237,26 +227,26 @@ class STACReader(MultiBaseReader):
237
227
 
238
228
  """
239
229
 
240
- input: str = attr.ib()
241
- item: pystac.Item = attr.ib(default=None, converter=_to_pystac_item)
230
+ input: str | None = attr.ib()
231
+ item: pystac.Item | None = attr.ib(default=None, converter=_to_pystac_item)
242
232
 
243
233
  tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
244
- minzoom: int = attr.ib(default=None)
245
- maxzoom: int = attr.ib(default=None)
234
+ minzoom: int | None = attr.ib(default=None)
235
+ maxzoom: int | None = attr.ib(default=None)
246
236
 
247
- include_assets: Optional[Set[str]] = attr.ib(default=None)
248
- exclude_assets: Optional[Set[str]] = attr.ib(default=None)
237
+ include_assets: set[str] | None = attr.ib(default=None)
238
+ exclude_assets: set[str] | None = attr.ib(default=None)
249
239
 
250
- include_asset_types: Set[str] = attr.ib(default=DEFAULT_VALID_TYPE)
251
- exclude_asset_types: Optional[Set[str]] = attr.ib(default=None)
240
+ include_asset_types: set[str] = attr.ib(default=DEFAULT_VALID_TYPE)
241
+ exclude_asset_types: set[str] | None = attr.ib(default=None)
252
242
 
253
243
  assets: Sequence[str] = attr.ib(init=False)
254
- default_assets: Optional[Sequence[str]] = attr.ib(default=None)
244
+ default_assets: Sequence[str] | None = attr.ib(default=None)
255
245
 
256
- reader: Type[BaseReader] = attr.ib(default=Reader)
257
- reader_options: Dict = attr.ib(factory=dict)
246
+ reader: type[BaseReader] = attr.ib(default=Reader)
247
+ reader_options: dict = attr.ib(factory=dict)
258
248
 
259
- fetch_options: Dict = attr.ib(factory=dict)
249
+ fetch_options: dict = attr.ib(factory=dict)
260
250
 
261
251
  ctx: rasterio.Env = attr.ib(default=rasterio.Env)
262
252
 
@@ -289,7 +279,7 @@ class STACReader(MultiBaseReader):
289
279
  if not self.assets:
290
280
  raise MissingAssets("No valid asset found. Asset's media types not supported")
291
281
 
292
- def get_asset_list(self) -> List[str]:
282
+ def get_asset_list(self) -> list[str]:
293
283
  """Get valid asset list"""
294
284
  return list(
295
285
  _get_assets(
@@ -301,11 +291,11 @@ class STACReader(MultiBaseReader):
301
291
  )
302
292
  )
303
293
 
304
- def _get_reader(self, asset_info: AssetInfo) -> Tuple[Type[BaseReader], Dict]:
294
+ def _get_reader(self, asset_info: AssetInfo) -> tuple[type[BaseReader], dict]:
305
295
  """Get Asset Reader."""
306
296
  return self.reader, {}
307
297
 
308
- def _parse_vrt_asset(self, asset: str) -> Tuple[str, Optional[str]]:
298
+ def _parse_vrt_asset(self, asset: str) -> tuple[str, str | None]:
309
299
  if asset.startswith("vrt://") and asset not in self.assets:
310
300
  parsed = urlparse(asset)
311
301
  if not parsed.netloc:
rio_tiler/io/xarray.py CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import math
6
6
  import os
7
7
  import warnings
8
- from typing import Any, Dict, List, Tuple, cast
8
+ from typing import Any, cast
9
9
 
10
10
  import attr
11
11
  import numpy
@@ -81,7 +81,7 @@ class XarrayReader(BaseReader):
81
81
 
82
82
  tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
83
83
 
84
- _dims: List = attr.ib(init=False, factory=list)
84
+ _dims: list = attr.ib(init=False, factory=list)
85
85
 
86
86
  def __attrs_post_init__(self):
87
87
  """Set bounds and CRS."""
@@ -138,7 +138,7 @@ class XarrayReader(BaseReader):
138
138
  return self._maxzoom
139
139
 
140
140
  @property
141
- def band_descriptions(self) -> List[str]:
141
+ def band_descriptions(self) -> list[str]:
142
142
  """
143
143
  Return list of `band descriptions` in DataArray.
144
144
 
@@ -193,7 +193,7 @@ class XarrayReader(BaseReader):
193
193
  def _sel_indexes(
194
194
  self,
195
195
  indexes: Indexes | None = None,
196
- ) -> Tuple[xarray.DataArray, List[str], List[str]]:
196
+ ) -> tuple[xarray.DataArray, list[str], list[str]]:
197
197
  """Select `band` indexes in DataArray."""
198
198
  da = self.input
199
199
  band_descriptions = self.band_descriptions
@@ -220,13 +220,13 @@ class XarrayReader(BaseReader):
220
220
  def statistics(
221
221
  self,
222
222
  categorical: bool = False,
223
- categories: List[float] | None = None,
224
- percentiles: List[int] | None = None,
225
- hist_options: Dict | None = None,
223
+ categories: list[float] | None = None,
224
+ percentiles: list[int] | None = None,
225
+ hist_options: dict | None = None,
226
226
  nodata: NoData | None = None,
227
227
  indexes: Indexes | None = None,
228
228
  **kwargs: Any,
229
- ) -> Dict[str, BandStatistics]:
229
+ ) -> dict[str, BandStatistics]:
230
230
  """Return statistics from a dataset."""
231
231
  hist_options = hist_options or {}
232
232
 
@@ -656,7 +656,7 @@ class XarrayReader(BaseReader):
656
656
 
657
657
  def feature(
658
658
  self,
659
- shape: Dict,
659
+ shape: dict,
660
660
  dst_crs: CRS | None = None,
661
661
  shape_crs: CRS = WGS84_CRS,
662
662
  reproject_method: WarpResampling = "nearest",
rio_tiler/models.py CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  import itertools
4
4
  import warnings
5
- from typing import Any, Dict, List, Literal, Optional, Sequence, Tuple, Union, cast
5
+ from collections.abc import Sequence
6
+ from typing import Any, Literal, cast
6
7
 
7
8
  import attr
8
9
  import numpy
@@ -34,7 +35,6 @@ from rio_tiler.types import (
34
35
  GDALColorMapType,
35
36
  IntervalTuple,
36
37
  NoData,
37
- NumType,
38
38
  RIOResampling,
39
39
  WarpResampling,
40
40
  )
@@ -58,14 +58,14 @@ class Bounds(BaseModel):
58
58
  class Info(Bounds):
59
59
  """Dataset Info."""
60
60
 
61
- band_metadata: List[Tuple[str, Dict]]
62
- band_descriptions: List[Tuple[str, str]]
61
+ band_metadata: list[tuple[str, dict]]
62
+ band_descriptions: list[tuple[str, str]]
63
63
  dtype: str
64
64
  nodata_type: Literal["Alpha", "Mask", "Internal", "Nodata", "None"]
65
- colorinterp: Optional[List[str]] = None
66
- scales: Optional[List[float]] = None
67
- offsets: Optional[List[float]] = None
68
- colormap: Optional[GDALColorMapType] = None
65
+ colorinterp: list[str] | None = None
66
+ scales: list[float] | None = None
67
+ offsets: list[float] | None = None
68
+ colormap: GDALColorMapType | None = None
69
69
 
70
70
  model_config = {"extra": "allow"}
71
71
 
@@ -83,7 +83,7 @@ class BandStatistics(BaseModel):
83
83
  majority: float
84
84
  minority: float
85
85
  unique: float
86
- histogram: List[List[NumType]]
86
+ histogram: list[list[float | int]]
87
87
  valid_percent: float
88
88
  masked_pixels: float
89
89
  valid_pixels: float
@@ -91,7 +91,7 @@ class BandStatistics(BaseModel):
91
91
  model_config = {"extra": "allow"}
92
92
 
93
93
 
94
- def to_coordsbbox(bbox) -> Optional[BoundingBox]:
94
+ def to_coordsbbox(bbox) -> BoundingBox | None:
95
95
  """Convert bbox to CoordsBbox nameTuple."""
96
96
  return BoundingBox(*bbox) if bbox else None
97
97
 
@@ -100,7 +100,7 @@ def rescale_image(
100
100
  array: numpy.ma.MaskedArray,
101
101
  in_range: Sequence[IntervalTuple],
102
102
  out_range: Sequence[IntervalTuple] = ((0, 255),),
103
- out_dtype: Union[str, numpy.number] = "uint8",
103
+ out_dtype: str | numpy.number = "uint8",
104
104
  ) -> numpy.ma.MaskedArray:
105
105
  """Rescale image data in-place."""
106
106
  if len(array.shape) < 3:
@@ -156,16 +156,16 @@ class PointData:
156
156
  """
157
157
 
158
158
  array: numpy.ma.MaskedArray = attr.ib(converter=to_masked)
159
- band_names: List[str] = attr.ib(kw_only=True)
160
- band_descriptions: List[str] = attr.ib(kw_only=True)
161
- coordinates: Optional[Tuple[float, float]] = attr.ib(default=None, kw_only=True)
162
- crs: Optional[CRS] = attr.ib(default=None, kw_only=True)
163
- assets: Optional[List] = attr.ib(default=None, kw_only=True)
164
- metadata: Optional[Dict] = attr.ib(factory=dict, kw_only=True)
165
- nodata: Optional[NoData] = attr.ib(default=None, kw_only=True)
166
- scales: List[NumType] = attr.ib(kw_only=True)
167
- offsets: List[NumType] = attr.ib(kw_only=True)
168
- pixel_location: Optional[Tuple[NumType, NumType]] = attr.ib(
159
+ band_names: list[str] = attr.ib(kw_only=True)
160
+ band_descriptions: list[str] = attr.ib(kw_only=True)
161
+ coordinates: tuple[float, float] | None = attr.ib(default=None, kw_only=True)
162
+ crs: CRS | None = attr.ib(default=None, kw_only=True)
163
+ assets: list | None = attr.ib(default=None, kw_only=True)
164
+ metadata: dict | None = attr.ib(factory=dict, kw_only=True)
165
+ nodata: NoData | None = attr.ib(default=None, kw_only=True)
166
+ scales: list[float | int] = attr.ib(kw_only=True)
167
+ offsets: list[float | int] = attr.ib(kw_only=True)
168
+ pixel_location: tuple[float | int, float | int] | None = attr.ib(
169
169
  default=None, kw_only=True
170
170
  )
171
171
 
@@ -340,22 +340,22 @@ class ImageData:
340
340
  """
341
341
 
342
342
  array: numpy.ma.MaskedArray = attr.ib(converter=masked_and_3d)
343
- assets: Optional[List] = attr.ib(default=None, kw_only=True)
344
- bounds: Optional[BoundingBox] = attr.ib(
343
+ assets: list | None = attr.ib(default=None, kw_only=True)
344
+ bounds: BoundingBox | None = attr.ib(
345
345
  default=None, converter=to_coordsbbox, kw_only=True
346
346
  )
347
- crs: Optional[CRS] = attr.ib(default=None, kw_only=True)
348
- metadata: Optional[Dict] = attr.ib(factory=dict, kw_only=True)
349
- nodata: Optional[NoData] = attr.ib(default=None, kw_only=True)
350
- scales: List[NumType] = attr.ib(kw_only=True)
351
- offsets: List[NumType] = attr.ib(kw_only=True)
352
- band_names: List[str] = attr.ib(kw_only=True)
353
- band_descriptions: List[str] = attr.ib(kw_only=True)
354
- dataset_statistics: Optional[Sequence[Tuple[float, float]]] = attr.ib(
347
+ crs: CRS | None = attr.ib(default=None, kw_only=True)
348
+ metadata: dict | None = attr.ib(factory=dict, kw_only=True)
349
+ nodata: NoData | None = attr.ib(default=None, kw_only=True)
350
+ scales: list[float | int] = attr.ib(kw_only=True)
351
+ offsets: list[float | int] = attr.ib(kw_only=True)
352
+ band_names: list[str] = attr.ib(kw_only=True)
353
+ band_descriptions: list[str] = attr.ib(kw_only=True)
354
+ dataset_statistics: Sequence[tuple[float, float]] | None = attr.ib(
355
355
  default=None, kw_only=True
356
356
  )
357
- cutline_mask: Optional[numpy.ndarray] = attr.ib(default=None)
358
- alpha_mask: Optional[numpy.ndarray] = attr.ib(default=None)
357
+ cutline_mask: numpy.ndarray | None = attr.ib(default=None)
358
+ alpha_mask: numpy.ndarray | None = attr.ib(default=None)
359
359
 
360
360
  @band_names.default
361
361
  def _default_band_names(self):
@@ -596,7 +596,7 @@ class ImageData:
596
596
  self,
597
597
  in_range: Sequence[IntervalTuple],
598
598
  out_range: Sequence[IntervalTuple] = ((0, 255),),
599
- out_dtype: Union[str, numpy.number] = "uint8",
599
+ out_dtype: str | numpy.number = "uint8",
600
600
  ) -> Self:
601
601
  """Rescale data in place."""
602
602
  self.array = rescale_image(
@@ -618,7 +618,7 @@ class ImageData:
618
618
 
619
619
  return self
620
620
 
621
- def apply_color_formula(self, color_formula: Optional[str]) -> Self:
621
+ def apply_color_formula(self, color_formula: str | None) -> Self:
622
622
  """Apply color-operations formula in place."""
623
623
  out = self.array.data
624
624
  out[out < 0] = 0
@@ -759,9 +759,9 @@ class ImageData:
759
759
 
760
760
  def post_process(
761
761
  self,
762
- in_range: Optional[Sequence[IntervalTuple]] = None,
763
- out_dtype: Union[str, numpy.number] = "uint8",
764
- color_formula: Optional[str] = None,
762
+ in_range: Sequence[IntervalTuple] | None = None,
763
+ out_dtype: str | numpy.number = "uint8",
764
+ color_formula: str | None = None,
765
765
  **kwargs: Any,
766
766
  ) -> "ImageData":
767
767
  """Post-process image data.
@@ -803,7 +803,7 @@ class ImageData:
803
803
  self,
804
804
  add_mask: bool = True,
805
805
  img_format: str = "PNG",
806
- colormap: Optional[ColorMapType] = None,
806
+ colormap: ColorMapType | None = None,
807
807
  **kwargs,
808
808
  ) -> bytes:
809
809
  """Render data to image blob.
@@ -899,11 +899,11 @@ class ImageData:
899
899
  def statistics(
900
900
  self,
901
901
  categorical: bool = False,
902
- categories: Optional[List[float]] = None,
903
- percentiles: Optional[List[int]] = None,
904
- hist_options: Optional[Dict] = None,
905
- coverage: Optional[numpy.ndarray] = None,
906
- ) -> Dict[str, BandStatistics]:
902
+ categories: list[float] | None = None,
903
+ percentiles: list[int] | None = None,
904
+ hist_options: dict | None = None,
905
+ coverage: numpy.ndarray | None = None,
906
+ ) -> dict[str, BandStatistics]:
907
907
  """Return statistics from ImageData."""
908
908
  hist_options = hist_options or {}
909
909
 
@@ -923,7 +923,7 @@ class ImageData:
923
923
 
924
924
  def get_coverage_array(
925
925
  self,
926
- shape: Dict,
926
+ shape: dict,
927
927
  shape_crs: CRS = WGS84_CRS,
928
928
  cover_scale: int = 10,
929
929
  ) -> NDArray[numpy.floating]:
@@ -972,7 +972,7 @@ class ImageData:
972
972
  def reproject(
973
973
  self,
974
974
  dst_crs: CRS,
975
- resolution: Optional[Tuple[float, float]] = None,
975
+ resolution: tuple[float, float] | None = None,
976
976
  reproject_method: WarpResampling = "nearest",
977
977
  ) -> "ImageData":
978
978
  """Reproject data and mask."""
@@ -2,7 +2,7 @@
2
2
 
3
3
  import abc
4
4
  import logging
5
- from typing import Any, Type
5
+ from typing import Any
6
6
 
7
7
  import attr
8
8
  from morecantile import TileMatrixSet
@@ -51,7 +51,7 @@ class BaseBackend(BaseReader):
51
51
  input: str = attr.ib()
52
52
  tms: TileMatrixSet = attr.ib(default=WEB_MERCATOR_TMS)
53
53
 
54
- reader: Type[BaseReader] | Type[MultiBaseReader] | Type[MultiBandReader] = attr.ib(
54
+ reader: type[BaseReader] | type[MultiBaseReader] | type[MultiBandReader] = attr.ib(
55
55
  default=Reader
56
56
  )
57
57
  reader_options: dict = attr.ib(factory=dict)