Skip to content

Commit c976bd7

Browse files
authored
Return 204 for tiles that are within the tile matrix set limits (#1959)
1 parent 17d1a6f commit c976bd7

File tree

6 files changed

+72
-4
lines changed

6 files changed

+72
-4
lines changed

pygeoapi/api/tiles.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ def get_collection_tiles(api: API, request: APIRequest,
199199
return headers, HTTPStatus.OK, to_json(tiles, api.pretty_print)
200200

201201

202-
# TODO: no test for this function?
203202
def get_collection_tiles_data(
204203
api: API, request: APIRequest,
205204
dataset=None, matrix_id=None,
@@ -247,7 +246,7 @@ def get_collection_tiles_data(
247246
if content is None:
248247
msg = 'identifier not found'
249248
return api.get_exception(
250-
HTTPStatus.NOT_FOUND, headers, format_, 'NotFound', msg)
249+
HTTPStatus.NO_CONTENT, headers, format_, 'NocContent', msg)
251250
else:
252251
return headers, HTTPStatus.OK, content
253252

@@ -444,7 +443,6 @@ def tilematrixset(api: API,
444443

445444
return headers, HTTPStatus.OK, to_json(tms, api.pretty_print)
446445

447-
448446
def get_oas_30(cfg: dict, locale: str) -> tuple[list[dict[str, str]], dict[str, dict]]: # noqa
449447
"""
450448
Get OpenAPI fragments

pygeoapi/provider/base_mvt.py

+42
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,45 @@ def get_tms_links(self):
248248
]
249249
}
250250
return links
251+
252+
def get_tilematrixset(self, tileMatrixSetId):
253+
"""
254+
Get tilematrixset
255+
256+
:param tileMatrixSetId: tilematrixsetid str
257+
258+
:returns: tilematrixset enum object
259+
"""
260+
261+
enums = [e.value for e in TileMatrixSetEnum]
262+
enum = None
263+
264+
try:
265+
for e in enums:
266+
if tileMatrixSetId == e.tileMatrixSet:
267+
enum = e
268+
if not enum:
269+
raise ValueError('could not find this tilematrixset')
270+
return enum
271+
272+
except ValueError as err:
273+
LOGGER.error(err)
274+
275+
def is_in_limits(self, tilematrixset, z, x, y):
276+
"""
277+
Is within the limits of the tilematrixset
278+
279+
:param z: tilematrix
280+
:param x: x
281+
:param y: y
282+
283+
:returns: wether this tile is within the tile matrix
284+
set limits (Boolean)
285+
"""
286+
287+
try:
288+
if int(x) < tilematrixset.tileMatrices[int(z)]['matrixWidth'] and int(y) < tilematrixset.tileMatrices[int(z)]['matrixHeight']: # noqa
289+
return True
290+
return False
291+
except ValueError as err:
292+
LOGGER.error(err)

pygeoapi/provider/mvt_elastic.py

+2
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ def get_tiles(self, layer=None, tileset=None,
179179
resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{url_query}', json=data) # noqa
180180

181181
if resp.status_code == 404:
182+
if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa
183+
return None
182184
raise ProviderTileNotFoundError
183185

184186
resp.raise_for_status()

pygeoapi/provider/mvt_proxy.py

+2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ def get_tiles(self, layer=None, tileset=None,
175175
resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{url_query}') # noqa
176176

177177
if resp.status_code == 404:
178+
if (self.is_in_limits(self.get_tilematrixset(tileset), z, x, y)): # noqa
179+
return None
178180
raise ProviderTileNotFoundError
179181

180182
resp.raise_for_status()

pygeoapi/provider/mvt_tippecanoe.py

+4
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ def get_tiles_from_url(self, layer=None, tileset=None,
188188
resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{extension}') # noqa
189189

190190
if resp.status_code == 404:
191+
if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa
192+
return None
191193
raise ProviderTileNotFoundError
192194

193195
resp.raise_for_status()
@@ -218,6 +220,8 @@ def get_tiles_from_disk(self, layer=None, tileset=None,
218220
with open(service_url_path, mode='rb') as tile:
219221
return tile.read()
220222
except FileNotFoundError as err:
223+
if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa
224+
return None
221225
raise ProviderTileNotFoundError(err)
222226

223227
def get_tiles(self, layer=None, tileset=None,

tests/api/test_tiles.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#
88
# Copyright (c) 2024 Tom Kralidis
99
# Copyright (c) 2022 John A Stevenson and Colin Blackburn
10+
# Copyright (c) 2025 Joana Simoes
1011
#
1112
# Permission is hereby granted, free of charge, to any person
1213
# obtaining a copy of this software and associated documentation
@@ -39,7 +40,8 @@
3940
from pygeoapi.api import FORMAT_TYPES, F_HTML
4041
from pygeoapi.api.tiles import (
4142
get_collection_tiles, tilematrixset,
42-
tilematrixsets, get_collection_tiles_metadata
43+
tilematrixsets, get_collection_tiles_metadata,
44+
get_collection_tiles_data
4345
)
4446
from pygeoapi.models.provider.base import TileMatrixSetEnum
4547

@@ -65,6 +67,24 @@ def test_get_collection_tiles(config, api_):
6567
assert len(content['tilesets']) > 0
6668

6769

70+
def test_get_collection_tiles_data(config, api_):
71+
req = mock_api_request({'f': 'mvt'})
72+
rsp_headers, code, response = get_collection_tiles_data(
73+
api_, req, 'naturalearth/lakes',
74+
matrix_id='WebMercatorQuad', z_idx=0, x_idx=0, y_idx=0)
75+
assert code == HTTPStatus.OK
76+
77+
rsp_headers, code, response = get_collection_tiles_data(
78+
api_, req, 'naturalearth/lakes',
79+
matrix_id='WebMercatorQuad', z_idx=5, x_idx=15, y_idx=16)
80+
assert code == HTTPStatus.NO_CONTENT
81+
82+
rsp_headers, code, response = get_collection_tiles_data(
83+
api_, req, 'naturalearth/lakes',
84+
matrix_id='WebMercatorQuad', z_idx=0, x_idx=1, y_idx=1)
85+
assert code == HTTPStatus.NOT_FOUND
86+
87+
6888
def test_tilematrixsets(config, api_):
6989
req = mock_api_request()
7090
rsp_headers, code, response = tilematrixsets(api_, req)

0 commit comments

Comments
 (0)