@@ -170,6 +170,9 @@ def __init__(self, user_conf_file_path=None, locations_conf_path=None):
170170 )
171171 self .set_locations_conf (locations_conf_path )
172172
173+ # record searchs done
174+ self .search_kwargs_list = []
175+
173176 def get_version (self ):
174177 """Get eodag package version"""
175178 return pkg_resources .get_distribution ("eodag" ).version
@@ -976,69 +979,77 @@ def search_iter_page(
976979 if iteration > 1 and next_page_query_obj :
977980 pagination_config ["next_page_query_obj" ] = next_page_query_obj
978981 logger .info ("Iterate search over multiple pages: page #%s" , iteration )
979- try :
980- products , _ = self ._do_search (
981- search_plugin , count = False , raise_errors = True , ** search_kwargs
982+ if search_kwargs in self .search_kwargs_list :
983+ logger .info (
984+ "Search on page #%s skipped since it was already requested" ,
985+ iteration ,
982986 )
983- except Exception :
984- products = SearchResult ([])
985- finally :
986- # we don't want that next(search_iter_page(...)) modifies the plugin
987- # indefinitely. So we reset after each request, but before the generator
988- # yields, the attr next_page_url (to None) and
989- # config.pagination["next_page_url_tpl"] (to its original value).
990- next_page_url = getattr (search_plugin , "next_page_url" , None )
991- next_page_query_obj = getattr (search_plugin , "next_page_query_obj" , {})
992- next_page_merge = getattr (search_plugin , "next_page_merge" , None )
993-
994- if next_page_url :
995- search_plugin .next_page_url = None
996- if prev_next_page_url_tpl :
997- search_plugin .config .pagination [
998- "next_page_url_tpl"
999- ] = prev_next_page_url_tpl
1000- if next_page_query_obj :
1001- if prev_next_page_query_obj :
1002- search_plugin .config .pagination [
1003- "next_page_query_obj"
1004- ] = prev_next_page_query_obj
1005- # Update next_page_query_obj for next page req
1006- if next_page_merge :
1007- search_plugin .next_page_query_obj = dict (
1008- getattr (search_plugin , "query_params" , {}),
1009- ** next_page_query_obj ,
1010- )
1011- else :
1012- search_plugin .next_page_query_obj = next_page_query_obj
1013-
1014- if len (products ) > 0 :
1015- # The first products between two iterations are compared. If they
1016- # are actually the same product, it means the iteration failed at
1017- # progressing for some reason. This is implemented as a workaround
1018- # to some search plugins/providers not handling pagination.
1019- product = products [0 ]
1020- if (
1021- prev_product
1022- and product .properties ["id" ] == prev_product .properties ["id" ]
1023- and product .provider == prev_product .provider
1024- ):
1025- logger .warning (
1026- "Iterate over pages: stop iterating since the next page "
1027- "appears to have the same products as in the previous one. "
1028- "This provider may not implement pagination." ,
987+ else :
988+ try :
989+ products , _ = self ._do_search (
990+ search_plugin , count = False , raise_errors = True , ** search_kwargs
991+ )
992+ except Exception :
993+ products = SearchResult ([])
994+ finally :
995+ # we don't want that next(search_iter_page(...)) modifies the plugin
996+ # indefinitely. So we reset after each request, but before the generator
997+ # yields, the attr next_page_url (to None) and
998+ # config.pagination["next_page_url_tpl"] (to its original value).
999+ next_page_url = getattr (search_plugin , "next_page_url" , None )
1000+ next_page_query_obj = getattr (
1001+ search_plugin , "next_page_query_obj" , {}
10291002 )
1003+ next_page_merge = getattr (search_plugin , "next_page_merge" , None )
1004+
1005+ if next_page_url :
1006+ search_plugin .next_page_url = None
1007+ if prev_next_page_url_tpl :
1008+ search_plugin .config .pagination [
1009+ "next_page_url_tpl"
1010+ ] = prev_next_page_url_tpl
1011+ if next_page_query_obj :
1012+ if prev_next_page_query_obj :
1013+ search_plugin .config .pagination [
1014+ "next_page_query_obj"
1015+ ] = prev_next_page_query_obj
1016+ # Update next_page_query_obj for next page req
1017+ if next_page_merge :
1018+ search_plugin .next_page_query_obj = dict (
1019+ getattr (search_plugin , "query_params" , {}),
1020+ ** next_page_query_obj ,
1021+ )
1022+ else :
1023+ search_plugin .next_page_query_obj = next_page_query_obj
1024+
1025+ if len (products ) > 0 :
1026+ # The first products between two iterations are compared. If they
1027+ # are actually the same product, it means the iteration failed at
1028+ # progressing for some reason. This is implemented as a workaround
1029+ # to some search plugins/providers not handling pagination.
1030+ product = products [0 ]
1031+ if (
1032+ prev_product
1033+ and product .properties ["id" ] == prev_product .properties ["id" ]
1034+ and product .provider == prev_product .provider
1035+ ):
1036+ logger .warning (
1037+ "Iterate over pages: stop iterating since the next page "
1038+ "appears to have the same products as in the previous one. "
1039+ "This provider may not implement pagination." ,
1040+ )
1041+ last_page_with_products = iteration - 1
1042+ break
1043+ yield products
1044+ prev_product = product
1045+ # Prevent a last search if the current one returned less than the
1046+ # maximum number of items asked for.
1047+ if len (products ) < items_per_page :
1048+ last_page_with_products = iteration
1049+ break
1050+ else :
10301051 last_page_with_products = iteration - 1
10311052 break
1032- yield products
1033- prev_product = product
1034- # Prevent a last search if the current one returned less than the
1035- # maximum number of items asked for.
1036- if len (products ) < items_per_page :
1037- last_page_with_products = iteration
1038- break
1039- else :
1040- last_page_with_products = iteration - 1
1041- break
10421053 iteration += 1
10431054 search_kwargs ["page" ] = iteration
10441055 logger .debug (
@@ -1360,7 +1371,10 @@ def _prepare_search(
13601371 logger .debug (
13611372 "Using plugin class for search: %s" , search_plugin .__class__ .__name__
13621373 )
1363- auth_plugin = self ._plugins_manager .get_auth_plugin (search_plugin .provider )
1374+ # get auth plugin by preventing possible multiple "auth" key in the return value
1375+ auth_plugin = kwargs .pop (
1376+ "auth" , self ._plugins_manager .get_auth_plugin (search_plugin .provider )
1377+ )
13641378
13651379 # append auth to search plugin if needed
13661380 if getattr (search_plugin .config , "need_auth" , False ) and callable (
@@ -1529,7 +1543,10 @@ def _do_search(self, search_plugin, count=True, raise_errors=False, **kwargs):
15291543 "Error while searching on provider %s (ignored):" ,
15301544 search_plugin .provider ,
15311545 )
1532- return SearchResult (results ), total_results
1546+ results .search_kwargs = kwargs
1547+ if kwargs not in self .search_kwargs_list :
1548+ self .search_kwargs_list .append (kwargs )
1549+ return results , total_results
15331550
15341551 def crunch (self , results , ** kwargs ):
15351552 """Apply the filters given through the keyword arguments to the results
@@ -1604,24 +1621,26 @@ def download_all(
16041621 :param timeout: (optional) If download fails, maximum time in minutes
16051622 before stop retrying to download
16061623 :type timeout: int
1607- :param kwargs: `outputs_prefix` (str), `extract` (bool), `delete_archive` (bool)
1608- and `dl_url_params` (dict) can be provided as additional kwargs
1609- and will override any other values defined in a configuration
1610- file or with environment variables.
1624+ :param kwargs: `outputs_prefix` (str), `extract` (bool), `delete_archive` (bool),
1625+ `dl_url_params` (dict) and `exhaust` (bool) can be provided as
1626+ additional kwargs and will override any other values defined in a
1627+ configuration file or with environment variables.
16111628 :type kwargs: Union[str, bool, dict]
16121629 :returns: A collection of the absolute paths to the downloaded products
16131630 :rtype: list
16141631 """
16151632 paths = []
16161633 if search_result :
1617- logger .info ("Downloading %s products" , len (search_result ))
1634+ if not kwargs .get ("exhaust" , False ):
1635+ logger .info ("Downloading %s products" , len (search_result ))
16181636 # Get download plugin using first product assuming product from several provider
16191637 # aren't mixed into a search result
16201638 download_plugin = self ._plugins_manager .get_download_plugin (
16211639 search_result [0 ]
16221640 )
16231641 paths = download_plugin .download_all (
16241642 search_result ,
1643+ self ,
16251644 downloaded_callback = downloaded_callback ,
16261645 progress_callback = progress_callback ,
16271646 wait = wait ,
0 commit comments