diff --git a/pygeoapi/api/tiles.py b/pygeoapi/api/tiles.py index d18683720..3a02db3d4 100644 --- a/pygeoapi/api/tiles.py +++ b/pygeoapi/api/tiles.py @@ -199,7 +199,6 @@ def get_collection_tiles(api: API, request: APIRequest, return headers, HTTPStatus.OK, to_json(tiles, api.pretty_print) -# TODO: no test for this function? def get_collection_tiles_data( api: API, request: APIRequest, dataset=None, matrix_id=None, @@ -247,7 +246,7 @@ def get_collection_tiles_data( if content is None: msg = 'identifier not found' return api.get_exception( - HTTPStatus.NOT_FOUND, headers, format_, 'NotFound', msg) + HTTPStatus.NO_CONTENT, headers, format_, 'NocContent', msg) else: return headers, HTTPStatus.OK, content @@ -444,7 +443,6 @@ def tilematrixset(api: API, return headers, HTTPStatus.OK, to_json(tms, api.pretty_print) - def get_oas_30(cfg: dict, locale: str) -> tuple[list[dict[str, str]], dict[str, dict]]: # noqa """ Get OpenAPI fragments diff --git a/pygeoapi/provider/base_mvt.py b/pygeoapi/provider/base_mvt.py index 5851c49de..0618909bb 100644 --- a/pygeoapi/provider/base_mvt.py +++ b/pygeoapi/provider/base_mvt.py @@ -248,3 +248,45 @@ def get_tms_links(self): ] } return links + + def get_tilematrixset(self, tileMatrixSetId): + """ + Get tilematrixset + + :param tileMatrixSetId: tilematrixsetid str + + :returns: tilematrixset enum object + """ + + enums = [e.value for e in TileMatrixSetEnum] + enum = None + + try: + for e in enums: + if tileMatrixSetId == e.tileMatrixSet: + enum = e + if not enum: + raise ValueError('could not find this tilematrixset') + return enum + + except ValueError as err: + LOGGER.error(err) + + def is_in_limits(self, tilematrixset, z, x, y): + """ + Is within the limits of the tilematrixset + + :param z: tilematrix + :param x: x + :param y: y + + :returns: wether this tile is within the tile matrix + set limits (Boolean) + """ + + try: + if int(x) < tilematrixset.tileMatrices[int(z)]['matrixWidth'] and int(y) < tilematrixset.tileMatrices[int(z)]['matrixHeight']: # noqa + return True + return False + except ValueError as err: + LOGGER.error(err) diff --git a/pygeoapi/provider/mvt_elastic.py b/pygeoapi/provider/mvt_elastic.py index 65e8af0f2..027009197 100644 --- a/pygeoapi/provider/mvt_elastic.py +++ b/pygeoapi/provider/mvt_elastic.py @@ -179,6 +179,8 @@ def get_tiles(self, layer=None, tileset=None, resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{url_query}', json=data) # noqa if resp.status_code == 404: + if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa + return None raise ProviderTileNotFoundError resp.raise_for_status() diff --git a/pygeoapi/provider/mvt_proxy.py b/pygeoapi/provider/mvt_proxy.py index c9aa64293..3d20d3ced 100644 --- a/pygeoapi/provider/mvt_proxy.py +++ b/pygeoapi/provider/mvt_proxy.py @@ -175,6 +175,8 @@ def get_tiles(self, layer=None, tileset=None, resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{url_query}') # noqa if resp.status_code == 404: + if (self.is_in_limits(self.get_tilematrixset(tileset), z, x, y)): # noqa + return None raise ProviderTileNotFoundError resp.raise_for_status() diff --git a/pygeoapi/provider/mvt_tippecanoe.py b/pygeoapi/provider/mvt_tippecanoe.py index e9753359c..2cf855903 100644 --- a/pygeoapi/provider/mvt_tippecanoe.py +++ b/pygeoapi/provider/mvt_tippecanoe.py @@ -188,6 +188,8 @@ def get_tiles_from_url(self, layer=None, tileset=None, resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{extension}') # noqa if resp.status_code == 404: + if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa + return None raise ProviderTileNotFoundError resp.raise_for_status() @@ -218,6 +220,8 @@ def get_tiles_from_disk(self, layer=None, tileset=None, with open(service_url_path, mode='rb') as tile: return tile.read() except FileNotFoundError as err: + if (self.is_in_limits(TileMatrixSetEnum.WEBMERCATORQUAD.value, z, x, y)): # noqa + return None raise ProviderTileNotFoundError(err) def get_tiles(self, layer=None, tileset=None, diff --git a/tests/api/test_tiles.py b/tests/api/test_tiles.py index 783419592..528220cdf 100644 --- a/tests/api/test_tiles.py +++ b/tests/api/test_tiles.py @@ -7,6 +7,7 @@ # # Copyright (c) 2024 Tom Kralidis # Copyright (c) 2022 John A Stevenson and Colin Blackburn +# Copyright (c) 2025 doublebyte # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation @@ -39,7 +40,8 @@ from pygeoapi.api import FORMAT_TYPES, F_HTML from pygeoapi.api.tiles import ( get_collection_tiles, tilematrixset, - tilematrixsets, get_collection_tiles_metadata + tilematrixsets, get_collection_tiles_metadata, + get_collection_tiles_data ) from pygeoapi.models.provider.base import TileMatrixSetEnum @@ -65,6 +67,24 @@ def test_get_collection_tiles(config, api_): assert len(content['tilesets']) > 0 +def test_get_collection_tiles_data(config, api_): + req = mock_api_request({'f': 'mvt'}) + rsp_headers, code, response = get_collection_tiles_data( + api_, req, 'naturalearth/lakes', + matrix_id='WebMercatorQuad', z_idx=0, x_idx=0, y_idx=0) + assert code == HTTPStatus.OK + + rsp_headers, code, response = get_collection_tiles_data( + api_, req, 'naturalearth/lakes', + matrix_id='WebMercatorQuad', z_idx=5, x_idx=15, y_idx=16) + assert code == HTTPStatus.NO_CONTENT + + rsp_headers, code, response = get_collection_tiles_data( + api_, req, 'naturalearth/lakes', + matrix_id='WebMercatorQuad', z_idx=0, x_idx=1, y_idx=1) + assert code == HTTPStatus.NOT_FOUND + + def test_tilematrixsets(config, api_): req = mock_api_request() rsp_headers, code, response = tilematrixsets(api_, req)