Skip to content

Commit df255c2

Browse files
update for rio-tiler 8.0 (#1272)
* update for rio-tiler 8.0 * update changelog * update extensions * update xarray * update mosaic * update mosaic and app
1 parent 820da86 commit df255c2

File tree

17 files changed

+1365
-450
lines changed

17 files changed

+1365
-450
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,6 @@ ENV/
108108
cdk.out/
109109
deployment/k8s/titiler/values-test.yaml
110110

111-
.vscode/
111+
.vscode/
112+
113+
dev_notebooks/*

CHANGES.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
11
# Release Notes
22

3+
## Unreleased
4+
5+
### Misc
6+
7+
* update rio-tiler requirement to `>=8.0,<9.0`
8+
9+
### titiler.core
10+
11+
* add `band_description` attribute to `Point` output model (returned by /point endpoints) **breaking change**
12+
13+
### titiler.extensions
14+
15+
* update rio-cogeo requirement to `7.0,<8.0`
16+
17+
### titiler.mosaic
18+
19+
* change Response model for `/point` endpoint **breaking change**
20+
21+
```python
22+
# before
23+
class Point(BaseModel):
24+
coordinates: List[float]
25+
values: List[Tuple[str, List[Optional[float]], List[str]]]
26+
27+
# now
28+
class AssetPoint(BaseModel):
29+
name: str
30+
values: list[float | None]
31+
band_names: list[str]
32+
band_descriptions: list[str] | None = None
33+
34+
class Point(BaseModel):
35+
coordinates: list[float]
36+
assets: list[AssetPoint]
37+
```
38+
339
## 0.26.0 (2025-11-25)
440

541
### titiler.xarray

pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ dev = [
4949
"s3fs>=2025.2.0",
5050
"aiohttp",
5151
"requests",
52-
"cogeo-mosaic>=8.2,<9.0",
5352
"pystac[validation]>=1.0.0,<2.0.0",
5453
"brotlipy",
5554
"boto3",
@@ -74,6 +73,12 @@ docs = [
7473
server = [
7574
"uvicorn",
7675
]
76+
notebook = [
77+
"IPython",
78+
"jupyter",
79+
"matplotlib",
80+
"folium",
81+
]
7782

7883
[project.urls]
7984
Homepage = 'https://developmentseed.org/titiler/'

src/titiler/application/tests/routes/test_mosaic.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def test_info(app):
4747
response = app.get("/mosaicjson/info", params={"url": MOSAICJSON_FILE})
4848
assert response.status_code == 200
4949
body = response.json()
50-
assert body["name"] == "mosaic" # mosaic.name is not set
5150
assert body["quadkeys"] == []
5251
assert body["mosaic_minzoom"] == 7
5352
assert body["mosaic_maxzoom"] == 9
@@ -58,7 +57,6 @@ def test_info(app):
5857
assert response.headers["content-type"] == "application/geo+json"
5958
body = response.json()
6059
assert body["geometry"]
61-
assert body["properties"]["name"] == "mosaic" # mosaic.name is not set
6260
assert body["properties"]["quadkeys"] == []
6361
assert body["properties"]["mosaic_minzoom"] == 7
6462
assert body["properties"]["mosaic_maxzoom"] == 9
@@ -95,9 +93,9 @@ def test_point(app):
9593
)
9694
assert response.status_code == 200
9795
body = response.json()
98-
assert len(body["values"]) == 1
99-
assert body["values"][0][0].endswith(".tif")
100-
assert body["values"][0][1] == [9943, 9127, 9603]
96+
assert len(body["assets"]) == 1
97+
assert body["assets"][0]["name"].endswith(".tif")
98+
assert body["assets"][0]["values"] == [9943, 9127, 9603]
10199

102100

103101
def test_tile(app):

src/titiler/core/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ dependencies = [
3535
"numpy",
3636
"pydantic~=2.0",
3737
"rasterio",
38-
"rio-tiler>=7.7,<8.0",
38+
"rio-tiler>=8.0,<9.0",
3939
"morecantile",
4040
"simplejson",
4141
"typing_extensions>=4.6.1",

src/titiler/core/tests/test_rendering.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,32 @@ def test_rendering():
8686
500: (100, 100, 100, 50),
8787
1000: (255, 255, 255, 255),
8888
}
89-
d = numpy.ma.zeros((1, 256, 256), dtype="float32") + 1
90-
d[0, 0:10, 0:10] = 500
91-
d[0, 10:20, 10:20] = 1000
89+
data = numpy.ma.zeros((1, 256, 256), dtype="float32") + 1
90+
data.mask = False
91+
92+
data[0, 0, 0] = 0
93+
data.mask[0, 0, 0] = True
94+
data[0, 1:, 1:] = 1
95+
data[0, 2:, 2:] = 500
96+
data[0, 3:, 3:] = 1000
97+
9298
content, media = render_image(
93-
ImageData(d),
99+
ImageData(data),
94100
output_format=ImageType.png,
95101
colormap=cm,
96102
)
97103
assert media == "image/png"
98104

99105
with MemoryFile(content) as mem:
100106
with mem.open() as dst:
107+
data_converted = dst.read()
101108
assert dst.count == 4
102109
assert dst.dtypes == ("uint8", "uint8", "uint8", "uint8")
103-
assert dst.read()[:, 0, 0].tolist() == [100, 100, 100, 50]
104-
assert dst.read()[:, 11, 11].tolist() == [255, 255, 255, 255]
105-
assert dst.read()[:, 30, 30].tolist() == [0, 0, 0, 0]
110+
# Masked from Original Mask | set to UINT8 (0)
111+
assert data_converted[:, 0, 0].tolist() == [0, 0, 0, 0]
112+
# masked from CMAP
113+
assert data_converted[:, 1, 1].tolist() == [0, 0, 0, 0]
114+
# Partially masked from CMAP
115+
assert data_converted[:, 2, 2].tolist() == [100, 100, 100, 50]
116+
# Non-masked from CMAP
117+
assert data_converted[:, 3, 3].tolist() == [255, 255, 255, 255]

src/titiler/core/titiler/core/factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,6 +1301,7 @@ def point(
13011301
"coordinates": [lon, lat],
13021302
"values": pts.array.tolist(),
13031303
"band_names": pts.band_names,
1304+
"band_descriptions": pts.band_descriptions,
13041305
}
13051306

13061307
############################################################################

src/titiler/core/titiler/core/models/responses.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ class Point(BaseModel):
1818
1919
"""
2020

21-
coordinates: List[float]
22-
values: List[Optional[float]]
23-
band_names: List[str]
21+
coordinates: list[float]
22+
values: list[float | None]
23+
band_names: list[str]
24+
band_descriptions: list[str] | None = None
2425

2526

2627
InfoGeoJSON = Feature[Union[Polygon, MultiPolygon], Info]

src/titiler/core/titiler/core/utils.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,16 @@ def render_image( # noqa: C901
7676
image.apply_color_formula(color_formula)
7777

7878
data, mask = image.data.copy(), image.mask.copy()
79-
datatype_range = image.dataset_statistics or (dtype_ranges[str(data.dtype)],)
79+
input_range = dtype_ranges[str(data.dtype)]
80+
output_range = image.dataset_statistics or (input_range,)
8081

8182
if colormap:
8283
data, alpha_from_cmap = apply_cmap(data, colormap)
84+
output_range = (dtype_ranges[str(data.dtype)],)
8385
# Combine both Mask from dataset and Alpha band from Colormap
84-
mask = numpy.bitwise_and(alpha_from_cmap, mask)
85-
datatype_range = (dtype_ranges[str(data.dtype)],)
86+
mask = numpy.where(
87+
mask != input_range[0], alpha_from_cmap, output_range[0][0]
88+
).astype(data.dtype)
8689

8790
# If output_format is not set, we choose between JPEG and PNG
8891
if not output_format:
@@ -105,7 +108,7 @@ def render_image( # noqa: C901
105108
InvalidDatatypeWarning,
106109
stacklevel=1,
107110
)
108-
data = rescale_array(data, mask, in_range=datatype_range)
111+
data = rescale_array(data, mask, in_range=output_range)
109112

110113
creation_options = {**kwargs, **output_format.profile}
111114
if output_format.driver == "GTiff":

src/titiler/extensions/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ dependencies = [
3434

3535
[project.optional-dependencies]
3636
cogeo = [
37-
"rio-cogeo>=5.0,<6.0",
37+
"rio-cogeo>=7.0,<8.0",
3838
]
3939
stac = [
4040
"rio-stac>=0.12,<0.13",

0 commit comments

Comments
 (0)