Repository: CS-SI/eodag-cube (language: python)

Issue:
Add driver for products with assets
Products having `assets` attribute like, like the ones obtained through `StacSearch` plugin, should have a common driver to help reading each asset with `get_data()`


Discussion / hints:

Fix patch:
diff --git a/eodag_cube/api/product/drivers/__init__.py b/eodag_cube/api/product/drivers/__init__.py
index 8d58e26..5a0b1bd 100644
--- a/eodag_cube/api/product/drivers/__init__.py
+++ b/eodag_cube/api/product/drivers/__init__.py
@@ -18,5 +18,23 @@
 """EODAG drivers package"""
 from eodag.api.product.drivers.base import NoDriver  # noqa
 from eodag_cube.api.product.drivers.sentinel2_l1c import Sentinel2L1C
+from eodag_cube.api.product.drivers.stac_assets import StacAssets
 
-DRIVERS = {"S2_MSI_L1C": Sentinel2L1C()}
+DRIVERS = [
+    {
+        "criteria": [lambda prod: True if hasattr(prod, "assets") else False],
+        "driver": StacAssets(),
+    },
+    {
+        "criteria": [lambda prod: True if "assets" in prod.properties else False],
+        "driver": StacAssets(),
+    },
+    {
+        "criteria": [
+            lambda prod: True
+            if getattr(prod, "product_type") == "S2_MSI_L1C"
+            else False
+        ],
+        "driver": Sentinel2L1C(),
+    },
+]
diff --git a/eodag_cube/api/product/drivers/stac_assets.py b/eodag_cube/api/product/drivers/stac_assets.py
new file mode 100644
index 0000000..48dead4
--- /dev/null
+++ b/eodag_cube/api/product/drivers/stac_assets.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021, CS GROUP - France, http://www.c-s.fr
+#
+# This file is part of EODAG project
+#     https://www.github.com/CS-SI/EODAG
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from eodag.api.product.drivers.base import DatasetDriver
+from eodag.utils.exceptions import AddressNotFound
+
+
+class StacAssets(DatasetDriver):
+    """Driver for Stac Assets"""
+
+    def get_data_address(self, eo_product, band):
+        """Get the address of a subdataset for a STAC provider product.
+
+        See :func:`~eodag.api.product.drivers.base.DatasetDriver.get_data_address` to get help on the formal
+        parameters.
+        """
+        if band in eo_product.assets:
+            return eo_product.assets[band]["href"]
+        elif band.upper() in [b.upper() for b in eo_product.assets.keys()]:
+            for k, v in eo_product.assets.items():
+                if k.upper() == band.upper():
+                    return v["href"]
+
+        raise AddressNotFound
diff --git a/setup.py b/setup.py
index 52b8ee2..91f2468 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
     package_data={"": ["LICENSE"]},
     include_package_data=True,
     install_requires=[
-        "eodag >= 2.0b2",
+        "eodag >= 2.3.1",
         "numpy",
         "rasterio",
         "protobuf",


Test patch:
diff --git a/tests/context.py b/tests/context.py
index 513fab4..a604daa 100644
--- a/tests/context.py
+++ b/tests/context.py
@@ -30,6 +30,7 @@
 from eodag.api.product.drivers import DRIVERS
 from eodag.api.product.drivers.base import NoDriver
 from eodag_cube.api.product.drivers.sentinel2_l1c import Sentinel2L1C
+from eodag_cube.api.product.drivers.stac_assets import StacAssets
 from eodag.api.search_result import SearchResult
 from eodag.cli import download, eodag, list_pt, search_crunch
 from eodag.plugins.authentication.base import Authentication
diff --git a/tests/units/test_eoproduct_driver_stac_assets.py b/tests/units/test_eoproduct_driver_stac_assets.py
new file mode 100644
index 0000000..8678704
--- /dev/null
+++ b/tests/units/test_eoproduct_driver_stac_assets.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# Copyright 2021, CS GROUP - France, http://www.c-s.fr
+#
+# This file is part of EODAG project
+#     https://www.github.com/CS-SI/EODAG
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from contextlib import contextmanager
+
+from tests import TEST_RESOURCES_PATH, EODagTestCase
+from tests.context import AddressNotFound, EOProduct, StacAssets
+
+
+class TestEOProductDriverStacAssets(EODagTestCase):
+    def setUp(self):
+        super(TestEOProductDriverStacAssets, self).setUp()
+        self.product = EOProduct(
+            self.provider, self.eoproduct_props, productType=self.product_type
+        )
+        self.product.properties["title"] = os.path.join(
+            TEST_RESOURCES_PATH,
+            "products",
+            "S2A_MSIL1C_20180101T105441_N0206_R051_T31TDH_20180101T124911.SAFE",
+        )
+        self.product.assets = {
+            "B01": {
+                "title": "Band 1 (coastal)",
+                "type": "image/jp2",
+                "href": os.path.join(
+                    TEST_RESOURCES_PATH,
+                    "products",
+                    "S2A_MSIL1C_20180101T105441_N0206_R051_T31TDH_20180101T124911.SAFE/"
+                    + "GRANULE/L1C_T31TDH_A013204_20180101T105435/IMG_DATA/T31TDH_20180101T105441_B01.jp2",
+                ),
+            }
+        }
+        self.stac_assets_driver = StacAssets()
+
+    def test_driver_get_local_dataset_address_bad_band(self):
+        """Driver must raise AddressNotFound if non existent band is requested"""
+        with self._filesystem_product() as product:
+            driver = StacAssets()
+            band = "B02"
+            self.assertRaises(AddressNotFound, driver.get_data_address, product, band)
+
+    def test_driver_get_local_dataset_address_ok(self):
+        """Driver returns a good address for an existing band"""
+        with self._filesystem_product() as product:
+            band = "B01"
+            address = self.stac_assets_driver.get_data_address(product, band)
+            self.assertEqual(address, self.local_band_file)
+
+    @contextmanager
+    def _filesystem_product(self):
+        original = self.product.location
+        try:
+            self.product.location = "file://{}".format(self.product.properties["title"])
+            yield self.product
+        finally:
+            self.product.location = original