Skip to content

Commit 5bb78c2

Browse files
update/fix type hints (#1287)
* update/fix type for titiler.core * update/fix type for titiler.extensions * update/fix type for titiler.xarray * update/fix type for titiler.mosaic * update/fix type for titiler.application * update changelog * run mypy in CI * update type hints for tests
1 parent ffe2105 commit 5bb78c2

44 files changed

Lines changed: 638 additions & 676 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,11 @@ jobs:
6262
run: |
6363
uv run pytest src/titiler/application --cov=titiler.application --cov-report=xml --cov-append --cov-report=term-missing
6464
65-
- name: run pre-commit
65+
- name: run pre-commit and mypy
6666
if: ${{ matrix.python-version == env.LATEST_PY_VERSION }}
6767
run: |
6868
uv run pre-commit run --all-files
69+
uv run --with mypy --with types-attrs --with types-simplejson mypy -p titiler.core -p titiler.extensions -p titiler.xarray -p titiler.application -p titiler.mosaic --ignore-missing-imports
6970
7071
- name: Upload Results
7172
if: ${{ matrix.python-version == env.LATEST_PY_VERSION }}

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* remove `/{tileMatrixSetId}/WMTSCapabilities.xml` endpoints from factories **breaking change**
1010
* add python 3.14 support
1111
* add `linux/arm64` docker image
12+
* update/fix type hints
1213

1314
### titiler.core
1415

src/titiler/application/titiler/application/main.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import json
44
import logging
55
from logging import config as log_config
6-
from typing import Annotated, Literal, Optional
6+
from typing import Annotated, Literal
77

88
import jinja2
99
import rasterio
@@ -58,7 +58,7 @@
5858
api_settings = ApiSettings()
5959

6060
# custom template directory
61-
templates_location = (
61+
templates_location: list[jinja2.BaseLoader] = (
6262
[jinja2.FileSystemLoader(api_settings.template_directory)]
6363
if api_settings.template_directory
6464
else []
@@ -173,7 +173,7 @@ def validate_access_token(access_token: str = Security(api_key_query)):
173173
# Mosaic endpoints
174174
if not api_settings.disable_mosaic:
175175
mosaic = MosaicTilerFactory(
176-
backend=MosaicJSONBackend,
176+
backend=MosaicJSONBackend, # type: ignore
177177
router_prefix="/mosaicjson",
178178
extensions=[
179179
MosaicJSONExtension(),
@@ -365,7 +365,7 @@ def application_health_check():
365365
def landing(
366366
request: Request,
367367
f: Annotated[
368-
Optional[Literal["html", "json"]],
368+
Literal["html", "json"] | None,
369369
Query(
370370
description="Response MediaType. Defaults to endpoint's default or value defined in `accept` header."
371371
),
@@ -471,7 +471,7 @@ def landing(
471471
def conformance(
472472
request: Request,
473473
f: Annotated[
474-
Optional[Literal["html", "json"]],
474+
Literal["html", "json"] | None,
475475
Query(
476476
description="Response MediaType. Defaults to endpoint's default or value defined in `accept` header."
477477
),

src/titiler/application/titiler/application/py.typed

Whitespace-only changes.

src/titiler/application/titiler/application/settings.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"""Titiler API settings."""
22

3-
from typing import Optional
4-
53
from pydantic import field_validator
64
from pydantic_settings import BaseSettings, SettingsConfigDict
75

@@ -27,7 +25,7 @@ class ApiSettings(BaseSettings):
2725
root_path: str = ""
2826
debug: bool = False
2927

30-
template_directory: Optional[str] = None
28+
template_directory: str | None = None
3129

3230
disable_cog: bool = False
3331
disable_stac: bool = False
@@ -38,7 +36,7 @@ class ApiSettings(BaseSettings):
3836
telemetry_enabled: bool = False
3937

4038
# an API key required to access any endpoint, passed via the ?access_token= query parameter
41-
global_access_token: Optional[str] = None
39+
global_access_token: str | None = None
4240

4341
model_config = SettingsConfigDict(
4442
env_prefix="TITILER_API_", env_file=".env", extra="ignore"

src/titiler/core/tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""``pytest`` configuration."""
22

33
import os
4-
from typing import Any, Dict
4+
from typing import Any
55

66
import pytest
77
import rasterio
@@ -21,7 +21,7 @@ def set_env(monkeypatch):
2121
monkeypatch.setenv("AWS_CONFIG_FILE", "/tmp/noconfigheere")
2222

2323

24-
def parse_img(content: bytes) -> Dict[Any, Any]:
24+
def parse_img(content: bytes) -> dict[Any, Any]:
2525
"""Read tile image and return metadata."""
2626
with MemoryFile(content) as mem:
2727
with mem.open() as dst:

src/titiler/core/tests/test_CustomRender.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Test TiTiler Custom Render Params."""
22

33
from dataclasses import dataclass
4-
from typing import Optional, Union
54

65
import numpy
76
from fastapi import FastAPI, Query
@@ -17,12 +16,12 @@
1716
class CustomRenderParams(ImageRenderingParams):
1817
"""Custom renderparams class."""
1918

20-
nodata: Optional[Union[str, int, float]] = Query(
19+
nodata: str | int | float | None = Query(
2120
None,
2221
title="Tiff Ouptut Nodata value",
2322
alias="output_nodata",
2423
)
25-
compress: Optional[str] = Query(
24+
compress: str | None = Query(
2625
None,
2726
title="Tiff compression schema",
2827
alias="output_compression",

src/titiler/core/tests/test_case_middleware.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Test titiler.core.middleware.LowerCaseQueryStringMiddleware."""
22

3-
from typing import Annotated, List
3+
from typing import Annotated
44

55
from fastapi import FastAPI, Query
66
from starlette.testclient import TestClient
@@ -33,7 +33,7 @@ def test_lowercase_middleware_multiple_values():
3333
app = FastAPI()
3434

3535
@app.get("/route1")
36-
async def route1(value: Annotated[List[str], Query()]):
36+
async def route1(value: Annotated[list[str], Query()]):
3737
"""route1."""
3838
return {"value": value}
3939

@@ -53,7 +53,7 @@ def test_lowercase_middleware_url_with_query_parameters():
5353
app = FastAPI()
5454

5555
@app.get("/route1")
56-
async def route1(url: List[str] = Query(...)):
56+
async def route1(url: list[str] = Query(...)):
5757
"""route1."""
5858
return {"url": url}
5959

src/titiler/core/tests/test_dependencies.py

Lines changed: 2 additions & 2 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 Annotated, Literal, Optional
5+
from typing import Annotated, Literal
66

77
import pytest
88
from fastapi import Depends, FastAPI, Path
@@ -146,7 +146,7 @@ def test_default():
146146

147147
@dataclass
148148
class dep(dependencies.DefaultDependency):
149-
v: Optional[int] = None
149+
v: int | None = None
150150

151151
assert dep(v=1).as_dict() == {"v": 1}
152152
assert dep().as_dict() == {}

src/titiler/core/titiler/core/algorithm/__init__.py

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

33
import json
44
from copy import copy
5-
from typing import Annotated, Dict, List, Literal, Optional, Type
5+
from typing import Annotated, Literal
66

77
import attr
88
from fastapi import HTTPException, Query
@@ -19,7 +19,7 @@
1919
from titiler.core.algorithm.math import _Max, _Mean, _Median, _Min, _Std, _Sum, _Var
2020
from titiler.core.algorithm.ops import CastToInt, Ceil, Floor
2121

22-
default_algorithms: Dict[str, Type[BaseAlgorithm]] = {
22+
default_algorithms: dict[str, type[BaseAlgorithm]] = {
2323
"hillshade": HillShade,
2424
"slope": Slope,
2525
"contours": Contours,
@@ -45,30 +45,30 @@
4545
class Algorithms:
4646
"""Algorithms."""
4747

48-
data: Dict[str, Type[BaseAlgorithm]] = attr.ib()
48+
data: dict[str, type[BaseAlgorithm]] = attr.ib(factory=dict)
4949

50-
def get(self, name: str) -> BaseAlgorithm:
50+
def get(self, name: str) -> type[BaseAlgorithm]:
5151
"""Fetch a TMS."""
5252
if name not in self.data:
5353
raise KeyError(f"Invalid name: {name}")
5454

5555
return self.data[name]
5656

57-
def list(self) -> List[str]:
57+
def list(self) -> list[str]:
5858
"""List registered Algorithm."""
5959
return list(self.data.keys())
6060

6161
def register(
6262
self,
63-
algorithms: Dict[str, BaseAlgorithm],
63+
algorithms: dict[str, BaseAlgorithm],
6464
overwrite: bool = False,
6565
) -> "Algorithms":
6666
"""Register Algorithm(s)."""
6767
for name, _algo in algorithms.items():
6868
if name in self.data and not overwrite:
6969
raise Exception(f"{name} is already a registered. Use overwrite=True.")
7070

71-
return Algorithms({**self.data, **algorithms})
71+
return Algorithms({**self.data, **algorithms}) # type: ignore [dict-item]
7272

7373
@property
7474
def dependency(self):
@@ -80,10 +80,10 @@ def post_process(
8080
Query(description="Algorithm name"),
8181
] = None,
8282
algorithm_params: Annotated[
83-
Optional[str],
83+
str | None,
8484
Query(description="Algorithm parameter"),
8585
] = None,
86-
) -> Optional[BaseAlgorithm]:
86+
) -> BaseAlgorithm | None:
8787
"""Data Post-Processing options."""
8888
kwargs = json.loads(algorithm_params) if algorithm_params else {}
8989
if algorithm:

0 commit comments

Comments
 (0)