Skip to content

Commit 47c7fb1

Browse files
Feature/mosaic asset accessor (#1151)
* add assets_accessor_dependency to MosaicTilerFactory * update docs
1 parent c680c5c commit 47c7fb1

File tree

5 files changed

+78
-3
lines changed

5 files changed

+78
-3
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
* add `/bbox` prefix to `/{minx},{miny},{maxx},{maxy}/assets` endpoint -> `/bbox/{minx},{miny},{maxx},{maxy}/assets` **breaking change**
145145
* add `/point` prefix to `{lon},{lat}/assets` endpoint -> `/point/{lon},{lat}/assets` **breaking change**
146146
* add `/tiles` prefix to `/{tileMatrixSetId}/{z}/{x}/{y}/assets` endpoint -> `/tiles/{tileMatrixSetId}/{z}/{x}/{y}/assets` **breaking change**
147-
147+
* add `assets_accessor_dependency` dependency to the MosaicTileFactory to pass options to the backend's `get_assets` method.
148148

149149
## 0.21.1 (2025-01-29)
150150

docs/src/advanced/endpoints_factories.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ Endpoints factory for mosaics, built on top of [MosaicJSON](https://github.com/d
302302
- **dataset_reader**: Dataset Reader. Defaults to `rio_tiler.io.Reader`
303303
- **reader_dependency**: Dependency to control options passed to the reader instance init. Defaults to `titiler.core.dependencies.DefaultDependency`
304304
- **path_dependency**: Dependency to use to define the dataset url. Defaults to `titiler.mosaic.factory.DatasetPathParams`.
305+
- **assets_accessor_dependency**: Dependency to define options to be forwarded to the backend `get_assets` method. Defaults to `titiler.core.dependencies.DefaultDependency`.
305306
- **layer_dependency**: Dependency to define band indexes or expression. Defaults to `titiler.core.dependencies.BidxExprParams`.
306307
- **dataset_dependency**: Dependency to overwrite `nodata` value, apply `rescaling` and change the `I/O` or `Warp` resamplings. Defaults to `titiler.core.dependencies.DatasetParams`.
307308
- **tile_dependency**: Dependency to define `buffer` and `padding` to apply at tile creation. Defaults to `titiler.core.dependencies.TileParams`.

src/titiler/mosaic/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ test = [
4141
"pytest-cov",
4242
"pytest-asyncio",
4343
"httpx",
44+
"cogeo-mosaic>=8.2,<9.0",
4445
]
4546

4647
[project.urls]

src/titiler/mosaic/tests/test_factory.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
from contextlib import contextmanager
66
from dataclasses import dataclass
77
from io import BytesIO
8+
from typing import List, Optional
89
from unittest.mock import patch
910

11+
import attr
1012
import morecantile
1113
import numpy
1214
from cogeo_mosaic.backends import FileBackend
1315
from cogeo_mosaic.mosaic import MosaicJSON
14-
from fastapi import FastAPI
16+
from fastapi import FastAPI, Query
1517
from rio_tiler.mosaic.methods import PixelSelectionMethod
1618
from starlette.testclient import TestClient
19+
from typing_extensions import Annotated
1720

1821
from titiler.core.dependencies import DefaultDependency
1922
from titiler.core.resources.enums import OptionalHeader
@@ -384,3 +387,53 @@ def test_MosaicTilerFactory_strict_zoom():
384387
)
385388
assert response.status_code == 400
386389
assert "Invalid ZOOM level 11" in response.text
390+
391+
392+
@dataclass
393+
class AssetsAccessParams(DefaultDependency):
394+
"""Backend options to overwrite min/max zoom."""
395+
396+
limit: Annotated[int, Query()] = 10
397+
398+
399+
@attr.s
400+
class CustomBackend(FileBackend):
401+
"""Custom FileBackend."""
402+
403+
def get_assets(
404+
self, x: int, y: int, z: int, limit: Optional[int] = None
405+
) -> List[str]:
406+
"""Find assets."""
407+
assets = super().get_assets(x, y, z)
408+
409+
if limit and len(assets) > limit:
410+
return assets[:limit]
411+
412+
return assets
413+
414+
415+
def test_MosaicTilerFactory_asset_accessor():
416+
"""Test MosaicTilerFactory factory with Backend dependency."""
417+
mosaic = MosaicTilerFactory(
418+
backend=CustomBackend,
419+
router_prefix="/mosaic",
420+
assets_accessor_dependency=AssetsAccessParams,
421+
)
422+
app = FastAPI()
423+
app.include_router(mosaic.router, prefix="/mosaic")
424+
client = TestClient(app)
425+
426+
with tmpmosaic() as mosaic_file:
427+
response = client.get(
428+
"/mosaic/tiles/WGS1984Quad/8/148/61/assets",
429+
params={"url": mosaic_file},
430+
)
431+
assert response.status_code == 200
432+
assert len(response.json()) == 2
433+
434+
response = client.get(
435+
"/mosaic/tiles/WGS1984Quad/8/148/61/assets",
436+
params={"url": mosaic_file, "limit": 1},
437+
)
438+
assert response.status_code == 200
439+
assert len(response.json()) == 1

src/titiler/mosaic/titiler/mosaic/factory.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class MosaicTilerFactory(BaseFactory):
9090
# Path Dependency
9191
path_dependency: Callable[..., Any] = DatasetPathParams
9292

93+
# Backend.get_assets() Options
94+
assets_accessor_dependency: Type[DefaultDependency] = DefaultDependency
95+
9396
# Indexes/Expression Dependencies
9497
layer_dependency: Type[DefaultDependency] = BidxExprParams
9598

@@ -585,6 +588,7 @@ def tile(
585588
src_path=Depends(self.path_dependency),
586589
backend_params=Depends(self.backend_dependency),
587590
reader_params=Depends(self.reader_dependency),
591+
assets_accessor_params=Depends(self.assets_accessor_dependency),
588592
layer_params=Depends(self.layer_dependency),
589593
dataset_params=Depends(self.dataset_dependency),
590594
pixel_selection=Depends(self.pixel_selection_dependency),
@@ -628,6 +632,7 @@ def tile(
628632
**tile_params.as_dict(),
629633
**layer_params.as_dict(),
630634
**dataset_params.as_dict(),
635+
**assets_accessor_params.as_dict(),
631636
)
632637

633638
if post_process:
@@ -687,6 +692,7 @@ def tilejson(
687692
src_path=Depends(self.path_dependency),
688693
backend_params=Depends(self.backend_dependency),
689694
reader_params=Depends(self.reader_dependency),
695+
assets_accessor_params=Depends(self.assets_accessor_dependency),
690696
layer_params=Depends(self.layer_dependency),
691697
dataset_params=Depends(self.dataset_dependency),
692698
pixel_selection=Depends(self.pixel_selection_dependency),
@@ -783,6 +789,7 @@ def map_viewer(
783789
src_path=Depends(self.path_dependency),
784790
backend_params=Depends(self.backend_dependency),
785791
reader_params=Depends(self.reader_dependency),
792+
assets_accessor_params=Depends(self.assets_accessor_dependency),
786793
layer_params=Depends(self.layer_dependency),
787794
dataset_params=Depends(self.dataset_dependency),
788795
pixel_selection=Depends(self.pixel_selection_dependency),
@@ -856,6 +863,7 @@ def wmts(
856863
src_path=Depends(self.path_dependency),
857864
backend_params=Depends(self.backend_dependency),
858865
reader_params=Depends(self.reader_dependency),
866+
assets_accessor_params=Depends(self.assets_accessor_dependency),
859867
layer_params=Depends(self.layer_dependency),
860868
dataset_params=Depends(self.dataset_dependency),
861869
pixel_selection=Depends(self.pixel_selection_dependency),
@@ -982,6 +990,7 @@ def point(
982990
src_path=Depends(self.path_dependency),
983991
backend_params=Depends(self.backend_dependency),
984992
reader_params=Depends(self.reader_dependency),
993+
assets_accessor_params=Depends(self.assets_accessor_dependency),
985994
coord_crs=Depends(CoordCRSParams),
986995
layer_params=Depends(self.layer_dependency),
987996
dataset_params=Depends(self.dataset_dependency),
@@ -1002,6 +1011,7 @@ def point(
10021011
threads=MOSAIC_THREADS,
10031012
**layer_params.as_dict(),
10041013
**dataset_params.as_dict(),
1014+
**assets_accessor_params.as_dict(),
10051015
)
10061016

10071017
return {
@@ -1038,6 +1048,7 @@ def assets_for_bbox(
10381048
src_path=Depends(self.path_dependency),
10391049
backend_params=Depends(self.backend_dependency),
10401050
reader_params=Depends(self.reader_dependency),
1051+
assets_accessor_params=Depends(self.assets_accessor_dependency),
10411052
coord_crs=Depends(CoordCRSParams),
10421053
env=Depends(self.environment_dependency),
10431054
):
@@ -1055,6 +1066,7 @@ def assets_for_bbox(
10551066
maxx,
10561067
maxy,
10571068
coord_crs=coord_crs or WGS84_CRS,
1069+
**assets_accessor_params.as_dict(),
10581070
)
10591071

10601072
@self.router.get(
@@ -1069,6 +1081,7 @@ def assets_for_lon_lat(
10691081
coord_crs=Depends(CoordCRSParams),
10701082
backend_params=Depends(self.backend_dependency),
10711083
reader_params=Depends(self.reader_dependency),
1084+
assets_accessor_params=Depends(self.assets_accessor_dependency),
10721085
env=Depends(self.environment_dependency),
10731086
):
10741087
"""Return a list of assets which overlap a point"""
@@ -1083,6 +1096,7 @@ def assets_for_lon_lat(
10831096
lon,
10841097
lat,
10851098
coord_crs=coord_crs or WGS84_CRS,
1099+
**assets_accessor_params.as_dict(),
10861100
)
10871101

10881102
@self.router.get(
@@ -1118,6 +1132,7 @@ def assets_for_tile(
11181132
src_path=Depends(self.path_dependency),
11191133
backend_params=Depends(self.backend_dependency),
11201134
reader_params=Depends(self.reader_dependency),
1135+
assets_accessor_params=Depends(self.assets_accessor_dependency),
11211136
env=Depends(self.environment_dependency),
11221137
):
11231138
"""Return a list of assets which overlap a given tile"""
@@ -1130,4 +1145,9 @@ def assets_for_tile(
11301145
reader_options=reader_params.as_dict(),
11311146
**backend_params.as_dict(),
11321147
) as src_dst:
1133-
return src_dst.assets_for_tile(x, y, z)
1148+
return src_dst.assets_for_tile(
1149+
x,
1150+
y,
1151+
z,
1152+
**assets_accessor_params.as_dict(),
1153+
)

0 commit comments

Comments
 (0)