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
3534from eodag .api .product .metadata_mapping import mtd_cfg_as_conversion_and_querypath
3635from eodag .api .provider import Provider , ProvidersDict
3736from eodag .api .search_result import SearchResult
3837from eodag .config import (
3938 PLUGINS_TOPICS_KEYS ,
39+ DiscoverProductTypes ,
40+ PluginConfig ,
4041 SimpleYamlProxyConfig ,
42+ credentials_in_auth ,
4143 get_ext_product_types_conf ,
4244 load_default_config ,
4345 load_yml_config ,
@@ -188,7 +190,7 @@ def get_version(self) -> str:
188190 """Get eodag package version"""
189191 return version ("eodag" )
190192
191- def set_preferred_provider (self , provider : str | Provider ) -> None :
193+ def set_preferred_provider (self , provider : str ) -> None :
192194 """Set max priority for the given provider.
193195
194196 :param provider: The name of the provider that should be considered as the
@@ -204,7 +206,7 @@ def set_preferred_provider(self, provider: str | Provider) -> None:
204206 new_priority = max_priority + 1
205207 self ._plugins_manager .set_priority (provider , new_priority )
206208
207- def get_preferred_provider (self ) -> tuple [Provider , int ]:
209+ def get_preferred_provider (self ) -> tuple [str , int ]:
208210 """Get the provider currently set as the preferred one for searching
209211 products, along with its priority.
210212
@@ -232,14 +234,14 @@ def update_providers_config(
232234 return None
233235
234236 # restore the pruned configuration
235- for provider , config in self ._pruned_providers_config .items ():
236- if provider in conf_update :
237+ for name in list (self ._pruned_providers_config ):
238+ config = self ._pruned_providers_config [name ]
239+ if name in conf_update :
237240 logger .info (
238- "%s: provider restored from the pruned configurations" ,
239- provider ,
241+ "%s: provider restored from the pruned configurations" , name
240242 )
241- self .providers [provider ] = Provider (provider , config )
242- self ._pruned_providers_config .pop (provider )
243+ self .providers [name ] = Provider (config , name )
244+ self ._pruned_providers_config .pop (name )
243245
244246 self .providers .update_from_configs (conf_update )
245247
@@ -351,7 +353,7 @@ def _prune_providers_list(self) -> None:
351353 elif hasattr (conf , "search" ) and getattr (conf .search , "need_auth" , False ):
352354 if not hasattr (conf , "auth" ) and not hasattr (conf , "search_auth" ):
353355 # credentials needed but no auth plugin was found
354- self ._pruned_providers_config [provider ] = conf
356+ self ._pruned_providers_config [provider . name ] = conf
355357 del self .providers [provider .name ]
356358
357359 update_needed = True
@@ -371,7 +373,7 @@ def _prune_providers_list(self) -> None:
371373 )
372374 if not credentials_exist :
373375 # credentials needed but not found
374- self ._pruned_providers_config [provider ] = conf
376+ self ._pruned_providers_config [provider . name ] = conf
375377 del self .providers [provider .name ]
376378
377379 update_needed = True
@@ -382,7 +384,7 @@ def _prune_providers_list(self) -> None:
382384
383385 elif not hasattr (conf , "api" ) and not hasattr (conf , "search" ):
384386 # provider should have at least an api or search plugin
385- self ._pruned_providers_config [provider ] = conf
387+ self ._pruned_providers_config [provider . name ] = conf
386388 del self .providers [provider .name ]
387389
388390 update_needed = True
@@ -516,13 +518,13 @@ def fetch_product_types_list(self, provider: Optional[str] = None) -> None:
516518 providers_to_fetch = self .providers .filter_by_name (provider )
517519
518520 # providers discovery confs that are fetchable
519- providers_discovery_configs_fetchable : dict [str , Any ] = {}
521+ providers_discovery_configs_fetchable : dict [str , DiscoverProductTypes ] = {}
520522 # check if any provider has not already been fetched for product types
521523 already_fetched = True
522524 for provider_to_fetch in providers_to_fetch .values ():
523- if provider_to_fetch .fetchable :
525+ if provider_to_fetch .fetchable and provider_to_fetch . search_config :
524526 providers_discovery_configs_fetchable [
525- provider_to_fetch
527+ provider_to_fetch . name
526528 ] = provider_to_fetch .search_config .discover_product_types
527529 if not provider_to_fetch .product_types_fetched :
528530 already_fetched = False
@@ -569,33 +571,36 @@ def fetch_product_types_list(self, provider: Optional[str] = None) -> None:
569571 if default_discovery_conf ["result_type" ] == "json" and isinstance (
570572 default_discovery_conf ["results_entry" ], str
571573 ):
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- )
574+ default_discovery_conf_parsed = cast (
575+ DiscoverProductTypes ,
576+ dict (
577+ default_discovery_conf ,
578+ ** {
579+ "results_entry" : string_to_jsonpath (
580+ default_discovery_conf ["results_entry" ], force = True
581+ )
582+ },
583+ ** mtd_cfg_as_conversion_and_querypath (
584+ dict (
585+ generic_product_type_id = default_discovery_conf [
586+ "generic_product_type_id"
587+ ]
588+ )
589+ ),
590+ ** dict (
591+ generic_product_type_parsable_properties = mtd_cfg_as_conversion_and_querypath (
592+ default_discovery_conf [
593+ "generic_product_type_parsable_properties"
594+ ]
595+ )
596+ ),
597+ ** dict (
598+ generic_product_type_parsable_metadata = mtd_cfg_as_conversion_and_querypath (
599+ default_discovery_conf [
600+ "generic_product_type_parsable_metadata"
601+ ]
602+ )
603+ ),
599604 ),
600605 )
601606 else :
@@ -650,7 +655,7 @@ def discover_product_types(
650655
651656 if p .fetchable :
652657 search_plugin : Union [Search , Api ] = next (
653- self ._plugins_manager .get_search_plugins (provider = p )
658+ self ._plugins_manager .get_search_plugins (provider = p . name )
654659 )
655660
656661 # check after plugin init if still fetchable
@@ -671,10 +676,10 @@ def discover_product_types(
671676 logger .debug (
672677 f"Could not authenticate on { p } for product types discovery"
673678 )
674- ext_product_types_conf [p ] = None
679+ ext_product_types_conf [p . name ] = None
675680 continue
676681
677- ext_product_types_conf [p ] = search_plugin .discover_product_types (
682+ ext_product_types_conf [p . name ] = search_plugin .discover_product_types (
678683 ** kwargs
679684 )
680685
@@ -763,7 +768,7 @@ def update_product_types_list(
763768
764769 def available_providers (
765770 self , product_type : Optional [str ] = None , by_group : bool = False
766- ) -> ProvidersDict :
771+ ) -> list [ str ] :
767772 """Gives the sorted list of the available providers or groups
768773
769774 The providers or groups are sorted first by their priority level in descending order,
@@ -775,32 +780,28 @@ def available_providers(
775780 of providers, mixed with other providers
776781 :returns: the sorted list of the available providers or groups
777782 """
783+ candidates = []
778784
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- ]
785+ for key , provider in self .providers .items ():
786+ if product_type and product_type not in provider .product_types :
787+ continue
788+
789+ group = getattr (provider .config , "group" , None )
790+ name = group if by_group and group else key
791+ candidates .append ((name , provider .priority ))
790792
791- # If by_group is True, keep only the highest priority for each group
792793 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 ())
794+ # Keep only the highest-priority entry per group
795+ grouped : dict [str , int ] = {}
796+ for name , priority in candidates :
797+ if name not in grouped or priority > grouped [name ]:
798+ grouped [name ] = priority
799+ candidates = list (grouped .items ())
798800
799- # Sort by priority ( descending) and then by name ( ascending)
800- providers .sort (key = lambda x : (- x [1 ], x [0 ]))
801+ # Sort: priority descending, then name ascending
802+ candidates .sort (key = lambda item : (- item [1 ], item [0 ]))
801803
802- # Return only the names of the providers or groups
803- return [name for name , _ in providers ]
804+ return [name for name , _ in candidates ]
804805
805806 def get_product_type_from_alias (self , alias_or_id : str ) -> str :
806807 """Return the ID of a product type by either its ID or alias
0 commit comments