Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion eodag/api/product/drivers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,17 @@ def guess_asset_key_and_roles(

:param href: The asset href
:param eo_product: The product to which the asset belongs
:returns: The asset key and roles
:returns: The asset key and roles, or ``(None, None)`` if the filename
extracted from ``href`` has no extension
"""
# If filename extracted from href has no extension, return None
# so that the caller can keep the original asset key and roles
filename = (
href.split("?")[0].split("!")[-1].replace("\\", "/").rsplit("/", 1)[-1]
)
if filename and "." not in filename:
return None, None

for pattern_dict in self.ASSET_KEYS_PATTERNS_ROLES:
if matched := pattern_dict["pattern"].match(href):
extracted_key, roles = (
Expand Down
13 changes: 10 additions & 3 deletions eodag/plugins/search/qssearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -1314,14 +1314,21 @@ def normalize_results(
product.assets.update(additional_assets)
# move assets from properties to product's attr, normalize keys & roles
for key, asset in product.properties.pop("assets", {}).items():
norm_key, asset["roles"] = product.driver.guess_asset_key_and_roles(
norm_key, norm_roles = product.driver.guess_asset_key_and_roles(
asset.get("href", "") if asset_key_from_href else key,
product,
)
# Keep original key and roles if driver couldn't guess
# (e.g., filename without extension)
if norm_key is None:
norm_key = key
else:
asset["roles"] = norm_roles
asset["title"] = norm_key
if norm_key:
product.assets[norm_key] = asset
# Normalize title with key
product.assets[norm_key]["title"] = norm_key
# Set title if not already set
product.assets[norm_key].setdefault("title", norm_key)
# sort assets
product.assets.data = dict(sorted(product.assets.data.items()))
products.append(product)
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/test_core_search_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,11 +721,11 @@ def test_core_import_stac_items_from_eodag_server(self, mock_fetch_stac_items):
self.assertEqual(results[1].collection, "bar-collection")
self.assertEqual(len(results[1].assets), 2)
self.assertEqual(
results[1].assets["asset-1-link"]["href"],
results[1].assets["asset-1"]["href"],
"https://provider-url/asset-1-link",
)
self.assertEqual(
results[1].assets["asset-2-link"]["href"],
results[1].assets["asset-2"]["href"],
"https://provider-url/asset-2-link",
)
self.assertIsInstance(results[1].downloader, Download)
Expand Down
13 changes: 13 additions & 0 deletions tests/units/test_eoproduct_driver_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,16 @@ def test_driver_generic_guess_asset_key_and_roles(self):
),
("quick-look.jpg", ["overview"]),
)
# no extension: return None to keep original key and roles
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"s3://foo/1/28/0/some-key", self.product
),
(None, None),
)
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"https://example.com/path/no-ext-file?foo=bar", self.product
),
(None, None),
)
13 changes: 13 additions & 0 deletions tests/units/test_eoproduct_driver_sentinel1.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,16 @@ def test_driver_s1_guess_asset_key_and_roles(self):
),
("foo.bar.baz", ["auxiliary"]),
)
# no extension: return None to keep original key and roles
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"s3://foo/1/28/0/some-key", self.product
),
(None, None),
)
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"https://example.com/path/no-ext-file?foo=bar", self.product
),
(None, None),
)
13 changes: 13 additions & 0 deletions tests/units/test_eoproduct_driver_sentinel2.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,16 @@ def test_driver_s2_guess_asset_key_and_roles(self):
),
("foo.bar", ["auxiliary"]),
)
# no extension: return None to keep original key and roles
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"s3://foo/1/28/0/some-key", self.product
),
(None, None),
)
self.assertEqual(
self.product.driver.guess_asset_key_and_roles(
"https://example.com/path/no-ext-file?foo=bar", self.product
),
(None, None),
)
38 changes: 38 additions & 0 deletions tests/units/test_search_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,44 @@ def test_plugins_search_stacsearch_normalize_asset_key_from_href(
products[0].assets["normalized_key"]["title"], "normalized_key"
)

mock_guess_asset_key_and_roles.reset_mock()
# no-extension href: driver returns (None, None), original key and roles are kept
mock_guess_asset_key_and_roles.return_value = (None, None)
mock_properties_from_json.return_value = {
"geometry": "POINT (0 0)",
"assets": {
"some-asset": {
"href": "https://example.com/foo",
"roles": ["bar"],
},
},
}
search_plugin = self.get_search_plugin(self.collection, "earth_search")
products = search_plugin.normalize_results([{}])
self.assertEqual(len(products[0].assets), 1)
self.assertIn("some-asset", products[0].assets)
self.assertEqual(products[0].assets["some-asset"]["roles"], ["bar"])
self.assertEqual(products[0].assets["some-asset"]["title"], "some-asset")

mock_guess_asset_key_and_roles.reset_mock()
# no-extension href with existing title: original title is preserved
mock_guess_asset_key_and_roles.return_value = (None, None)
mock_properties_from_json.return_value = {
"geometry": "POINT (0 0)",
"assets": {
"some-asset": {
"href": "https://example.com/foo",
"roles": ["bar"],
"title": "My custom title",
},
},
}
search_plugin = self.get_search_plugin(self.collection, "earth_search")
products = search_plugin.normalize_results([{}])
self.assertEqual(len(products[0].assets), 1)
self.assertIn("some-asset", products[0].assets)
self.assertEqual(products[0].assets["some-asset"]["title"], "My custom title")

@mock.patch("eodag.plugins.search.qssearch.requests.post", autospec=True)
def test_plugins_search_stacsearch_opened_time_intervals(self, mock_requests_post):
"""Opened time intervals must be handled by StacSearch plugin"""
Expand Down
Loading