33from typing import Annotated , Optional
44from urllib .parse import quote_plus , urljoin
55
6+ import jinja2
67import fastapi
78import pystac
8- from fastapi import Body , Depends , Query , Request , Response
9+ from pydantic import Field
10+ from fastapi import Body , Depends , Query , Request , Response , Path
911from fastapi .templating import Jinja2Templates
1012from geojson_pydantic .features import Feature
1113from html_sanitizer .sanitizer import Sanitizer
1214from starlette .responses import HTMLResponse
1315from titiler .core .dependencies import CoordCRSParams , DstCRSParams
1416from titiler .core .factory import MultiBaseTilerFactory , img_endpoint_params
1517from titiler .core .resources .enums import ImageType
18+ from titiler .core .models .mapbox import TileJSON
1619from titiler .pgstac .dependencies import get_stac_item
1720
1821from pccommon .config import get_render_config
2225from pctiler .endpoints .dependencies import get_endpoint_function
2326from pctiler .reader import ItemSTACReader , ReaderParams
2427
25- try :
26- from importlib .resources import files as resources_files # type: ignore
27- except ImportError :
28- # Try backported to PY<39 `importlib_resources`.
29- from importlib_resources import files as resources_files # type: ignore
30-
3128logger = logging .getLogger (__name__ )
3229
3330
@@ -79,11 +76,10 @@ async def _fetch() -> dict:
7976 return pystac .Item .from_dict (_item )
8077
8178
82- # TODO: mypy fails in python 3.9, we need to find a proper way to do this
83- templates = Jinja2Templates (
84- directory = str (resources_files (__package__ ) / "templates" ) # type: ignore
79+ jinja2_env = jinja2 .Environment (
80+ loader = jinja2 .ChoiceLoader ([jinja2 .PackageLoader (__package__ , "templates" )])
8581)
86-
82+ templates = Jinja2Templates ( env = jinja2_env )
8783
8884pc_tile_factory = MultiBaseTilerFactory (
8985 reader = ItemSTACReader ,
@@ -135,17 +131,20 @@ def map(
135131 },
136132 )
137133
138-
134+ # crop/feature endpoint compat with titiler<0.15 (`/crop` was renamed `/feature`)
139135@pc_tile_factory .router .post (
140136 r"/crop" ,
137+ operation_id = f"{ self .operation_prefix } postDataForGeoJSONCrop" ,
141138 ** img_endpoint_params ,
142139)
143140@pc_tile_factory .router .post (
144141 r"/crop.{format}" ,
142+ operation_id = f"{ self .operation_prefix } postDataForGeoJSONWithFormatCrop" ,
145143 ** img_endpoint_params ,
146144)
147145@pc_tile_factory .router .post (
148146 r"/crop/{width}x{height}.{format}" ,
147+ operation_id = f"{ self .operation_prefix } postDataForGeoJSONWithSizesAndFormatCrop" ,
149148 ** img_endpoint_params ,
150149)
151150def geojson_crop ( # type: ignore
@@ -155,7 +154,9 @@ def geojson_crop( # type: ignore
155154 ],
156155 format : Annotated [
157156 ImageType ,
158- "Default will be automatically defined if the output image needs a mask (png) or not (jpeg)." , # noqa: E501,F722
157+ Field (
158+ description = "Default will be automatically defined if the output image needs a mask (png) or not (jpeg)."
159+ ),
159160 ] = None , # type: ignore[assignment]
160161 src_path = Depends (pc_tile_factory .path_dependency ),
161162 coord_crs = Depends (CoordCRSParams ),
@@ -164,14 +165,6 @@ def geojson_crop( # type: ignore
164165 dataset_params = Depends (pc_tile_factory .dataset_dependency ),
165166 image_params = Depends (pc_tile_factory .img_part_dependency ),
166167 post_process = Depends (pc_tile_factory .process_dependency ),
167- rescale = Depends (pc_tile_factory .rescale_dependency ),
168- color_formula : Annotated [
169- Optional [str ],
170- Query (
171- title = "Color Formula" , # noqa: F722
172- description = "rio-color formula (info: https://github.com/mapbox/rio-color)" , # noqa: E501,F722
173- ),
174- ] = None ,
175168 colormap = Depends (pc_tile_factory .colormap_dependency ),
176169 render_params = Depends (pc_tile_factory .render_dependency ),
177170 reader_params = Depends (pc_tile_factory .reader_dependency ),
@@ -191,11 +184,159 @@ def geojson_crop( # type: ignore
191184 dataset_params = dataset_params ,
192185 image_params = image_params ,
193186 post_process = post_process ,
194- rescale = rescale ,
195- color_formula = color_formula ,
196187 colormap = colormap ,
197188 render_params = render_params ,
198189 reader_params = reader_params ,
199190 env = env ,
200191 )
201192 return result
193+
194+
195+ # /tiles endpoint compat with titiler<0.15, Optional `tileMatrixSetId`
196+ @pc_tile_factory .router .get (
197+ "/tiles/{z}/{x}/{y}" ,
198+ operation_id = f"{ pc_tile_factory .operation_prefix } getWebMercatorQuadTile" ,
199+ ** img_endpoint_params ,
200+ )
201+ @pc_tile_factory .router .get (
202+ "/tiles/{z}/{x}/{y}.{format}" ,
203+ operation_id = f"{ pc_tile_factory .operation_prefix } getWebMercatorQuadTileWithFormat" ,
204+ ** img_endpoint_params ,
205+ )
206+ @pc_tile_factory .router .get (
207+ "/tiles/{z}/{x}/{y}@{scale}x" ,
208+ operation_id = f"{ pc_tile_factory .operation_prefix } getWebMercatorQuadTileWithScale" ,
209+ ** img_endpoint_params ,
210+ )
211+ @pc_tile_factory .router .get (
212+ "/tiles/{z}/{x}/{y}@{scale}x.{format}" ,
213+ operation_id = f"{ pc_tile_factory .operation_prefix } getWebMercatorQuadTileWithFormatAndScale" ,
214+ ** img_endpoint_params ,
215+ )
216+ def tile_compat (
217+ request : fastapi .Request ,
218+ z : Annotated [
219+ int ,
220+ Path (
221+ description = "Identifier (Z) selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile." ,
222+ ),
223+ ],
224+ x : Annotated [
225+ int ,
226+ Path (
227+ description = "Column (X) index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix." ,
228+ ),
229+ ],
230+ y : Annotated [
231+ int ,
232+ Path (
233+ description = "Row (Y) index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix." ,
234+ ),
235+ ],
236+ scale : Annotated [
237+ int ,
238+ Field (
239+ gt = 0 , le = 4 , description = "Tile size scale. 1=256x256, 2=512x512..."
240+ ),
241+ ] = 1 ,
242+ format : Annotated [
243+ ImageType ,
244+ Field (
245+ description = "Default will be automatically defined if the output image needs a mask (png) or not (jpeg)."
246+ ),
247+ ] = None ,
248+ src_path = Depends (pc_tile_factory .path_dependency ),
249+ reader_params = Depends (pc_tile_factory .reader_dependency ),
250+ tile_params = Depends (pc_tile_factory .tile_dependency ),
251+ layer_params = Depends (pc_tile_factory .layer_dependency ),
252+ dataset_params = Depends (pc_tile_factory .dataset_dependency ),
253+ post_process = Depends (pc_tile_factory .process_dependency ),
254+ colormap = Depends (pc_tile_factory .colormap_dependency ),
255+ render_params = Depends (pc_tile_factory .render_dependency ),
256+ env = Depends (pc_tile_factory .environment_dependency ),
257+ ) -> Response :
258+ """tiles endpoints compat."""
259+ endpoint = get_endpoint_function (
260+ pc_tile_factory .router , path = "/tiles/{tileMatrixSetId}/{z}/{x}/{y}" , method = request .method
261+ )
262+ result = endpoint (
263+ z = z ,
264+ x = x ,
265+ y = y ,
266+ tileMatrixSetId = "WebMercatorQuad" ,
267+ scale = scale ,
268+ format = format ,
269+ src_path = src_path ,
270+ reader_params = reader_params ,
271+ tile_params = tile_params ,
272+ layer_params = layer_params ,
273+ dataset_params = dataset_params ,
274+ post_process = post_process ,
275+ colormap = colormap ,
276+ render_params = render_params ,
277+ env = env ,
278+ )
279+ return result
280+
281+
282+ # /tilejson.json endpoint compat with titiler<0.15, Optional `tileMatrixSetId`
283+ @pc_tile_factory .router .get (
284+ "/tilejson.json" ,
285+ response_model = TileJSON ,
286+ responses = {200 : {"description" : "Return a tilejson" }},
287+ response_model_exclude_none = True ,
288+ operation_id = f"{ pc_tile_factory .operation_prefix } getWebMercatorQuadTileJSON" ,
289+ )
290+ def tilejson_compat (
291+ request : fastapi .Request ,
292+ tile_format : Annotated [
293+ Optional [ImageType ],
294+ Query (
295+ description = "Default will be automatically defined if the output image needs a mask (png) or not (jpeg)." ,
296+ ),
297+ ] = None ,
298+ tile_scale : Annotated [
299+ int ,
300+ Query (
301+ gt = 0 , lt = 4 , description = "Tile size scale. 1=256x256, 2=512x512..."
302+ ),
303+ ] = 1 ,
304+ minzoom : Annotated [
305+ Optional [int ],
306+ Query (description = "Overwrite default minzoom." ),
307+ ] = None ,
308+ maxzoom : Annotated [
309+ Optional [int ],
310+ Query (description = "Overwrite default maxzoom." ),
311+ ] = None ,
312+ src_path = Depends (pc_tile_factory .path_dependency ),
313+ reader_params = Depends (pc_tile_factory .reader_dependency ),
314+ tile_params = Depends (pc_tile_factory .tile_dependency ),
315+ layer_params = Depends (pc_tile_factory .layer_dependency ),
316+ dataset_params = Depends (pc_tile_factory .dataset_dependency ),
317+ post_process = Depends (pc_tile_factory .process_dependency ),
318+ colormap = Depends (pc_tile_factory .colormap_dependency ),
319+ render_params = Depends (pc_tile_factory .render_dependency ),
320+ env = Depends (pc_tile_factory .environment_dependency ),
321+ ) -> Response :
322+ """tilejson endpoint compat."""
323+ endpoint = get_endpoint_function (
324+ pc_tile_factory .router , path = "/{tileMatrixSetId}/tilejson.json" , method = request .method
325+ )
326+ result = endpoint (
327+ tileMatrixSetId = "WebMercatorQuad" ,
328+ tile_format = tile_format ,
329+ tile_scale = tile_scale ,
330+ minzoom = minzoom ,
331+ maxzoom = maxzoom ,
332+ src_path = src_path ,
333+ reader_params = reader_params ,
334+ tile_params = tile_params ,
335+ layer_params = layer_params ,
336+ dataset_params = dataset_params ,
337+ post_process = post_process ,
338+ colormap = colormap ,
339+ render_params = render_params ,
340+ env = env ,
341+ )
342+ return result
0 commit comments