rio-tiler 8.0.4__py3-none-any.whl → 9.0.0a1__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/__init__.py +1 -1
- rio_tiler/colormap.py +6 -6
- rio_tiler/experimental/vsifile.py +1 -3
- rio_tiler/experimental/zarr.py +29 -28
- rio_tiler/expression.py +4 -4
- rio_tiler/io/base.py +222 -347
- rio_tiler/io/rasterio.py +89 -81
- rio_tiler/io/stac.py +50 -41
- rio_tiler/io/xarray.py +35 -27
- rio_tiler/models.py +70 -53
- rio_tiler/mosaic/backend.py +2 -2
- rio_tiler/mosaic/methods/base.py +3 -4
- rio_tiler/mosaic/methods/defaults.py +18 -19
- rio_tiler/mosaic/reader.py +20 -19
- rio_tiler/reader.py +44 -44
- rio_tiler/tasks.py +9 -8
- rio_tiler/types.py +20 -21
- rio_tiler/utils.py +33 -42
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/METADATA +1 -1
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/RECORD +23 -23
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/WHEEL +0 -0
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/licenses/AUTHORS.txt +0 -0
- {rio_tiler-8.0.4.dist-info → rio_tiler-9.0.0a1.dist-info}/licenses/LICENSE +0 -0
rio_tiler/io/rasterio.py
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import contextlib
|
|
4
4
|
import warnings
|
|
5
|
-
from
|
|
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,
|
|
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:
|
|
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:
|
|
84
|
+
colormap: dict | None = attr.ib(default=None)
|
|
84
85
|
|
|
85
86
|
options: reader.Options = attr.ib()
|
|
86
87
|
|
|
@@ -168,7 +169,7 @@ class Reader(BaseReader):
|
|
|
168
169
|
|
|
169
170
|
def _get_descr(ix):
|
|
170
171
|
"""Return band description."""
|
|
171
|
-
return self.dataset.descriptions[ix - 1] or ""
|
|
172
|
+
return self.dataset.descriptions[ix - 1] or f"b{ix}"
|
|
172
173
|
|
|
173
174
|
if self.options.get("nodata", self.dataset.nodata) is not None:
|
|
174
175
|
nodata_type = "Nodata"
|
|
@@ -214,14 +215,14 @@ class Reader(BaseReader):
|
|
|
214
215
|
def statistics(
|
|
215
216
|
self,
|
|
216
217
|
categorical: bool = False,
|
|
217
|
-
categories:
|
|
218
|
-
percentiles:
|
|
219
|
-
hist_options:
|
|
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:
|
|
222
|
-
expression:
|
|
222
|
+
indexes: Indexes | None = None,
|
|
223
|
+
expression: str | None = None,
|
|
223
224
|
**kwargs: Any,
|
|
224
|
-
) ->
|
|
225
|
+
) -> dict[str, BandStatistics]:
|
|
225
226
|
"""Return bands statistics from a dataset.
|
|
226
227
|
|
|
227
228
|
Args:
|
|
@@ -253,10 +254,10 @@ class Reader(BaseReader):
|
|
|
253
254
|
tile_x: int,
|
|
254
255
|
tile_y: int,
|
|
255
256
|
tile_z: int,
|
|
256
|
-
tilesize: int =
|
|
257
|
-
indexes:
|
|
258
|
-
expression:
|
|
259
|
-
buffer:
|
|
257
|
+
tilesize: int | None = 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.
|
|
@@ -265,7 +266,7 @@ class Reader(BaseReader):
|
|
|
265
266
|
tile_x (int): Tile's horizontal index.
|
|
266
267
|
tile_y (int): Tile's vertical index.
|
|
267
268
|
tile_z (int): Tile's zoom level index.
|
|
268
|
-
tilesize (int, optional): Output image size.
|
|
269
|
+
tilesize (int, optional): Output image size.
|
|
269
270
|
indexes (int or sequence of int, optional): Band indexes.
|
|
270
271
|
expression (str, optional): rio-tiler expression (e.g. b1/b2+b3).
|
|
271
272
|
buffer (float, optional): Buffer on each side of the given tile. It must be a multiple of `0.5`. Output **tilesize** will be expanded to `tilesize + 2 * tile_buffer` (e.g 0.5 = 257x257, 1.0 = 258x258).
|
|
@@ -280,12 +281,18 @@ class Reader(BaseReader):
|
|
|
280
281
|
f"Tile(x={tile_x}, y={tile_y}, z={tile_z}) is outside bounds"
|
|
281
282
|
)
|
|
282
283
|
|
|
284
|
+
matrix = self.tms.matrix(tile_z)
|
|
285
|
+
bbox = cast(
|
|
286
|
+
BBox,
|
|
287
|
+
self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z)),
|
|
288
|
+
)
|
|
289
|
+
|
|
283
290
|
return self.part(
|
|
284
|
-
|
|
291
|
+
bbox,
|
|
285
292
|
dst_crs=self.tms.rasterio_crs,
|
|
286
293
|
bounds_crs=self.tms.rasterio_crs,
|
|
287
|
-
height=tilesize,
|
|
288
|
-
width=tilesize,
|
|
294
|
+
height=tilesize or matrix.tileHeight,
|
|
295
|
+
width=tilesize or matrix.tileWidth,
|
|
289
296
|
max_size=None,
|
|
290
297
|
indexes=indexes,
|
|
291
298
|
expression=expression,
|
|
@@ -296,14 +303,14 @@ class Reader(BaseReader):
|
|
|
296
303
|
def part(
|
|
297
304
|
self,
|
|
298
305
|
bbox: BBox,
|
|
299
|
-
dst_crs:
|
|
306
|
+
dst_crs: CRS | None = None,
|
|
300
307
|
bounds_crs: CRS = WGS84_CRS,
|
|
301
|
-
indexes:
|
|
302
|
-
expression:
|
|
303
|
-
max_size:
|
|
304
|
-
height:
|
|
305
|
-
width:
|
|
306
|
-
buffer:
|
|
308
|
+
indexes: Indexes | None = None,
|
|
309
|
+
expression: str | None = None,
|
|
310
|
+
max_size: int | None = None,
|
|
311
|
+
height: int | None = None,
|
|
312
|
+
width: int | None = None,
|
|
313
|
+
buffer: float | None = None,
|
|
307
314
|
**kwargs: Any,
|
|
308
315
|
) -> ImageData:
|
|
309
316
|
"""Read part of a Dataset.
|
|
@@ -359,11 +366,11 @@ class Reader(BaseReader):
|
|
|
359
366
|
|
|
360
367
|
def preview(
|
|
361
368
|
self,
|
|
362
|
-
indexes:
|
|
363
|
-
expression:
|
|
369
|
+
indexes: Indexes | None = None,
|
|
370
|
+
expression: str | None = None,
|
|
364
371
|
max_size: int = 1024,
|
|
365
|
-
height:
|
|
366
|
-
width:
|
|
372
|
+
height: int | None = None,
|
|
373
|
+
width: int | None = None,
|
|
367
374
|
**kwargs: Any,
|
|
368
375
|
) -> ImageData:
|
|
369
376
|
"""Return a preview of a Dataset.
|
|
@@ -394,8 +401,8 @@ class Reader(BaseReader):
|
|
|
394
401
|
lon: float,
|
|
395
402
|
lat: float,
|
|
396
403
|
coord_crs: CRS = WGS84_CRS,
|
|
397
|
-
indexes:
|
|
398
|
-
expression:
|
|
404
|
+
indexes: Indexes | None = None,
|
|
405
|
+
expression: str | None = None,
|
|
399
406
|
**kwargs: Any,
|
|
400
407
|
) -> PointData:
|
|
401
408
|
"""Read a pixel value from a Dataset.
|
|
@@ -435,15 +442,15 @@ class Reader(BaseReader):
|
|
|
435
442
|
|
|
436
443
|
def feature(
|
|
437
444
|
self,
|
|
438
|
-
shape:
|
|
439
|
-
dst_crs:
|
|
445
|
+
shape: dict,
|
|
446
|
+
dst_crs: CRS | None = None,
|
|
440
447
|
shape_crs: CRS = WGS84_CRS,
|
|
441
|
-
indexes:
|
|
442
|
-
expression:
|
|
443
|
-
max_size:
|
|
444
|
-
height:
|
|
445
|
-
width:
|
|
446
|
-
buffer:
|
|
448
|
+
indexes: Indexes | None = None,
|
|
449
|
+
expression: str | None = None,
|
|
450
|
+
max_size: int | None = None,
|
|
451
|
+
height: int | None = None,
|
|
452
|
+
width: int | None = None,
|
|
453
|
+
buffer: float | None = None,
|
|
447
454
|
**kwargs: Any,
|
|
448
455
|
) -> ImageData:
|
|
449
456
|
"""Read part of a Dataset defined by a geojson feature.
|
|
@@ -514,8 +521,8 @@ class Reader(BaseReader):
|
|
|
514
521
|
|
|
515
522
|
def read(
|
|
516
523
|
self,
|
|
517
|
-
indexes:
|
|
518
|
-
expression:
|
|
524
|
+
indexes: Indexes | None = None,
|
|
525
|
+
expression: str | None = None,
|
|
519
526
|
**kwargs: Any,
|
|
520
527
|
) -> ImageData:
|
|
521
528
|
"""Read the Dataset.
|
|
@@ -560,7 +567,7 @@ class LocalTileMatrixSet:
|
|
|
560
567
|
minzoom: int = attr.ib(init=False, default=0)
|
|
561
568
|
maxzoom: int = attr.ib(init=False)
|
|
562
569
|
|
|
563
|
-
rasterio_crs: CRS = attr.ib(init=False, default=None)
|
|
570
|
+
rasterio_crs: CRS | None = attr.ib(init=False, default=None)
|
|
564
571
|
|
|
565
572
|
@maxzoom.default
|
|
566
573
|
def _maxzoom(self):
|
|
@@ -592,9 +599,9 @@ class LocalTileMatrixSet:
|
|
|
592
599
|
class ImageReader(Reader):
|
|
593
600
|
"""Non Geo Image Reader"""
|
|
594
601
|
|
|
595
|
-
tms:
|
|
602
|
+
tms: LocalTileMatrixSet = attr.ib(init=False) # type: ignore[assignment]
|
|
596
603
|
|
|
597
|
-
crs: CRS = attr.ib(init=False, default=None)
|
|
604
|
+
crs: CRS | None = attr.ib(init=False, default=None)
|
|
598
605
|
transform: Affine = attr.ib(init=False)
|
|
599
606
|
|
|
600
607
|
def __attrs_post_init__(self):
|
|
@@ -634,15 +641,14 @@ class ImageReader(Reader):
|
|
|
634
641
|
tile_x: int,
|
|
635
642
|
tile_y: int,
|
|
636
643
|
tile_z: int,
|
|
637
|
-
tilesize: int =
|
|
638
|
-
indexes:
|
|
639
|
-
expression:
|
|
640
|
-
out_dtype:
|
|
644
|
+
tilesize: int | None = None,
|
|
645
|
+
indexes: Indexes | None = None,
|
|
646
|
+
expression: str | None = None,
|
|
647
|
+
out_dtype: str | numpy.dtype | None = None,
|
|
641
648
|
resampling_method: RIOResampling = "nearest",
|
|
642
649
|
unscale: bool = False,
|
|
643
|
-
post_process:
|
|
644
|
-
|
|
645
|
-
] = None,
|
|
650
|
+
post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
|
|
651
|
+
| None = None,
|
|
646
652
|
) -> ImageData:
|
|
647
653
|
"""Read a Web Map tile from an Image.
|
|
648
654
|
|
|
@@ -666,10 +672,15 @@ class ImageReader(Reader):
|
|
|
666
672
|
f"Tile {tile_z}/{tile_x}/{tile_y} is outside {self.input} bounds"
|
|
667
673
|
)
|
|
668
674
|
|
|
675
|
+
bbox = cast(
|
|
676
|
+
BBox,
|
|
677
|
+
self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z)),
|
|
678
|
+
)
|
|
679
|
+
|
|
669
680
|
return self.part(
|
|
670
|
-
|
|
671
|
-
height=tilesize,
|
|
672
|
-
width=tilesize,
|
|
681
|
+
bbox,
|
|
682
|
+
height=tilesize or self.tms.tile_size,
|
|
683
|
+
width=tilesize or self.tms.tile_size,
|
|
673
684
|
max_size=None,
|
|
674
685
|
indexes=indexes,
|
|
675
686
|
expression=expression,
|
|
@@ -682,17 +693,16 @@ class ImageReader(Reader):
|
|
|
682
693
|
def part( # type: ignore
|
|
683
694
|
self,
|
|
684
695
|
bbox: BBox,
|
|
685
|
-
indexes:
|
|
686
|
-
expression:
|
|
687
|
-
max_size:
|
|
688
|
-
height:
|
|
689
|
-
width:
|
|
690
|
-
out_dtype:
|
|
696
|
+
indexes: Indexes | None = None,
|
|
697
|
+
expression: str | None = None,
|
|
698
|
+
max_size: int | None = None,
|
|
699
|
+
height: int | None = None,
|
|
700
|
+
width: int | None = None,
|
|
701
|
+
out_dtype: str | numpy.dtype | None = None,
|
|
691
702
|
resampling_method: RIOResampling = "nearest",
|
|
692
703
|
unscale: bool = False,
|
|
693
|
-
post_process:
|
|
694
|
-
|
|
695
|
-
] = None,
|
|
704
|
+
post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
|
|
705
|
+
| None = None,
|
|
696
706
|
) -> ImageData:
|
|
697
707
|
"""Read part of an Image.
|
|
698
708
|
|
|
@@ -744,14 +754,13 @@ class ImageReader(Reader):
|
|
|
744
754
|
self,
|
|
745
755
|
x: float,
|
|
746
756
|
y: float,
|
|
747
|
-
indexes:
|
|
748
|
-
expression:
|
|
749
|
-
out_dtype:
|
|
757
|
+
indexes: Indexes | None = None,
|
|
758
|
+
expression: str | None = None,
|
|
759
|
+
out_dtype: str | numpy.dtype | None = None,
|
|
750
760
|
resampling_method: RIOResampling = "nearest",
|
|
751
761
|
unscale: bool = False,
|
|
752
|
-
post_process:
|
|
753
|
-
|
|
754
|
-
] = None,
|
|
762
|
+
post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
|
|
763
|
+
| None = None,
|
|
755
764
|
) -> PointData:
|
|
756
765
|
"""Read a pixel value from an Image.
|
|
757
766
|
|
|
@@ -793,18 +802,17 @@ class ImageReader(Reader):
|
|
|
793
802
|
|
|
794
803
|
def feature( # type: ignore
|
|
795
804
|
self,
|
|
796
|
-
shape:
|
|
797
|
-
indexes:
|
|
798
|
-
expression:
|
|
799
|
-
max_size:
|
|
800
|
-
height:
|
|
801
|
-
width:
|
|
802
|
-
out_dtype:
|
|
805
|
+
shape: dict,
|
|
806
|
+
indexes: Indexes | None = None,
|
|
807
|
+
expression: str | None = None,
|
|
808
|
+
max_size: int | None = None,
|
|
809
|
+
height: int | None = None,
|
|
810
|
+
width: int | None = None,
|
|
811
|
+
out_dtype: str | numpy.dtype | None = None,
|
|
803
812
|
resampling_method: RIOResampling = "nearest",
|
|
804
813
|
unscale: bool = False,
|
|
805
|
-
post_process:
|
|
806
|
-
|
|
807
|
-
] = None,
|
|
814
|
+
post_process: Callable[[numpy.ma.MaskedArray], numpy.ma.MaskedArray]
|
|
815
|
+
| None = None,
|
|
808
816
|
) -> ImageData:
|
|
809
817
|
"""Read part of an Image defined by a geojson feature."""
|
|
810
818
|
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
|
|
7
|
-
|
|
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) ->
|
|
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:
|
|
146
|
-
exclude:
|
|
147
|
-
include_asset_types:
|
|
148
|
-
exclude_asset_types:
|
|
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:
|
|
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,
|
|
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:
|
|
248
|
-
exclude_assets:
|
|
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:
|
|
251
|
-
exclude_asset_types:
|
|
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:
|
|
244
|
+
default_assets: Sequence[str] | None = attr.ib(default=None)
|
|
255
245
|
|
|
256
|
-
reader:
|
|
257
|
-
reader_options:
|
|
246
|
+
reader: type[BaseReader] = attr.ib(default=Reader)
|
|
247
|
+
reader_options: dict = attr.ib(factory=dict)
|
|
258
248
|
|
|
259
|
-
fetch_options:
|
|
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) ->
|
|
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) ->
|
|
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) ->
|
|
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:
|
|
@@ -333,33 +323,52 @@ class STACReader(MultiBaseReader):
|
|
|
333
323
|
|
|
334
324
|
"""
|
|
335
325
|
asset, vrt_options = self._parse_vrt_asset(asset)
|
|
326
|
+
|
|
327
|
+
method_options: dict[str, Any] = {}
|
|
328
|
+
|
|
329
|
+
# NOTE: asset can be in form of
|
|
330
|
+
# "{asset_name}|some_option=some_value&another_option=another_value"
|
|
331
|
+
if "|" in asset:
|
|
332
|
+
asset, params = asset.split("|", 1)
|
|
333
|
+
# NOTE: Construct method options from params
|
|
334
|
+
if params:
|
|
335
|
+
for param in params.split("&"):
|
|
336
|
+
key, value = param.split("=", 1)
|
|
337
|
+
if key == "indexes":
|
|
338
|
+
method_options["indexes"] = list(map(int, value.split(",")))
|
|
339
|
+
elif key == "expression":
|
|
340
|
+
method_options["expression"] = value
|
|
341
|
+
|
|
336
342
|
if asset not in self.assets:
|
|
337
343
|
raise InvalidAssetName(
|
|
338
344
|
f"'{asset}' is not valid, should be one of {self.assets}"
|
|
339
345
|
)
|
|
340
346
|
|
|
347
|
+
asset_modified = "expression" in method_options or vrt_options
|
|
348
|
+
|
|
341
349
|
asset_info = self.item.assets[asset]
|
|
342
350
|
extras = asset_info.extra_fields
|
|
343
351
|
|
|
344
352
|
info = AssetInfo(
|
|
345
353
|
url=asset_info.get_absolute_href() or asset_info.href,
|
|
346
|
-
|
|
354
|
+
name=asset,
|
|
355
|
+
media_type=asset_info.media_type,
|
|
356
|
+
method_options=method_options,
|
|
347
357
|
)
|
|
348
358
|
|
|
359
|
+
if not asset_modified:
|
|
360
|
+
info["metadata"] = extras
|
|
361
|
+
|
|
349
362
|
if STAC_ALTERNATE_KEY and extras.get("alternate"):
|
|
350
363
|
if alternate := extras["alternate"].get(STAC_ALTERNATE_KEY):
|
|
351
364
|
info["url"] = alternate["href"]
|
|
352
365
|
|
|
353
|
-
if asset_info.media_type:
|
|
354
|
-
info["media_type"] = asset_info.media_type
|
|
355
|
-
|
|
356
366
|
# https://github.com/stac-extensions/file
|
|
357
367
|
if head := extras.get("file:header_size"):
|
|
358
368
|
info["env"] = {"GDAL_INGESTED_BYTES_AT_OPEN": head}
|
|
359
369
|
|
|
360
370
|
# https://github.com/stac-extensions/raster
|
|
361
|
-
if extras.get("raster:bands") and not
|
|
362
|
-
bands = extras.get("raster:bands")
|
|
371
|
+
if (bands := extras.get("raster:bands", [])) and not asset_modified:
|
|
363
372
|
stats = [
|
|
364
373
|
(b["statistics"]["minimum"], b["statistics"]["maximum"])
|
|
365
374
|
for b in bands
|