2626from importlib .metadata import version
2727from importlib .resources import files as res_files
2828from operator import itemgetter
29- from typing import TYPE_CHECKING , Any , Iterator , Optional , Union
29+ from typing import TYPE_CHECKING , Any , Iterator , Optional , Union , cast
3030
3131import geojson
3232import yaml
3333
34- from eodag .api .plugin import PluginConfig , credentials_in_auth
34+ from eodag .api .plugin import DiscoverProductTypes , PluginConfig , credentials_in_auth
3535from eodag .api .product .metadata_mapping import mtd_cfg_as_conversion_and_querypath
3636from eodag .api .provider import Provider , ProvidersDict
3737from eodag .api .search_result import SearchResult
@@ -188,7 +188,7 @@ def get_version(self) -> str:
188188 """Get eodag package version"""
189189 return version ("eodag" )
190190
191- def set_preferred_provider (self , provider : str | Provider ) -> None :
191+ def set_preferred_provider (self , provider : str ) -> None :
192192 """Set max priority for the given provider.
193193
194194 :param provider: The name of the provider that should be considered as the
@@ -204,7 +204,7 @@ def set_preferred_provider(self, provider: str | Provider) -> None:
204204 new_priority = max_priority + 1
205205 self ._plugins_manager .set_priority (provider , new_priority )
206206
207- def get_preferred_provider (self ) -> tuple [Provider , int ]:
207+ def get_preferred_provider (self ) -> tuple [str , int ]:
208208 """Get the provider currently set as the preferred one for searching
209209 products, along with its priority.
210210
@@ -232,14 +232,14 @@ def update_providers_config(
232232 return None
233233
234234 # restore the pruned configuration
235- for provider , config in self ._pruned_providers_config .items ():
236- if provider in conf_update :
235+ for name in list (self ._pruned_providers_config ):
236+ config = self ._pruned_providers_config [name ]
237+ if name in conf_update :
237238 logger .info (
238- "%s: provider restored from the pruned configurations" ,
239- provider ,
239+ "%s: provider restored from the pruned configurations" , name
240240 )
241- self .providers [provider ] = Provider (provider , config )
242- self ._pruned_providers_config .pop (provider )
241+ self .providers [name ] = Provider (config , name )
242+ self ._pruned_providers_config .pop (name )
243243
244244 self .providers .update_from_configs (conf_update )
245245
@@ -351,7 +351,7 @@ def _prune_providers_list(self) -> None:
351351 elif hasattr (conf , "search" ) and getattr (conf .search , "need_auth" , False ):
352352 if not hasattr (conf , "auth" ) and not hasattr (conf , "search_auth" ):
353353 # credentials needed but no auth plugin was found
354- self ._pruned_providers_config [provider ] = conf
354+ self ._pruned_providers_config [provider . name ] = conf
355355 del self .providers [provider .name ]
356356
357357 update_needed = True
@@ -371,7 +371,7 @@ def _prune_providers_list(self) -> None:
371371 )
372372 if not credentials_exist :
373373 # credentials needed but not found
374- self ._pruned_providers_config [provider ] = conf
374+ self ._pruned_providers_config [provider . name ] = conf
375375 del self .providers [provider .name ]
376376
377377 update_needed = True
@@ -382,7 +382,7 @@ def _prune_providers_list(self) -> None:
382382
383383 elif not hasattr (conf , "api" ) and not hasattr (conf , "search" ):
384384 # provider should have at least an api or search plugin
385- self ._pruned_providers_config [provider ] = conf
385+ self ._pruned_providers_config [provider . name ] = conf
386386 del self .providers [provider .name ]
387387
388388 update_needed = True
@@ -516,13 +516,13 @@ def fetch_product_types_list(self, provider: Optional[str] = None) -> None:
516516 providers_to_fetch = self .providers .filter_by_name (provider )
517517
518518 # providers discovery confs that are fetchable
519- providers_discovery_configs_fetchable : dict [str , Any ] = {}
519+ providers_discovery_configs_fetchable : dict [str , DiscoverProductTypes ] = {}
520520 # check if any provider has not already been fetched for product types
521521 already_fetched = True
522522 for provider_to_fetch in providers_to_fetch .values ():
523- if provider_to_fetch .fetchable :
523+ if provider_to_fetch .fetchable and provider_to_fetch . search_config :
524524 providers_discovery_configs_fetchable [
525- provider_to_fetch
525+ provider_to_fetch . name
526526 ] = provider_to_fetch .search_config .discover_product_types
527527 if not provider_to_fetch .product_types_fetched :
528528 already_fetched = False
@@ -569,33 +569,36 @@ def fetch_product_types_list(self, provider: Optional[str] = None) -> None:
569569 if default_discovery_conf ["result_type" ] == "json" and isinstance (
570570 default_discovery_conf ["results_entry" ], str
571571 ):
572- default_discovery_conf_parsed = dict (
573- default_discovery_conf ,
574- ** {
575- "results_entry" : string_to_jsonpath (
576- default_discovery_conf ["results_entry" ], force = True
577- )
578- },
579- ** mtd_cfg_as_conversion_and_querypath (
580- dict (
581- generic_product_type_id = default_discovery_conf [
582- "generic_product_type_id"
583- ]
584- )
585- ),
586- ** dict (
587- generic_product_type_parsable_properties = mtd_cfg_as_conversion_and_querypath (
588- default_discovery_conf [
589- "generic_product_type_parsable_properties"
590- ]
591- )
592- ),
593- ** dict (
594- generic_product_type_parsable_metadata = mtd_cfg_as_conversion_and_querypath (
595- default_discovery_conf [
596- "generic_product_type_parsable_metadata"
597- ]
598- )
572+ default_discovery_conf_parsed = cast (
573+ DiscoverProductTypes ,
574+ dict (
575+ default_discovery_conf ,
576+ ** {
577+ "results_entry" : string_to_jsonpath (
578+ default_discovery_conf ["results_entry" ], force = True
579+ )
580+ },
581+ ** mtd_cfg_as_conversion_and_querypath (
582+ dict (
583+ generic_product_type_id = default_discovery_conf [
584+ "generic_product_type_id"
585+ ]
586+ )
587+ ),
588+ ** dict (
589+ generic_product_type_parsable_properties = mtd_cfg_as_conversion_and_querypath (
590+ default_discovery_conf [
591+ "generic_product_type_parsable_properties"
592+ ]
593+ )
594+ ),
595+ ** dict (
596+ generic_product_type_parsable_metadata = mtd_cfg_as_conversion_and_querypath (
597+ default_discovery_conf [
598+ "generic_product_type_parsable_metadata"
599+ ]
600+ )
601+ ),
599602 ),
600603 )
601604 else :
@@ -650,7 +653,7 @@ def discover_product_types(
650653
651654 if p .fetchable :
652655 search_plugin : Union [Search , Api ] = next (
653- self ._plugins_manager .get_search_plugins (provider = p )
656+ self ._plugins_manager .get_search_plugins (provider = p . name )
654657 )
655658
656659 # check after plugin init if still fetchable
@@ -671,10 +674,10 @@ def discover_product_types(
671674 logger .debug (
672675 f"Could not authenticate on { p } for product types discovery"
673676 )
674- ext_product_types_conf [p ] = None
677+ ext_product_types_conf [p . name ] = None
675678 continue
676679
677- ext_product_types_conf [p ] = search_plugin .discover_product_types (
680+ ext_product_types_conf [p . name ] = search_plugin .discover_product_types (
678681 ** kwargs
679682 )
680683
@@ -763,7 +766,7 @@ def update_product_types_list(
763766
764767 def available_providers (
765768 self , product_type : Optional [str ] = None , by_group : bool = False
766- ) -> ProvidersDict :
769+ ) -> list [ str ] :
767770 """Gives the sorted list of the available providers or groups
768771
769772 The providers or groups are sorted first by their priority level in descending order,
@@ -775,32 +778,28 @@ def available_providers(
775778 of providers, mixed with other providers
776779 :returns: the sorted list of the available providers or groups
777780 """
781+ candidates = []
778782
779- if product_type :
780- providers = [
781- (v .group if by_group and hasattr (v .config , "group" ) else k , v .priority )
782- for k , v in self .providers .items ()
783- if product_type in v .products
784- ]
785- else :
786- providers = [
787- (v .group if by_group and hasattr (v .config , "group" ) else k , v .priority )
788- for k , v in self .providers .items ()
789- ]
783+ for key , provider in self .providers .items ():
784+ if product_type and product_type not in provider .product_types :
785+ continue
786+
787+ group = getattr (provider .config , "group" , None )
788+ name = group if by_group and group else key
789+ candidates .append ((name , provider .priority ))
790790
791- # If by_group is True, keep only the highest priority for each group
792791 if by_group :
793- group_priority : dict [str , int ] = {}
794- for name , priority in providers :
795- if name not in group_priority or priority > group_priority [name ]:
796- group_priority [name ] = priority
797- providers = list (group_priority .items ())
792+ # Keep only the highest-priority entry per group
793+ grouped : dict [str , int ] = {}
794+ for name , priority in candidates :
795+ if name not in grouped or priority > grouped [name ]:
796+ grouped [name ] = priority
797+ candidates = list (grouped .items ())
798798
799- # Sort by priority ( descending) and then by name ( ascending)
800- providers .sort (key = lambda x : (- x [1 ], x [0 ]))
799+ # Sort: priority descending, then name ascending
800+ candidates .sort (key = lambda item : (- item [1 ], item [0 ]))
801801
802- # Return only the names of the providers or groups
803- return [name for name , _ in providers ]
802+ return [name for name , _ in candidates ]
804803
805804 def get_product_type_from_alias (self , alias_or_id : str ) -> str :
806805 """Return the ID of a product type by either its ID or alias
0 commit comments