Skip to content

Commit

Permalink
refactor: search all pages during _search_by_id
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrunato committed Apr 16, 2024
1 parent 82d0af1 commit 695b329
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 33 deletions.
61 changes: 41 additions & 20 deletions eodag/api/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1064,14 +1064,11 @@ def search(
)

if search_kwargs.get("id"):
# adds minimal pagination to be able to check only 1 product is returned
search_kwargs.update(
page=1,
items_per_page=2,
raise_errors=raise_errors,
)
return self._search_by_id(
search_kwargs.pop("id"), provider=provider, **search_kwargs
search_kwargs.pop("id"),
provider=provider,
raise_errors=raise_errors,
**search_kwargs,
)
# remove datacube query string from kwargs which was only needed for search-by-id
search_kwargs.pop("_dc_qs", None)
Expand Down Expand Up @@ -1454,16 +1451,51 @@ def _search_by_id(
# datacube query string
_dc_qs = kwargs.pop("_dc_qs", None)

results = SearchResult([])

for plugin in search_plugins:
logger.info(
"Searching product with id '%s' on provider: %s", uid, plugin.provider
)
logger.debug("Using plugin class for search: %s", plugin.__class__.__name__)
plugin.clear()

# adds maximal pagination to be able to do a search-all + crunch if more
# than one result are returned
items_per_page = plugin.config.pagination.get(
"max_items_per_page", DEFAULT_MAX_ITEMS_PER_PAGE
)
kwargs.update(items_per_page=items_per_page)
if isinstance(plugin, BuildPostSearchResult):
results, _ = self._do_search(plugin, id=uid, _dc_qs=_dc_qs, **kwargs)
kwargs.update(
items_per_page=items_per_page,
_dc_qs=_dc_qs,
)
else:
results, _ = self._do_search(plugin, id=uid, **kwargs)
kwargs.update(
items_per_page=items_per_page,
)

try:
# if more than one results are found, try getting them all and then filter using crunch
for page_results in self.search_iter_page_plugin(
search_plugin=plugin,
id=uid,
**kwargs,
):
results.data.extend(page_results.data)
except Exception:
if kwargs.get("raise_errors"):
raise
continue

# try using crunch to get unique result
if (
len(results) > 1
and len(filtered := results.filter_property(id=uid)) == 1
):
results = filtered

if len(results) == 1:
if not results[0].product_type:
# guess product type from properties
Expand All @@ -1473,17 +1505,6 @@ def _search_by_id(
results[0].driver = results[0].get_driver()
return results, 1
elif len(results) > 1:
if getattr(plugin.config, "two_passes_id_search", False):
# check if id of one product exactly matches id that was searched for
# required if provider does not offer search by id and therefore other
# parameters which might not given an exact result are used
for result in results:
if result.properties["id"] == uid.split(".")[0]:
return SearchResult([results[0]]), 1
# try using crunch to get unique result
if len(filtered := results.filter_property(id=uid)) == 1:
return filtered, 1

logger.info(
"Several products found for this id (%s). You may try searching using more selective criteria.",
results,
Expand Down
45 changes: 32 additions & 13 deletions tests/units/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@ def test__prepare_search_unknown_product_type(self, mock_fetch_product_types_lis
@mock.patch(
"eodag.api.core.EODataAccessGateway._do_search",
autospec=True,
return_value=([mock.Mock()], 1),
return_value=(SearchResult([mock.Mock()]), 1),
)
@mock.patch("eodag.plugins.manager.PluginManager.get_auth_plugin", autospec=True)
@mock.patch(
Expand All @@ -1961,6 +1961,21 @@ def test__search_by_id(
self, mock_get_search_plugins, mock_get_auth_plugin, mock__do_search
):
"""_search_by_id must filter search plugins using given kwargs, clear plugin and perform search"""
# max_items_per_page plugin conf
mock_config = mock.Mock()
type(mock_config).pagination = mock.PropertyMock(
return_value={"max_items_per_page": 100}
)
type(mock_get_search_plugins.return_value[0]).config = mock.PropertyMock(
return_value=mock_config
)
type(
mock_get_search_plugins.return_value[0]
).next_page_query_obj = mock.PropertyMock(return_value={})
# mocked search result id
type(mock__do_search.return_value[0][0]).properties = mock.PropertyMock(
return_value={"id": "foo"}
)

found = self.dag._search_by_id(uid="foo", productType="bar", provider="baz")

Expand All @@ -1981,32 +1996,36 @@ def test__search_by_id(
mock_get_search_plugins.return_value[0],
id="foo",
productType="bar",
count=False,
raise_errors=True,
page=1,
items_per_page=100,
)
self.assertEqual(found, mock__do_search.return_value)

mock__do_search.reset_mock()
# return None if more than 1 product is found
m = mock.MagicMock()
p = EOProduct(
"peps", {"id": "a", "geometry": {"type": "Point", "coordinates": [1, 1]}}
mock__do_search.return_value = (SearchResult([mock.Mock(), mock.Mock()]), 2)
type(mock__do_search.return_value[0][0]).properties = mock.PropertyMock(
return_value={"id": "foo"}
)
type(mock__do_search.return_value[0][1]).properties = mock.PropertyMock(
return_value={"id": "foo"}
)
m.__len__.return_value = 2
m.__iter__.return_value = [p, p]
mock__do_search.return_value = (m, 2)
with self.assertLogs(level="INFO") as cm:
found = self.dag._search_by_id(uid="foo", productType="bar", provider="baz")
self.assertEqual(found, (SearchResult([]), 0))
self.assertIn("Several products found for this id", str(cm.output))

mock__do_search.reset_mock()
# return 1 result if more than 1 product is found but only 1 has the matching id
m = mock.MagicMock()
p2 = EOProduct(
"peps", {"id": "foo", "geometry": {"type": "Point", "coordinates": [1, 1]}}
mock__do_search.return_value = (SearchResult([mock.Mock(), mock.Mock()]), 2)
type(mock__do_search.return_value[0][0]).properties = mock.PropertyMock(
return_value={"id": "foo"}
)
type(mock__do_search.return_value[0][1]).properties = mock.PropertyMock(
return_value={"id": "foooooo"}
)
m.__len__.return_value = 2
m.__iter__.return_value = [p, p2]
mock__do_search.return_value = (m, 2)
found = self.dag._search_by_id(uid="foo", productType="bar", provider="baz")
self.assertEqual(found[1], 1)
self.assertEqual(len(found[0]), 1)
Expand Down

0 comments on commit 695b329

Please sign in to comment.