Repository: developmentseed/cogeo-mosaic

Issue:
add`asset_prefix` to assets
### Discussed in https://github.com/developmentseed/cogeo-mosaic/discussions/226

<div type='discussions-op-text'>

<sup>Originally posted by **scottyhq** December  6, 2023</sup>
I tired rendering the 0.0.3 example which uses public data:
https://titiler.xyz/mosaicjson/map?url=https://raw.githubusercontent.com/developmentseed/mosaicjson-spec/main/0.0.3/example/dg_post_idai.json 

But get a lot of 500 errors, I also tried modifying the docs example to just use `"asset_prefix":"s3://noaa-eri-pds/2020_Nashville_Tornado/20200307a_RGB/"`:
https://titiler.xyz/mosaicjson/map?url=https://gist.githubusercontent.com/scottyhq/4c288a2dbf7b97ef7833c5e0ee19d6d6/raw/636083cf7117a96e38d271eeef932a3ee507d7d1/NOAA_Nashville_Tornado_v3.json

So I suspect titiler by default doesn't have logic to pick up the `asset_prefix`

</div>

Comments:

Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 12763d0..1ec014f 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,6 @@
+## 7.1.0
+
+* Automatically remove/add `asset_prefix` in Mosaic Backends
 
 ## 7.0.1 (2023-10-17)
 
diff --git a/cogeo_mosaic/backends/base.py b/cogeo_mosaic/backends/base.py
index 4fe4f64..7cb8a91 100644
--- a/cogeo_mosaic/backends/base.py
+++ b/cogeo_mosaic/backends/base.py
@@ -236,13 +236,17 @@ class BaseBackend(BaseReader):
     def get_assets(self, x: int, y: int, z: int) -> List[str]:
         """Find assets."""
         quadkeys = self.find_quadkeys(Tile(x=x, y=y, z=z), self.quadkey_zoom)
-        return list(
+        assets = list(
             dict.fromkeys(
                 itertools.chain.from_iterable(
                     [self.mosaic_def.tiles.get(qk, []) for qk in quadkeys]
                 )
             )
         )
+        if self.mosaic_def.asset_prefix:
+            assets = [self.mosaic_def.asset_prefix + asset for asset in assets]
+
+        return assets
 
     def find_quadkeys(self, tile: Tile, quadkey_zoom: int) -> List[str]:
         """
diff --git a/cogeo_mosaic/backends/dynamodb.py b/cogeo_mosaic/backends/dynamodb.py
index 5a1e5f8..8c14e6a 100644
--- a/cogeo_mosaic/backends/dynamodb.py
+++ b/cogeo_mosaic/backends/dynamodb.py
@@ -222,13 +222,17 @@ class DynamoDBBackend(BaseBackend):
     def get_assets(self, x: int, y: int, z: int) -> List[str]:
         """Find assets."""
         quadkeys = self.find_quadkeys(Tile(x=x, y=y, z=z), self.quadkey_zoom)
-        return list(
+        assets = list(
             dict.fromkeys(
                 itertools.chain.from_iterable(
                     [self._fetch_dynamodb(qk).get("assets", []) for qk in quadkeys]
                 )
             )
         )
+        if self.mosaic_def.asset_prefix:
+            assets = [self.mosaic_def.asset_prefix + asset for asset in assets]
+
+        return assets
 
     @property
     def _quadkeys(self) -> List[str]:
diff --git a/cogeo_mosaic/backends/sqlite.py b/cogeo_mosaic/backends/sqlite.py
index d4ae7d7..d336c9e 100644
--- a/cogeo_mosaic/backends/sqlite.py
+++ b/cogeo_mosaic/backends/sqlite.py
@@ -316,11 +316,15 @@ class SQLiteBackend(BaseBackend):
         """Find assets."""
         mercator_tile = morecantile.Tile(x=x, y=y, z=z)
         quadkeys = self.find_quadkeys(mercator_tile, self.quadkey_zoom)
-        return list(
+        assets = list(
             dict.fromkeys(
                 itertools.chain.from_iterable([self._fetch(qk) for qk in quadkeys])
             )
         )
+        if self.mosaic_def.asset_prefix:
+            assets = [self.mosaic_def.asset_prefix + asset for asset in assets]
+
+        return assets
 
     @property
     def _quadkeys(self) -> List[str]:
diff --git a/cogeo_mosaic/mosaic.py b/cogeo_mosaic/mosaic.py
index 21d0dbc..4ba709c 100644
--- a/cogeo_mosaic/mosaic.py
+++ b/cogeo_mosaic/mosaic.py
@@ -1,6 +1,7 @@
 """cogeo_mosaic.mosaic MosaicJSON models and helper functions."""
 
 import os
+import re
 import sys
 import warnings
 from contextlib import ExitStack
@@ -230,9 +231,16 @@ class MosaicJSON(BaseModel, validate_assignment=True):
                     )
 
                     if dataset:
-                        mosaic_definition["tiles"][quadkey] = [
-                            accessor(f) for f in dataset
-                        ]
+                        assets = [accessor(f) for f in dataset]
+                        if asset_prefix:
+                            assets = [
+                                re.sub(rf"^{asset_prefix}", "", asset)
+                                if asset.startswith(asset_prefix)
+                                else asset
+                                for asset in assets
+                            ]
+
+                        mosaic_definition["tiles"][quadkey] = assets
 
         return cls(**mosaic_definition)
 


Test patch:
diff --git a/tests/test_backends.py b/tests/test_backends.py
index c2e7d57..852157e 100644
--- a/tests/test_backends.py
+++ b/tests/test_backends.py
@@ -1217,3 +1217,15 @@ def test_point_crs_coordinates():
         assert ptsR[0][0] == pts[0][0]
         assert ptsR[0][1].crs == "epsg:3857"
         assert ptsR[0][1].coordinates == (-8200051.8694, 5782905.49327)
+
+
+def test_InMemoryReader_asset_prefix():
+    """Test MemoryBackend."""
+    assets = [asset1, asset2]
+    prefix = os.path.join(os.path.dirname(__file__), "fixtures")
+    mosaicdef = MosaicJSON.from_urls(assets, quiet=False, asset_prefix=prefix)
+
+    assert mosaicdef.tiles["0302310"] == ["/cog1.tif", "/cog2.tif"]
+    with MemoryBackend(mosaic_def=mosaicdef) as mosaic:
+        assets = mosaic.assets_for_tile(150, 182, 9)
+        assert assets[0].startswith(prefix)
diff --git a/tests/test_create.py b/tests/test_create.py
index 6998267..4fb30e5 100644
--- a/tests/test_create.py
+++ b/tests/test_create.py
@@ -127,7 +127,7 @@ def test_mosaic_create_additional_metadata():
         quiet=True,
         tilematrixset=tms_3857,
         asset_type="COG",
-        asset_prefix="s3://my-bucket/",
+        asset_prefix=basepath,
         data_type="uint16",
         layers={
             "true-color": {
@@ -137,6 +137,7 @@ def test_mosaic_create_additional_metadata():
         },
     )
     assert mosaic.asset_type == "COG"
-    assert mosaic.asset_prefix == "s3://my-bucket/"
+    assert mosaic.asset_prefix == basepath
     assert mosaic.data_type == "uint16"
     assert mosaic.layers["true-color"]
+    assert mosaic.tiles["0302301"] == ["/cog1.tif", "/cog2.tif"]