-
Notifications
You must be signed in to change notification settings - Fork 51
feat(plugins): allow multiple download or auth plugins for a single provider #1704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
a2a269c
ef26829
9c70f2f
4fd8ffb
7159eee
b9955d4
fd4c5ba
3e10237
5081cbb
1037b65
d93c26a
3d76b87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -29,7 +29,7 @@ | |||||||||||||||||||||||||||||||||
| from typing import TYPE_CHECKING, Any, Iterator, Optional, Union | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import geojson | ||||||||||||||||||||||||||||||||||
| import yaml.parser | ||||||||||||||||||||||||||||||||||
| import yaml | ||||||||||||||||||||||||||||||||||
| from whoosh import analysis, fields | ||||||||||||||||||||||||||||||||||
| from whoosh.fields import Schema | ||||||||||||||||||||||||||||||||||
| from whoosh.index import exists_in, open_dir | ||||||||||||||||||||||||||||||||||
|
|
@@ -463,7 +463,7 @@ def add_provider( | |||||||||||||||||||||||||||||||||
| products: dict[str, Any] = { | ||||||||||||||||||||||||||||||||||
| GENERIC_PRODUCT_TYPE: {"productType": "{productType}"} | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| download: dict[str, Any] = {"type": "HTTPDownload", "auth_error_code": 401}, | ||||||||||||||||||||||||||||||||||
| download: list[dict[str, Any]] = [], | ||||||||||||||||||||||||||||||||||
| **kwargs: dict[str, Any], | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please replace |
||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| """Adds a new provider. | ||||||||||||||||||||||||||||||||||
|
|
@@ -480,9 +480,11 @@ def add_provider( | |||||||||||||||||||||||||||||||||
| :param priority: Provider priority. If None, provider will be set as preferred (highest priority) | ||||||||||||||||||||||||||||||||||
| :param search: Search :class:`~eodag.config.PluginConfig` mapping | ||||||||||||||||||||||||||||||||||
| :param products: Provider product types mapping | ||||||||||||||||||||||||||||||||||
| :param download: Download :class:`~eodag.config.PluginConfig` mapping | ||||||||||||||||||||||||||||||||||
| :param download: list of Download :class:`~eodag.config.PluginConfig` mapping | ||||||||||||||||||||||||||||||||||
| :param kwargs: Additional :class:`~eodag.config.ProviderConfig` mapping | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
| if not download: | ||||||||||||||||||||||||||||||||||
| download.extend([{"type": "HTTPDownload", "auth_error_code": 401}]) | ||||||||||||||||||||||||||||||||||
| conf_dict: dict[str, Any] = { | ||||||||||||||||||||||||||||||||||
| name: { | ||||||||||||||||||||||||||||||||||
| "url": url, | ||||||||||||||||||||||||||||||||||
|
|
@@ -491,11 +493,7 @@ def add_provider( | |||||||||||||||||||||||||||||||||
| GENERIC_PRODUCT_TYPE: {"productType": "{productType}"}, | ||||||||||||||||||||||||||||||||||
| **products, | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| "download": { | ||||||||||||||||||||||||||||||||||
| "type": "HTTPDownload", | ||||||||||||||||||||||||||||||||||
| "auth_error_code": 401, | ||||||||||||||||||||||||||||||||||
| **download, | ||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||
| "download": download, | ||||||||||||||||||||||||||||||||||
| **kwargs, | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
@@ -552,36 +550,27 @@ def _prune_providers_list(self) -> None: | |||||||||||||||||||||||||||||||||
| "%s: provider needing auth for search has been pruned because no credentials could be found", | ||||||||||||||||||||||||||||||||||
| provider, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| elif hasattr(conf, "search") and getattr(conf.search, "need_auth", False): | ||||||||||||||||||||||||||||||||||
| if not hasattr(conf, "auth") and not hasattr(conf, "search_auth"): | ||||||||||||||||||||||||||||||||||
| # credentials needed but no auth plugin was found | ||||||||||||||||||||||||||||||||||
| self._pruned_providers_config[provider] = self.providers_config.pop( | ||||||||||||||||||||||||||||||||||
| provider | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| update_needed = True | ||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||
| "%s: provider needing auth for search has been pruned because no auth plugin could be found", | ||||||||||||||||||||||||||||||||||
| provider, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| elif hasattr(conf, "search"): | ||||||||||||||||||||||||||||||||||
| if not hasattr(conf, "auth"): | ||||||||||||||||||||||||||||||||||
| # no auth plugin found -> we assume that no auth is necessary | ||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||
| credentials_exist = ( | ||||||||||||||||||||||||||||||||||
| hasattr(conf, "search_auth") | ||||||||||||||||||||||||||||||||||
| and credentials_in_auth(conf.search_auth) | ||||||||||||||||||||||||||||||||||
| ) or ( | ||||||||||||||||||||||||||||||||||
| not hasattr(conf, "search_auth") | ||||||||||||||||||||||||||||||||||
| and hasattr(conf, "auth") | ||||||||||||||||||||||||||||||||||
| and credentials_in_auth(conf.auth) | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| if not credentials_exist: | ||||||||||||||||||||||||||||||||||
| # credentials needed but not found | ||||||||||||||||||||||||||||||||||
| self._pruned_providers_config[provider] = self.providers_config.pop( | ||||||||||||||||||||||||||||||||||
| provider | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| update_needed = True | ||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||
| "%s: provider needing auth for search has been pruned because no credentials could be found", | ||||||||||||||||||||||||||||||||||
| provider, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| for auth_config in conf.auth: | ||||||||||||||||||||||||||||||||||
| if "search" not in getattr(auth_config, "required_for", []): | ||||||||||||||||||||||||||||||||||
| # plugin not required for search | ||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||
| credentials_exist = credentials_in_auth(auth_config) | ||||||||||||||||||||||||||||||||||
| if not credentials_exist: | ||||||||||||||||||||||||||||||||||
| update_needed = True | ||||||||||||||||||||||||||||||||||
| logger.info( | ||||||||||||||||||||||||||||||||||
| "%s: provider needing auth for search has been pruned because " | ||||||||||||||||||||||||||||||||||
| "no credentials could be found", | ||||||||||||||||||||||||||||||||||
| provider, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| self._pruned_providers_config[ | ||||||||||||||||||||||||||||||||||
| provider | ||||||||||||||||||||||||||||||||||
| ] = self.providers_config.pop(provider) | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+564
to
+571
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| elif not hasattr(conf, "api") and not hasattr(conf, "search"): | ||||||||||||||||||||||||||||||||||
| # provider should have at least an api or search plugin | ||||||||||||||||||||||||||||||||||
| self._pruned_providers_config[provider] = self.providers_config.pop( | ||||||||||||||||||||||||||||||||||
|
|
@@ -891,20 +880,18 @@ def discover_product_types( | |||||||||||||||||||||||||||||||||
| "fetch_url" | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||
| # append auth to search plugin if needed | ||||||||||||||||||||||||||||||||||
| if getattr(search_plugin.config, "need_auth", False): | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| search_plugin.provider, | ||||||||||||||||||||||||||||||||||
| getattr(search_plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| search_plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| kwargs["auth"] = auth | ||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||
| f"Could not authenticate on {provider} for product types discovery" | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| ext_product_types_conf[provider] = None | ||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||
| # append auth to search plugin if available | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| search_plugin.provider, | ||||||||||||||||||||||||||||||||||
| "search", | ||||||||||||||||||||||||||||||||||
| getattr(search_plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| search_plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| kwargs["auth"] = auth | ||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||
| f"No authentication plugin for {provider} for product types discovery found" | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ext_product_types_conf[provider] = search_plugin.discover_product_types( | ||||||||||||||||||||||||||||||||||
| **kwargs | ||||||||||||||||||||||||||||||||||
|
|
@@ -1708,14 +1695,14 @@ def _fetch_external_product_type(self, provider: str, product_type: str): | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| kwargs: dict[str, Any] = {"productType": product_type} | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # append auth if needed | ||||||||||||||||||||||||||||||||||
| if getattr(plugin.config, "need_auth", False): | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| plugin.provider, | ||||||||||||||||||||||||||||||||||
| getattr(plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| kwargs["auth"] = auth | ||||||||||||||||||||||||||||||||||
| # append auth if available | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| plugin.provider, | ||||||||||||||||||||||||||||||||||
| "search", | ||||||||||||||||||||||||||||||||||
| getattr(plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| kwargs["auth"] = auth | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| product_type_config = plugin.discover_product_types(**kwargs) | ||||||||||||||||||||||||||||||||||
| self.update_product_types_list({provider: product_type_config}) | ||||||||||||||||||||||||||||||||||
|
|
@@ -1914,15 +1901,14 @@ def _do_search( | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| prep = PreparedSearch(count=count) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # append auth if needed | ||||||||||||||||||||||||||||||||||
| if getattr(search_plugin.config, "need_auth", False): | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| search_plugin.provider, | ||||||||||||||||||||||||||||||||||
| getattr(search_plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| search_plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| prep.auth = auth | ||||||||||||||||||||||||||||||||||
| # append auth if available | ||||||||||||||||||||||||||||||||||
| if auth := self._plugins_manager.get_auth( | ||||||||||||||||||||||||||||||||||
| search_plugin.provider, | ||||||||||||||||||||||||||||||||||
| "search", | ||||||||||||||||||||||||||||||||||
| getattr(search_plugin.config, "api_endpoint", None), | ||||||||||||||||||||||||||||||||||
| search_plugin.config, | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| prep.auth = auth | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| prep.page = kwargs.pop("page", None) | ||||||||||||||||||||||||||||||||||
| prep.items_per_page = kwargs.pop("items_per_page", None) | ||||||||||||||||||||||||||||||||||
|
|
@@ -2372,9 +2358,8 @@ def list_queryables( | |||||||||||||||||||||||||||||||||
| product_type_configs[pt] = plugin.config.product_type_config | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| # authenticate if required | ||||||||||||||||||||||||||||||||||
| if getattr(plugin.config, "need_auth", False) and ( | ||||||||||||||||||||||||||||||||||
| auth := self._plugins_manager.get_auth_plugin(plugin) | ||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||
| auth = self._plugins_manager.get_auth_plugin(plugin) | ||||||||||||||||||||||||||||||||||
| if auth and "search" in getattr(auth, "required_for", []): | ||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||
| plugin.auth = auth.authenticate() | ||||||||||||||||||||||||||||||||||
| except AuthenticationError: | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use
Noneas default value instead of[]Please also use
Noneas search default, and apply default value in code.See https://docs.astral.sh/ruff/rules/mutable-argument-default/