Skip to content

Commit dc9209a

Browse files
remove deprecated dependencies and fixes (#1141)
1 parent 0a6e9b4 commit dc9209a

File tree

13 files changed

+177
-153
lines changed

13 files changed

+177
-153
lines changed

CHANGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
### titiler.core
1414

15+
* remove deprecated `ColorFormulaParams` and `RescalingParams` dependencies **breaking change**
16+
17+
* remove deprecated `DefaultDependency` dict-unpacking feature **breaking change**
18+
1519
* add `min`, `max`, `mean`, `median`, `std` and `var` algorithms
1620

1721
* Fix TerrainRGB algorithm and param user-controlled nodata-height (@jo-chemla, https://github.com/developmentseed/titiler/pull/1116)
@@ -94,6 +98,11 @@
9498
)
9599
```
96100

101+
### titiler.extensions
102+
103+
* update `wms` extension to remove usage of `ColorFormulaParams` and `RescalingParams` dependencies
104+
* update `render` extension to better validate query-parameters from render expression
105+
97106
### titiler.xarray
98107

99108
* update `rio-tiler` requirement to `>=7.6.1`

docs/src/examples/code/tiler_with_auth.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ app/models.py
4343
4444
"""
4545

46-
from datetime import datetime, timedelta
46+
from datetime import datetime, timedelta, timezone
4747
from typing import List, Optional
4848

4949
from jose import jwt
@@ -67,7 +67,7 @@ class AccessToken(BaseModel):
6767
@validator("iat", pre=True, always=True)
6868
def set_creation_time(cls, v) -> datetime:
6969
"""Set token creation time (iat)."""
70-
return datetime.utcnow()
70+
return datetime.now(timezone.UTC)
7171

7272
@validator("exp", always=True)
7373
def set_expiration_time(cls, v, values) -> datetime:

docs/src/user_guide/rendering.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,5 @@ giving a possible range of 0 to 255 or 0 to 65,536, so Titiler will use these ra
130130
For certain datasets (e.g. DEMs) this default behaviour can make the image seem washed out (or even entirely one color),
131131
so if you see this happen look into rescaling your images to something that makes sense for your data.
132132

133-
It is also possible to add a [rescaling dependency](../api/titiler/core/dependencies/#rescalingparams) to automatically apply
133+
It is also possible to add a [rescaling dependency](../api/titiler/core/dependencies/#ImageRenderingParams) to automatically apply
134134
a default rescale.

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Dict
44
from unittest.mock import patch
55

6+
import pytest
67
from rasterio.io import MemoryFile
78

89
from ..conftest import mock_rasterio_open, mock_RequestGet
@@ -36,7 +37,9 @@ def test_info(httpx, rio, app):
3637
body = response.json()
3738
assert body["B01"]
3839

39-
response = app.get("/stac/info?url=https://myurl.com/item.json")
40+
# no assets
41+
with pytest.warns(UserWarning):
42+
response = app.get("/stac/info?url=https://myurl.com/item.json")
4043
assert response.status_code == 200
4144
body = response.json()
4245
assert body["B01"]

src/titiler/core/tests/test_dependencies.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import json
44
from dataclasses import dataclass
5-
from typing import Literal
5+
from typing import Literal, Optional
66

77
import pytest
88
from fastapi import Depends, FastAPI, Path
@@ -147,10 +147,11 @@ def test_default():
147147

148148
@dataclass
149149
class dep(dependencies.DefaultDependency):
150-
v: int
150+
v: Optional[int] = None
151151

152-
# make sure we can unpack the class
153-
assert dict(**dep(v=1)) == {"v": 1}
152+
assert dep(v=1).as_dict() == {"v": 1}
153+
assert dep().as_dict() == {}
154+
assert dep().as_dict(exclude_none=False) == {"v": None}
154155
assert dep(v=1).v == 1
155156

156157

src/titiler/core/tests/test_factories.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from rasterio.crs import CRS
2424
from rasterio.io import MemoryFile
2525
from rio_tiler.colormap import cmap as default_cmap
26-
from rio_tiler.errors import NoOverviewWarning
26+
from rio_tiler.errors import InvalidDatatypeWarning, NoOverviewWarning
2727
from rio_tiler.io import BaseReader, MultiBandReader, Reader, STACReader
2828
from starlette.requests import Request
2929
from starlette.testclient import TestClient
@@ -279,7 +279,7 @@ def test_TilerFactory():
279279
assert meta["driver"] == "WMTS"
280280
assert meta["crs"] == "EPSG:3857"
281281
root = ET.fromstring(response.content)
282-
assert root
282+
assert root is not None
283283

284284
response = client.get(
285285
f"/WebMercatorQuad/WMTSCapabilities.xml?url={DATA_DIR}/cog.tif&bdix=1&rescale=0,1000"
@@ -290,7 +290,7 @@ def test_TilerFactory():
290290
assert meta["driver"] == "WMTS"
291291
assert meta["crs"] == "EPSG:3857"
292292
root = ET.fromstring(response.content)
293-
assert root
293+
assert root is not None
294294

295295
response = client.get(
296296
f"/WorldCRS84Quad/WMTSCapabilities.xml?url={DATA_DIR}/cog.tif&minzoom=5&maxzoom=12"
@@ -301,7 +301,7 @@ def test_TilerFactory():
301301
assert meta["driver"] == "WMTS"
302302
assert str(meta["crs"]) == "OGC:CRS84"
303303
root = ET.fromstring(response.content)
304-
assert root
304+
assert root is not None
305305

306306
response = client.get(f"/bounds?url={DATA_DIR}/cog.tif")
307307
assert response.status_code == 200
@@ -321,7 +321,9 @@ def test_TilerFactory():
321321
assert "bbox" in response.json()
322322
assert response.json()["geometry"]["type"] == "Polygon"
323323

324-
response = client.get(f"/info.geojson?url={DATA_DIR}/cog_dateline.tif")
324+
# BBOX crossing the Antimeridian
325+
with pytest.warns(UserWarning):
326+
response = client.get(f"/info.geojson?url={DATA_DIR}/cog_dateline.tif")
325327
assert response.status_code == 200
326328
assert response.headers["content-type"] == "application/geo+json"
327329
assert response.json()["type"] == "Feature"
@@ -415,9 +417,10 @@ def test_TilerFactory():
415417
assert meta["dtype"] == "uint16"
416418
assert meta["count"] == 2
417419

418-
response = client.post(
419-
f"/feature/100x100.jpeg?url={DATA_DIR}/cog.tif", json=feature
420-
)
420+
with pytest.warns(InvalidDatatypeWarning):
421+
response = client.post(
422+
f"/feature/100x100.jpeg?url={DATA_DIR}/cog.tif", json=feature
423+
)
421424
assert response.status_code == 200
422425
assert response.headers["content-type"] == "image/jpeg"
423426
meta = parse_img(response.content)
@@ -785,9 +788,11 @@ def test_MultiBaseTilerFactory(rio):
785788
assert len(response.json()["bounds"]) == 4
786789
assert response.json()["crs"]
787790

788-
response = client.get(f"/info?url={DATA_DIR}/item.json")
789-
assert response.status_code == 200
790-
assert len(response.json()) == 2
791+
# no assets
792+
with pytest.warns(UserWarning):
793+
response = client.get(f"/info?url={DATA_DIR}/item.json")
794+
assert response.status_code == 200
795+
assert len(response.json()) == 2
791796

792797
response = client.get(f"/info?url={DATA_DIR}/item.json&assets=B01&assets=B09")
793798
assert response.status_code == 200
@@ -1169,7 +1174,9 @@ def test_MultiBandTilerFactory():
11691174
assert response.json() == ["B01", "B09"]
11701175

11711176
# default bands
1172-
response = client.get(f"/info?directory={DATA_DIR}")
1177+
# no bands
1178+
with pytest.warns(UserWarning):
1179+
response = client.get(f"/info?directory={DATA_DIR}")
11731180
assert response.json()["band_metadata"] == [["B01", {}], ["B09", {}]]
11741181

11751182
response = client.get(f"/info?directory={DATA_DIR}&bands=B01")
@@ -1626,7 +1633,8 @@ def test_TilerFactory_WithGdalEnv():
16261633
app.include_router(router)
16271634
client = TestClient(app)
16281635

1629-
response = client.get(f"/info?url={DATA_DIR}/non_cog.tif")
1636+
with pytest.warns(NoOverviewWarning):
1637+
response = client.get(f"/info?url={DATA_DIR}/non_cog.tif")
16301638
assert not response.json()["overviews"]
16311639

16321640
router = TilerFactory(

src/titiler/core/tests/test_utils.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import pytest
44

5-
from titiler.core.dependencies import BidxParams
5+
from titiler.core.dependencies import AssetsBidxExprParams, BidxParams
66
from titiler.core.resources.enums import MediaType
77
from titiler.core.utils import (
88
accept_media_type,
9+
check_query_params,
910
deserialize_query_params,
11+
extract_query_params,
1012
get_dependency_query_params,
1113
)
1214

@@ -62,7 +64,6 @@ def test_deserialize_query_params():
6264
res, err = deserialize_query_params(
6365
dependency=BidxParams, params={"bidx": ["invalid type"]}
6466
)
65-
print(res)
6667
assert res == BidxParams(indexes=None)
6768
assert err
6869

@@ -74,6 +75,67 @@ def test_deserialize_query_params():
7475
assert not err
7576

7677

78+
def test_extract_query_params():
79+
"""Test extract_query_params."""
80+
# invalid
81+
qs, err = extract_query_params(
82+
dependencies=[BidxParams],
83+
params={"bidx": ["invalid type"]},
84+
)
85+
assert qs == {}
86+
assert len(err)
87+
88+
qs, err = extract_query_params(
89+
dependencies=[BidxParams],
90+
params={"bidx": [1]},
91+
)
92+
assert qs == {"indexes": [1]}
93+
assert len(err) == 0
94+
95+
qs, err = extract_query_params(
96+
dependencies=[BidxParams],
97+
params={"bidx": 1},
98+
)
99+
assert qs == {"indexes": [1]}
100+
assert len(err) == 0
101+
102+
qs, err = extract_query_params(
103+
dependencies=[BidxParams],
104+
params={"not_in_dep": "no error, no value", "bidx": [1]},
105+
)
106+
assert qs == {"indexes": [1]}
107+
assert len(err) == 0
108+
109+
110+
def test_check_query_params():
111+
"""Test check_query_params."""
112+
# invalid bidx value
113+
assert (
114+
check_query_params(
115+
dependencies=[BidxParams],
116+
params={"bidx": ["invalid type"]},
117+
)
118+
is False
119+
)
120+
121+
# assets is required
122+
assert (
123+
check_query_params(
124+
dependencies=[AssetsBidxExprParams],
125+
params={},
126+
)
127+
is False
128+
)
129+
130+
assert (
131+
check_query_params(
132+
dependencies=[AssetsBidxExprParams, BidxParams],
133+
params={"assets": "yo", "bidx": 1},
134+
)
135+
is True
136+
)
137+
138+
77139
@pytest.mark.parametrize(
78140
"media,accept,expected",
79141
[

src/titiler/core/titiler/core/dependencies.py

Lines changed: 10 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,6 @@ def DatasetPathParams(url: Annotated[str, Query(description="Dataset URL")]) ->
6767
class DefaultDependency:
6868
"""Dataclass with dict unpacking"""
6969

70-
def keys(self):
71-
"""Return Keys."""
72-
warnings.warn(
73-
"Dict unpacking will be removed for `DefaultDependency` in titiler 0.19.0",
74-
DeprecationWarning,
75-
stacklevel=1,
76-
)
77-
return self.__dict__.keys()
78-
79-
def __getitem__(self, key):
80-
"""Return value."""
81-
return self.__dict__[key]
82-
8370
def as_dict(self, exclude_none: bool = True) -> Dict:
8471
"""Transform dataclass to dict."""
8572
if exclude_none:
@@ -437,7 +424,7 @@ def __post_init__(self):
437424

438425

439426
@dataclass
440-
class ImageRenderingParams(DefaultDependency):
427+
class RenderingParams(DefaultDependency):
441428
"""Image Rendering options."""
442429

443430
rescale: Annotated[
@@ -457,14 +444,6 @@ class ImageRenderingParams(DefaultDependency):
457444
),
458445
] = None
459446

460-
add_mask: Annotated[
461-
Optional[bool],
462-
Query(
463-
alias="return_mask",
464-
description="Add mask to the output data. Defaults to `True`",
465-
),
466-
] = None
467-
468447
def __post_init__(self):
469448
"""Post Init."""
470449
if self.rescale:
@@ -484,40 +463,17 @@ def __post_init__(self):
484463
self.rescale: RescaleType = rescale_array
485464

486465

487-
def RescalingParams(
488-
rescale: Annotated[
489-
Optional[List[str]],
466+
@dataclass
467+
class ImageRenderingParams(RenderingParams):
468+
"""Image Rendering options."""
469+
470+
add_mask: Annotated[
471+
Optional[bool],
490472
Query(
491-
title="Min/Max data Rescaling",
492-
description="comma (',') delimited Min,Max range. Can set multiple time for multiple bands.",
493-
examples=["0,2000", "0,1000", "0,10000"], # band 1 # band 2 # band 3
473+
alias="return_mask",
474+
description="Add mask to the output data. Defaults to `True`",
494475
),
495-
] = None,
496-
) -> Optional[RescaleType]:
497-
"""Min/Max data Rescaling"""
498-
warnings.warn(
499-
"RescalingParams is deprecated and set to be removed in 0.20",
500-
DeprecationWarning,
501-
stacklevel=1,
502-
)
503-
if rescale:
504-
rescale_array = []
505-
for r in rescale:
506-
parsed = tuple(
507-
map(
508-
float,
509-
r.replace(" ", "").replace("[", "").replace("]", "").split(","),
510-
)
511-
)
512-
assert (
513-
len(parsed) == 2
514-
), f"Invalid rescale values: {rescale}, should be of form ['min,max', 'min,max'] or [[min,max], [min, max]]"
515-
516-
rescale_array.append(parsed)
517-
518-
return rescale_array
519-
520-
return None
476+
] = None
521477

522478

523479
@dataclass
@@ -685,24 +641,6 @@ def BufferParams(
685641
return buffer
686642

687643

688-
def ColorFormulaParams(
689-
color_formula: Annotated[
690-
Optional[str],
691-
Query(
692-
title="Color Formula",
693-
description="rio-color formula (info: https://github.com/mapbox/rio-color)",
694-
),
695-
] = None,
696-
) -> Optional[str]:
697-
"""ColorFormula Parameter."""
698-
warnings.warn(
699-
"ColorFormulaParams is deprecated and set to be removed in 0.20",
700-
DeprecationWarning,
701-
stacklevel=1,
702-
)
703-
return color_formula
704-
705-
706644
@dataclass
707645
class TileParams(DefaultDependency):
708646
"""Tile options."""

0 commit comments

Comments
 (0)