eodag 3.0.0b3__py3-none-any.whl → 3.1.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eodag/api/core.py +292 -198
- eodag/api/product/_assets.py +6 -6
- eodag/api/product/_product.py +18 -18
- eodag/api/product/metadata_mapping.py +51 -14
- eodag/api/search_result.py +29 -3
- eodag/cli.py +57 -20
- eodag/config.py +413 -117
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +49 -16
- eodag/plugins/apis/usgs.py +30 -7
- eodag/plugins/authentication/aws_auth.py +14 -5
- eodag/plugins/authentication/base.py +10 -1
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +12 -4
- eodag/plugins/authentication/keycloak.py +41 -22
- eodag/plugins/authentication/oauth.py +11 -1
- eodag/plugins/authentication/openid_connect.py +178 -163
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +19 -2
- eodag/plugins/authentication/token.py +93 -15
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/crunch/base.py +4 -1
- eodag/plugins/crunch/filter_date.py +5 -2
- eodag/plugins/crunch/filter_latest_intersect.py +5 -4
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/crunch/filter_overlap.py +5 -7
- eodag/plugins/crunch/filter_property.py +6 -6
- eodag/plugins/download/aws.py +50 -34
- eodag/plugins/download/base.py +41 -50
- eodag/plugins/download/creodias_s3.py +40 -2
- eodag/plugins/download/http.py +221 -195
- eodag/plugins/download/s3rest.py +25 -25
- eodag/plugins/manager.py +168 -23
- eodag/plugins/search/base.py +106 -39
- eodag/plugins/search/build_search_result.py +1065 -324
- eodag/plugins/search/cop_marine.py +112 -29
- eodag/plugins/search/creodias_s3.py +45 -24
- eodag/plugins/search/csw.py +41 -1
- eodag/plugins/search/data_request_search.py +109 -9
- eodag/plugins/search/qssearch.py +549 -257
- eodag/plugins/search/static_stac_search.py +20 -21
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +577 -87
- eodag/resources/providers.yml +1619 -2776
- eodag/resources/stac.yml +3 -163
- eodag/resources/user_conf_template.yml +112 -97
- eodag/rest/config.py +1 -2
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +138 -98
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +55 -329
- eodag/rest/stac.py +93 -544
- eodag/rest/types/eodag_search.py +19 -8
- eodag/rest/types/queryables.py +6 -8
- eodag/rest/types/stac_search.py +11 -2
- eodag/rest/utils/__init__.py +3 -0
- eodag/types/__init__.py +71 -18
- eodag/types/download_args.py +3 -3
- eodag/types/queryables.py +180 -73
- eodag/types/search_args.py +3 -3
- eodag/types/whoosh.py +126 -0
- eodag/utils/__init__.py +147 -66
- eodag/utils/exceptions.py +47 -26
- eodag/utils/logging.py +37 -77
- eodag/utils/repr.py +65 -6
- eodag/utils/requests.py +11 -13
- eodag/utils/stac_reader.py +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/METADATA +80 -81
- eodag-3.1.0b1.dist-info/RECORD +108 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/entry_points.txt +4 -2
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag/utils/constraints.py +0 -244
- eodag-3.0.0b3.dist-info/RECORD +0 -110
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/top_level.txt +0 -0
eodag/api/core.py
CHANGED
|
@@ -17,29 +17,34 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import datetime
|
|
20
21
|
import logging
|
|
21
22
|
import os
|
|
22
23
|
import re
|
|
23
24
|
import shutil
|
|
24
25
|
import tempfile
|
|
25
26
|
from operator import itemgetter
|
|
26
|
-
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional,
|
|
27
|
+
from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple, Union
|
|
27
28
|
|
|
28
29
|
import geojson
|
|
29
30
|
import pkg_resources
|
|
30
31
|
import yaml.parser
|
|
31
32
|
from pkg_resources import resource_filename
|
|
32
|
-
from pydantic.fields import FieldInfo
|
|
33
33
|
from whoosh import analysis, fields
|
|
34
34
|
from whoosh.fields import Schema
|
|
35
|
-
from whoosh.index import
|
|
35
|
+
from whoosh.index import exists_in, open_dir
|
|
36
36
|
from whoosh.qparser import QueryParser
|
|
37
37
|
|
|
38
|
-
from eodag.api.product.metadata_mapping import
|
|
38
|
+
from eodag.api.product.metadata_mapping import (
|
|
39
|
+
ONLINE_STATUS,
|
|
40
|
+
mtd_cfg_as_conversion_and_querypath,
|
|
41
|
+
)
|
|
39
42
|
from eodag.api.search_result import SearchResult
|
|
40
43
|
from eodag.config import (
|
|
44
|
+
PLUGINS_TOPICS_KEYS,
|
|
41
45
|
PluginConfig,
|
|
42
46
|
SimpleYamlProxyConfig,
|
|
47
|
+
credentials_in_auth,
|
|
43
48
|
get_ext_product_types_conf,
|
|
44
49
|
load_default_config,
|
|
45
50
|
load_stac_provider_config,
|
|
@@ -48,13 +53,15 @@ from eodag.config import (
|
|
|
48
53
|
override_config_from_file,
|
|
49
54
|
override_config_from_mapping,
|
|
50
55
|
provider_config_init,
|
|
56
|
+
share_credentials,
|
|
51
57
|
)
|
|
52
58
|
from eodag.plugins.manager import PluginManager
|
|
53
59
|
from eodag.plugins.search import PreparedSearch
|
|
54
|
-
from eodag.plugins.search.build_search_result import
|
|
60
|
+
from eodag.plugins.search.build_search_result import MeteoblueSearch
|
|
61
|
+
from eodag.plugins.search.qssearch import PostJsonSearch
|
|
55
62
|
from eodag.types import model_fields_to_annotated
|
|
56
|
-
from eodag.types.queryables import CommonQueryables
|
|
57
|
-
from eodag.types.whoosh import EODAGQueryParser
|
|
63
|
+
from eodag.types.queryables import CommonQueryables, QueryablesDict
|
|
64
|
+
from eodag.types.whoosh import EODAGQueryParser, create_in
|
|
58
65
|
from eodag.utils import (
|
|
59
66
|
DEFAULT_DOWNLOAD_TIMEOUT,
|
|
60
67
|
DEFAULT_DOWNLOAD_WAIT,
|
|
@@ -65,7 +72,6 @@ from eodag.utils import (
|
|
|
65
72
|
HTTP_REQ_TIMEOUT,
|
|
66
73
|
MockResponse,
|
|
67
74
|
_deprecated,
|
|
68
|
-
copy_deepcopy,
|
|
69
75
|
get_geometry_from_various,
|
|
70
76
|
makedirs,
|
|
71
77
|
obj_md5sum,
|
|
@@ -76,7 +82,6 @@ from eodag.utils import (
|
|
|
76
82
|
from eodag.utils.exceptions import (
|
|
77
83
|
AuthenticationError,
|
|
78
84
|
EodagError,
|
|
79
|
-
MisconfiguredError,
|
|
80
85
|
NoMatchingProductType,
|
|
81
86
|
PluginImplementationError,
|
|
82
87
|
RequestError,
|
|
@@ -96,7 +101,7 @@ if TYPE_CHECKING:
|
|
|
96
101
|
from eodag.plugins.search.base import Search
|
|
97
102
|
from eodag.types import ProviderSortables
|
|
98
103
|
from eodag.types.download_args import DownloadConf
|
|
99
|
-
from eodag.utils import
|
|
104
|
+
from eodag.utils import DownloadedCallback, ProgressCallback, Unpack
|
|
100
105
|
|
|
101
106
|
logger = logging.getLogger("eodag.core")
|
|
102
107
|
|
|
@@ -166,10 +171,15 @@ class EODataAccessGateway:
|
|
|
166
171
|
# Second level override: From environment variables
|
|
167
172
|
override_config_from_env(self.providers_config)
|
|
168
173
|
|
|
174
|
+
# share credentials between updated plugins confs
|
|
175
|
+
share_credentials(self.providers_config)
|
|
176
|
+
|
|
169
177
|
# init updated providers conf
|
|
170
|
-
stac_provider_config = load_stac_provider_config()
|
|
171
178
|
for provider in self.providers_config.keys():
|
|
172
|
-
provider_config_init(
|
|
179
|
+
provider_config_init(
|
|
180
|
+
self.providers_config[provider],
|
|
181
|
+
load_stac_provider_config(),
|
|
182
|
+
)
|
|
173
183
|
|
|
174
184
|
# re-build _plugins_manager using up-to-date providers_config
|
|
175
185
|
self._plugins_manager.rebuild(self.providers_config)
|
|
@@ -197,9 +207,10 @@ class EODataAccessGateway:
|
|
|
197
207
|
"eodag",
|
|
198
208
|
os.path.join("resources", "locations_conf_template.yml"),
|
|
199
209
|
)
|
|
200
|
-
with
|
|
201
|
-
|
|
202
|
-
|
|
210
|
+
with (
|
|
211
|
+
open(locations_conf_template) as infile,
|
|
212
|
+
open(locations_conf_path, "w") as outfile,
|
|
213
|
+
):
|
|
203
214
|
# The template contains paths in the form of:
|
|
204
215
|
# /path/to/locations/file.shp
|
|
205
216
|
path_template = "/path/to/locations/"
|
|
@@ -215,7 +226,6 @@ class EODataAccessGateway:
|
|
|
215
226
|
os.path.join(self.conf_dir, "shp"),
|
|
216
227
|
)
|
|
217
228
|
self.set_locations_conf(locations_conf_path)
|
|
218
|
-
self.search_errors: Set = set()
|
|
219
229
|
|
|
220
230
|
def get_version(self) -> str:
|
|
221
231
|
"""Get eodag package version"""
|
|
@@ -296,13 +306,18 @@ class EODataAccessGateway:
|
|
|
296
306
|
product_type, **{"md5": self.product_types_config_md5}
|
|
297
307
|
)
|
|
298
308
|
# add to index
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
309
|
+
try:
|
|
310
|
+
ix_writer.add_document(
|
|
311
|
+
**{
|
|
312
|
+
k: v
|
|
313
|
+
for k, v in versioned_product_type.items()
|
|
314
|
+
if k in product_types_schema.names()
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
except TypeError as e:
|
|
318
|
+
logger.error(
|
|
319
|
+
f"Cannot write product type {product_type['ID']} into index. e={e} product_type={product_type}"
|
|
320
|
+
)
|
|
306
321
|
ix_writer.commit()
|
|
307
322
|
|
|
308
323
|
def set_preferred_provider(self, provider: str) -> None:
|
|
@@ -333,14 +348,24 @@ class EODataAccessGateway:
|
|
|
333
348
|
preferred, priority = max(providers_with_priority, key=itemgetter(1))
|
|
334
349
|
return preferred, priority
|
|
335
350
|
|
|
336
|
-
def update_providers_config(
|
|
351
|
+
def update_providers_config(
|
|
352
|
+
self,
|
|
353
|
+
yaml_conf: Optional[str] = None,
|
|
354
|
+
dict_conf: Optional[Dict[str, Any]] = None,
|
|
355
|
+
) -> None:
|
|
337
356
|
"""Update providers configuration with given input.
|
|
338
357
|
Can be used to add a provider to existing configuration or update
|
|
339
358
|
an existing one.
|
|
340
359
|
|
|
341
360
|
:param yaml_conf: YAML formated provider configuration
|
|
361
|
+
:param dict_conf: provider configuration as dictionary in place of ``yaml_conf``
|
|
342
362
|
"""
|
|
343
|
-
|
|
363
|
+
if dict_conf is not None:
|
|
364
|
+
conf_update = dict_conf
|
|
365
|
+
elif yaml_conf is not None:
|
|
366
|
+
conf_update = yaml.safe_load(yaml_conf)
|
|
367
|
+
else:
|
|
368
|
+
return None
|
|
344
369
|
|
|
345
370
|
# restore the pruned configuration
|
|
346
371
|
for provider in list(self._pruned_providers_config.keys()):
|
|
@@ -355,9 +380,14 @@ class EODataAccessGateway:
|
|
|
355
380
|
|
|
356
381
|
override_config_from_mapping(self.providers_config, conf_update)
|
|
357
382
|
|
|
358
|
-
|
|
383
|
+
# share credentials between updated plugins confs
|
|
384
|
+
share_credentials(self.providers_config)
|
|
385
|
+
|
|
359
386
|
for provider in conf_update.keys():
|
|
360
|
-
provider_config_init(
|
|
387
|
+
provider_config_init(
|
|
388
|
+
self.providers_config[provider],
|
|
389
|
+
load_stac_provider_config(),
|
|
390
|
+
)
|
|
361
391
|
setattr(self.providers_config[provider], "product_types_fetched", False)
|
|
362
392
|
# re-create _plugins_manager using up-to-date providers_config
|
|
363
393
|
self._plugins_manager.build_product_type_to_provider_config_map()
|
|
@@ -419,14 +449,11 @@ class EODataAccessGateway:
|
|
|
419
449
|
|
|
420
450
|
# api plugin usage: remove unneeded search/download/auth plugin conf
|
|
421
451
|
if conf_dict[name].get("api"):
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
452
|
+
for k in PLUGINS_TOPICS_KEYS:
|
|
453
|
+
if k != "api":
|
|
454
|
+
conf_dict[name].pop(k, None)
|
|
425
455
|
|
|
426
|
-
|
|
427
|
-
provider_config_init(self.providers_config[name], load_stac_provider_config())
|
|
428
|
-
setattr(self.providers_config[name], "product_types_fetched", False)
|
|
429
|
-
self._plugins_manager.build_product_type_to_provider_config_map()
|
|
456
|
+
self.update_providers_config(dict_conf=conf_dict)
|
|
430
457
|
|
|
431
458
|
if priority is None:
|
|
432
459
|
self.set_preferred_provider(name)
|
|
@@ -452,12 +479,7 @@ class EODataAccessGateway:
|
|
|
452
479
|
|
|
453
480
|
# check authentication
|
|
454
481
|
if hasattr(conf, "api") and getattr(conf.api, "need_auth", False):
|
|
455
|
-
credentials_exist =
|
|
456
|
-
[
|
|
457
|
-
cred is not None
|
|
458
|
-
for cred in getattr(conf.api, "credentials", {}).values()
|
|
459
|
-
]
|
|
460
|
-
)
|
|
482
|
+
credentials_exist = credentials_in_auth(conf.api)
|
|
461
483
|
if not credentials_exist:
|
|
462
484
|
# credentials needed but not found
|
|
463
485
|
self._pruned_providers_config[provider] = self.providers_config.pop(
|
|
@@ -469,7 +491,7 @@ class EODataAccessGateway:
|
|
|
469
491
|
provider,
|
|
470
492
|
)
|
|
471
493
|
elif hasattr(conf, "search") and getattr(conf.search, "need_auth", False):
|
|
472
|
-
if not hasattr(conf, "auth"):
|
|
494
|
+
if not hasattr(conf, "auth") and not hasattr(conf, "search_auth"):
|
|
473
495
|
# credentials needed but no auth plugin was found
|
|
474
496
|
self._pruned_providers_config[provider] = self.providers_config.pop(
|
|
475
497
|
provider
|
|
@@ -480,11 +502,13 @@ class EODataAccessGateway:
|
|
|
480
502
|
provider,
|
|
481
503
|
)
|
|
482
504
|
continue
|
|
483
|
-
credentials_exist =
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
505
|
+
credentials_exist = (
|
|
506
|
+
hasattr(conf, "search_auth")
|
|
507
|
+
and credentials_in_auth(conf.search_auth)
|
|
508
|
+
) or (
|
|
509
|
+
not hasattr(conf, "search_auth")
|
|
510
|
+
and hasattr(conf, "auth")
|
|
511
|
+
and credentials_in_auth(conf.auth)
|
|
488
512
|
)
|
|
489
513
|
if not credentials_exist:
|
|
490
514
|
# credentials needed but not found
|
|
@@ -599,21 +623,32 @@ class EODataAccessGateway:
|
|
|
599
623
|
def fetch_product_types_list(self, provider: Optional[str] = None) -> None:
|
|
600
624
|
"""Fetch product types list and update if needed
|
|
601
625
|
|
|
602
|
-
:param provider:
|
|
603
|
-
should be updated. Defaults to all providers (None value).
|
|
626
|
+
:param provider: The name of a provider or provider-group for which product types
|
|
627
|
+
list should be updated. Defaults to all providers (None value).
|
|
604
628
|
"""
|
|
629
|
+
providers_to_fetch = list(self.providers_config.keys())
|
|
630
|
+
# check if some providers are grouped under a group name which is not a provider name
|
|
605
631
|
if provider is not None and provider not in self.providers_config:
|
|
606
|
-
|
|
632
|
+
providers_to_fetch = [
|
|
633
|
+
p
|
|
634
|
+
for p, pconf in self.providers_config.items()
|
|
635
|
+
if provider == getattr(pconf, "group", None)
|
|
636
|
+
]
|
|
637
|
+
if providers_to_fetch:
|
|
638
|
+
logger.info(
|
|
639
|
+
f"Fetch product types for {provider} group: {', '.join(providers_to_fetch)}"
|
|
640
|
+
)
|
|
641
|
+
else:
|
|
642
|
+
return None
|
|
643
|
+
elif provider is not None:
|
|
644
|
+
providers_to_fetch = [provider]
|
|
607
645
|
|
|
608
646
|
# providers discovery confs that are fetchable
|
|
609
647
|
providers_discovery_configs_fetchable: Dict[str, Any] = {}
|
|
610
648
|
# check if any provider has not already been fetched for product types
|
|
611
649
|
already_fetched = True
|
|
612
|
-
for provider_to_fetch
|
|
613
|
-
|
|
614
|
-
if provider
|
|
615
|
-
else self.providers_config.items()
|
|
616
|
-
):
|
|
650
|
+
for provider_to_fetch in providers_to_fetch:
|
|
651
|
+
provider_config = self.providers_config[provider_to_fetch]
|
|
617
652
|
# get discovery conf
|
|
618
653
|
if hasattr(provider_config, "search"):
|
|
619
654
|
provider_search_config = provider_config.search
|
|
@@ -735,11 +770,20 @@ class EODataAccessGateway:
|
|
|
735
770
|
) -> Optional[Dict[str, Any]]:
|
|
736
771
|
"""Fetch providers for product types
|
|
737
772
|
|
|
738
|
-
:param provider:
|
|
739
|
-
providers (None value).
|
|
773
|
+
:param provider: The name of a provider or provider-group to fetch. Defaults to
|
|
774
|
+
all providers (None value).
|
|
740
775
|
:returns: external product types configuration
|
|
741
776
|
"""
|
|
742
|
-
|
|
777
|
+
grouped_providers = [
|
|
778
|
+
p
|
|
779
|
+
for p, provider_config in self.providers_config.items()
|
|
780
|
+
if provider == getattr(provider_config, "group", None)
|
|
781
|
+
]
|
|
782
|
+
if provider and provider not in self.providers_config and grouped_providers:
|
|
783
|
+
logger.info(
|
|
784
|
+
f"Discover product types for {provider} group: {', '.join(grouped_providers)}"
|
|
785
|
+
)
|
|
786
|
+
elif provider and provider not in self.providers_config:
|
|
743
787
|
raise UnsupportedProvider(
|
|
744
788
|
f"The requested provider is not (yet) supported: {provider}"
|
|
745
789
|
)
|
|
@@ -748,7 +792,9 @@ class EODataAccessGateway:
|
|
|
748
792
|
p
|
|
749
793
|
for p in (
|
|
750
794
|
[
|
|
751
|
-
|
|
795
|
+
p
|
|
796
|
+
for p in self.providers_config
|
|
797
|
+
if p in grouped_providers + [provider]
|
|
752
798
|
]
|
|
753
799
|
if provider
|
|
754
800
|
else self.available_providers()
|
|
@@ -762,7 +808,9 @@ class EODataAccessGateway:
|
|
|
762
808
|
search_plugin_config = self.providers_config[provider].api
|
|
763
809
|
else:
|
|
764
810
|
return None
|
|
765
|
-
if getattr(search_plugin_config, "discover_product_types",
|
|
811
|
+
if getattr(search_plugin_config, "discover_product_types", {}).get(
|
|
812
|
+
"fetch_url", None
|
|
813
|
+
):
|
|
766
814
|
search_plugin: Union[Search, Api] = next(
|
|
767
815
|
self._plugins_manager.get_search_plugins(provider=provider)
|
|
768
816
|
)
|
|
@@ -773,23 +821,15 @@ class EODataAccessGateway:
|
|
|
773
821
|
continue
|
|
774
822
|
# append auth to search plugin if needed
|
|
775
823
|
if getattr(search_plugin.config, "need_auth", False):
|
|
776
|
-
|
|
777
|
-
search_plugin.provider
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
getattr(auth_plugin, "authenticate", None)
|
|
824
|
+
if auth := self._plugins_manager.get_auth(
|
|
825
|
+
search_plugin.provider,
|
|
826
|
+
getattr(search_plugin.config, "api_endpoint", None),
|
|
827
|
+
search_plugin.config,
|
|
781
828
|
):
|
|
782
|
-
|
|
783
|
-
kwargs["auth"] = auth_plugin.authenticate()
|
|
784
|
-
except (AuthenticationError, MisconfiguredError) as e:
|
|
785
|
-
logger.warning(
|
|
786
|
-
f"Could not authenticate on {provider}: {str(e)}"
|
|
787
|
-
)
|
|
788
|
-
ext_product_types_conf[provider] = None
|
|
789
|
-
continue
|
|
829
|
+
kwargs["auth"] = auth
|
|
790
830
|
else:
|
|
791
|
-
logger.
|
|
792
|
-
f"Could not authenticate on {provider}
|
|
831
|
+
logger.debug(
|
|
832
|
+
f"Could not authenticate on {provider} for product types discovery"
|
|
793
833
|
)
|
|
794
834
|
ext_product_types_conf[provider] = None
|
|
795
835
|
continue
|
|
@@ -815,7 +855,9 @@ class EODataAccessGateway:
|
|
|
815
855
|
) or getattr(self.providers_config[provider], "api", None)
|
|
816
856
|
if search_plugin_config is None:
|
|
817
857
|
continue
|
|
818
|
-
if not
|
|
858
|
+
if not getattr(
|
|
859
|
+
search_plugin_config, "discover_product_types", {}
|
|
860
|
+
).get("fetch_url", None):
|
|
819
861
|
# conf has been updated and provider product types are no more discoverable
|
|
820
862
|
continue
|
|
821
863
|
provider_products_config = (
|
|
@@ -874,7 +916,7 @@ class EODataAccessGateway:
|
|
|
874
916
|
new_product_types.append(new_product_type)
|
|
875
917
|
if new_product_types:
|
|
876
918
|
logger.debug(
|
|
877
|
-
f"Added
|
|
919
|
+
f"Added {len(new_product_types)} product types for {provider}"
|
|
878
920
|
)
|
|
879
921
|
|
|
880
922
|
elif provider not in self.providers_config:
|
|
@@ -1046,20 +1088,28 @@ class EODataAccessGateway:
|
|
|
1046
1088
|
|
|
1047
1089
|
# datetime filtering
|
|
1048
1090
|
if missionStartDate or missionEndDate:
|
|
1091
|
+
min_aware = datetime.datetime.min.replace(tzinfo=datetime.timezone.utc)
|
|
1092
|
+
max_aware = datetime.datetime.max.replace(tzinfo=datetime.timezone.utc)
|
|
1049
1093
|
guesses = [
|
|
1050
1094
|
g
|
|
1051
1095
|
for g in guesses
|
|
1052
1096
|
if (
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1097
|
+
max(
|
|
1098
|
+
rfc3339_str_to_datetime(missionStartDate)
|
|
1099
|
+
if missionStartDate
|
|
1100
|
+
else min_aware,
|
|
1101
|
+
rfc3339_str_to_datetime(g["missionStartDate"])
|
|
1102
|
+
if g.get("missionStartDate")
|
|
1103
|
+
else min_aware,
|
|
1104
|
+
)
|
|
1105
|
+
<= min(
|
|
1106
|
+
rfc3339_str_to_datetime(missionEndDate)
|
|
1107
|
+
if missionEndDate
|
|
1108
|
+
else max_aware,
|
|
1109
|
+
rfc3339_str_to_datetime(g["missionEndDate"])
|
|
1110
|
+
if g.get("missionEndDate")
|
|
1111
|
+
else max_aware,
|
|
1112
|
+
)
|
|
1063
1113
|
)
|
|
1064
1114
|
]
|
|
1065
1115
|
|
|
@@ -1155,7 +1205,7 @@ class EODataAccessGateway:
|
|
|
1155
1205
|
items_per_page=items_per_page,
|
|
1156
1206
|
)
|
|
1157
1207
|
|
|
1158
|
-
|
|
1208
|
+
errors: List[Tuple[str, Exception]] = []
|
|
1159
1209
|
# Loop over available providers and return the first non-empty results
|
|
1160
1210
|
for i, search_plugin in enumerate(search_plugins):
|
|
1161
1211
|
search_plugin.clear()
|
|
@@ -1165,17 +1215,19 @@ class EODataAccessGateway:
|
|
|
1165
1215
|
raise_errors=raise_errors,
|
|
1166
1216
|
**search_kwargs,
|
|
1167
1217
|
)
|
|
1218
|
+
errors.extend(search_results.errors)
|
|
1168
1219
|
if len(search_results) == 0 and i < len(search_plugins) - 1:
|
|
1169
1220
|
logger.warning(
|
|
1170
1221
|
f"No result could be obtained from provider {search_plugin.provider}, "
|
|
1171
1222
|
"we will try to get the data from another provider",
|
|
1172
1223
|
)
|
|
1173
1224
|
elif len(search_results) > 0:
|
|
1225
|
+
search_results.errors = errors
|
|
1174
1226
|
return search_results
|
|
1175
1227
|
|
|
1176
1228
|
if i > 1:
|
|
1177
1229
|
logger.error("No result could be obtained from any available provider")
|
|
1178
|
-
return SearchResult([], 0) if count else SearchResult([])
|
|
1230
|
+
return SearchResult([], 0, errors) if count else SearchResult([], errors=errors)
|
|
1179
1231
|
|
|
1180
1232
|
def search_iter_page(
|
|
1181
1233
|
self,
|
|
@@ -1435,7 +1487,7 @@ class EODataAccessGateway:
|
|
|
1435
1487
|
)
|
|
1436
1488
|
or DEFAULT_MAX_ITEMS_PER_PAGE
|
|
1437
1489
|
)
|
|
1438
|
-
logger.
|
|
1490
|
+
logger.info(
|
|
1439
1491
|
"Searching for all the products with provider %s and a maximum of %s "
|
|
1440
1492
|
"items per page.",
|
|
1441
1493
|
search_plugin.provider,
|
|
@@ -1503,7 +1555,7 @@ class EODataAccessGateway:
|
|
|
1503
1555
|
try:
|
|
1504
1556
|
product_type = self.get_product_type_from_alias(product_type)
|
|
1505
1557
|
except NoMatchingProductType:
|
|
1506
|
-
logger.
|
|
1558
|
+
logger.debug("product type %s not found", product_type)
|
|
1507
1559
|
get_search_plugins_kwargs = dict(provider=provider, product_type=product_type)
|
|
1508
1560
|
search_plugins = self._plugins_manager.get_search_plugins(
|
|
1509
1561
|
**get_search_plugins_kwargs
|
|
@@ -1526,7 +1578,7 @@ class EODataAccessGateway:
|
|
|
1526
1578
|
"max_items_per_page", DEFAULT_MAX_ITEMS_PER_PAGE
|
|
1527
1579
|
)
|
|
1528
1580
|
kwargs.update(items_per_page=items_per_page)
|
|
1529
|
-
if isinstance(plugin,
|
|
1581
|
+
if isinstance(plugin, PostJsonSearch):
|
|
1530
1582
|
kwargs.update(
|
|
1531
1583
|
items_per_page=items_per_page,
|
|
1532
1584
|
_dc_qs=_dc_qs,
|
|
@@ -1544,9 +1596,10 @@ class EODataAccessGateway:
|
|
|
1544
1596
|
**kwargs,
|
|
1545
1597
|
):
|
|
1546
1598
|
results.data.extend(page_results.data)
|
|
1547
|
-
except Exception:
|
|
1599
|
+
except Exception as e:
|
|
1548
1600
|
if kwargs.get("raise_errors"):
|
|
1549
1601
|
raise
|
|
1602
|
+
logger.warning(e)
|
|
1550
1603
|
continue
|
|
1551
1604
|
|
|
1552
1605
|
# try using crunch to get unique result
|
|
@@ -1584,16 +1637,12 @@ class EODataAccessGateway:
|
|
|
1584
1637
|
|
|
1585
1638
|
# append auth if needed
|
|
1586
1639
|
if getattr(plugin.config, "need_auth", False):
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
else:
|
|
1594
|
-
logger.warning(
|
|
1595
|
-
f"Could not authenticate on {provider} using {auth_plugin} plugin"
|
|
1596
|
-
)
|
|
1640
|
+
if auth := self._plugins_manager.get_auth(
|
|
1641
|
+
plugin.provider,
|
|
1642
|
+
getattr(plugin.config, "api_endpoint", None),
|
|
1643
|
+
plugin.config,
|
|
1644
|
+
):
|
|
1645
|
+
kwargs["auth"] = auth
|
|
1597
1646
|
|
|
1598
1647
|
product_type_config = plugin.discover_product_types(**kwargs)
|
|
1599
1648
|
self.update_product_types_list({provider: product_type_config})
|
|
@@ -1718,12 +1767,12 @@ class EODataAccessGateway:
|
|
|
1718
1767
|
for plugin in self._plugins_manager.get_search_plugins(
|
|
1719
1768
|
product_type=product_type, provider=provider
|
|
1720
1769
|
):
|
|
1721
|
-
# exclude
|
|
1770
|
+
# exclude MeteoblueSearch plugins from search fallback for unknown product_type
|
|
1722
1771
|
if (
|
|
1723
1772
|
provider != plugin.provider
|
|
1724
1773
|
and preferred_provider != plugin.provider
|
|
1725
1774
|
and product_type not in self.product_types_config
|
|
1726
|
-
and isinstance(plugin,
|
|
1775
|
+
and isinstance(plugin, MeteoblueSearch)
|
|
1727
1776
|
):
|
|
1728
1777
|
continue
|
|
1729
1778
|
search_plugins.append(plugin)
|
|
@@ -1732,12 +1781,10 @@ class EODataAccessGateway:
|
|
|
1732
1781
|
provider = preferred_provider
|
|
1733
1782
|
providers = [plugin.provider for plugin in search_plugins]
|
|
1734
1783
|
if provider not in providers:
|
|
1735
|
-
logger.
|
|
1736
|
-
"Product type '%s' is not available with provider '%s'.
|
|
1737
|
-
"Searching it on provider '%s' instead.",
|
|
1784
|
+
logger.debug(
|
|
1785
|
+
"Product type '%s' is not available with preferred provider '%s'.",
|
|
1738
1786
|
product_type,
|
|
1739
1787
|
provider,
|
|
1740
|
-
search_plugins[0].provider,
|
|
1741
1788
|
)
|
|
1742
1789
|
else:
|
|
1743
1790
|
provider_plugin = list(
|
|
@@ -1745,35 +1792,10 @@ class EODataAccessGateway:
|
|
|
1745
1792
|
)[0]
|
|
1746
1793
|
search_plugins.remove(provider_plugin)
|
|
1747
1794
|
search_plugins.insert(0, provider_plugin)
|
|
1748
|
-
logger.info(
|
|
1749
|
-
"Searching product type '%s' on provider: %s",
|
|
1750
|
-
product_type,
|
|
1751
|
-
search_plugins[0].provider,
|
|
1752
|
-
)
|
|
1753
1795
|
# Add product_types_config to plugin config. This dict contains product
|
|
1754
1796
|
# type metadata that will also be stored in each product's properties.
|
|
1755
1797
|
for search_plugin in search_plugins:
|
|
1756
|
-
|
|
1757
|
-
search_plugin.config.product_type_config = dict(
|
|
1758
|
-
[
|
|
1759
|
-
p
|
|
1760
|
-
for p in self.list_product_types(
|
|
1761
|
-
search_plugin.provider, fetch_providers=False
|
|
1762
|
-
)
|
|
1763
|
-
if p["_id"] == product_type
|
|
1764
|
-
][0],
|
|
1765
|
-
**{"productType": product_type},
|
|
1766
|
-
)
|
|
1767
|
-
# If the product isn't in the catalog, it's a generic product type.
|
|
1768
|
-
except IndexError:
|
|
1769
|
-
# Construct the GENERIC_PRODUCT_TYPE metadata
|
|
1770
|
-
search_plugin.config.product_type_config = dict(
|
|
1771
|
-
ID=GENERIC_PRODUCT_TYPE,
|
|
1772
|
-
**self.product_types_config[GENERIC_PRODUCT_TYPE],
|
|
1773
|
-
productType=product_type,
|
|
1774
|
-
)
|
|
1775
|
-
# Remove the ID since this is equal to productType.
|
|
1776
|
-
search_plugin.config.product_type_config.pop("ID", None)
|
|
1798
|
+
self._attach_product_type_config(search_plugin, product_type)
|
|
1777
1799
|
|
|
1778
1800
|
return search_plugins, kwargs
|
|
1779
1801
|
|
|
@@ -1793,6 +1815,7 @@ class EODataAccessGateway:
|
|
|
1793
1815
|
:param kwargs: Some other criteria that will be used to do the search
|
|
1794
1816
|
:returns: A collection of EO products matching the criteria
|
|
1795
1817
|
"""
|
|
1818
|
+
logger.info("Searching on provider %s", search_plugin.provider)
|
|
1796
1819
|
max_items_per_page = getattr(search_plugin.config, "pagination", {}).get(
|
|
1797
1820
|
"max_items_per_page", DEFAULT_MAX_ITEMS_PER_PAGE
|
|
1798
1821
|
)
|
|
@@ -1810,19 +1833,23 @@ class EODataAccessGateway:
|
|
|
1810
1833
|
max_items_per_page,
|
|
1811
1834
|
)
|
|
1812
1835
|
|
|
1813
|
-
need_auth = getattr(search_plugin.config, "need_auth", False)
|
|
1814
|
-
auth_plugin = self._plugins_manager.get_auth_plugin(search_plugin.provider)
|
|
1815
|
-
can_authenticate = callable(getattr(auth_plugin, "authenticate", None))
|
|
1816
|
-
|
|
1817
1836
|
results: List[EOProduct] = []
|
|
1818
1837
|
total_results: Optional[int] = 0 if count else None
|
|
1819
1838
|
|
|
1839
|
+
errors: List[Tuple[str, Exception]] = []
|
|
1840
|
+
|
|
1820
1841
|
try:
|
|
1821
1842
|
prep = PreparedSearch(count=count)
|
|
1822
|
-
if need_auth and auth_plugin and can_authenticate:
|
|
1823
|
-
prep.auth = auth_plugin.authenticate()
|
|
1824
1843
|
|
|
1825
|
-
|
|
1844
|
+
# append auth if needed
|
|
1845
|
+
if getattr(search_plugin.config, "need_auth", False):
|
|
1846
|
+
if auth := self._plugins_manager.get_auth(
|
|
1847
|
+
search_plugin.provider,
|
|
1848
|
+
getattr(search_plugin.config, "api_endpoint", None),
|
|
1849
|
+
search_plugin.config,
|
|
1850
|
+
):
|
|
1851
|
+
prep.auth = auth
|
|
1852
|
+
|
|
1826
1853
|
prep.page = kwargs.pop("page", None)
|
|
1827
1854
|
prep.items_per_page = kwargs.pop("items_per_page", None)
|
|
1828
1855
|
|
|
@@ -1876,12 +1903,31 @@ class EODataAccessGateway:
|
|
|
1876
1903
|
eo_product.product_type
|
|
1877
1904
|
)
|
|
1878
1905
|
except NoMatchingProductType:
|
|
1879
|
-
logger.
|
|
1906
|
+
logger.debug("product type %s not found", eo_product.product_type)
|
|
1880
1907
|
|
|
1881
1908
|
if eo_product.search_intersection is not None:
|
|
1882
1909
|
download_plugin = self._plugins_manager.get_download_plugin(
|
|
1883
1910
|
eo_product
|
|
1884
1911
|
)
|
|
1912
|
+
if len(eo_product.assets) > 0:
|
|
1913
|
+
matching_url = next(iter(eo_product.assets.values()))["href"]
|
|
1914
|
+
elif eo_product.properties.get("storageStatus") != ONLINE_STATUS:
|
|
1915
|
+
matching_url = eo_product.properties.get(
|
|
1916
|
+
"orderLink"
|
|
1917
|
+
) or eo_product.properties.get("downloadLink")
|
|
1918
|
+
else:
|
|
1919
|
+
matching_url = eo_product.properties.get("downloadLink")
|
|
1920
|
+
|
|
1921
|
+
try:
|
|
1922
|
+
auth_plugin = next(
|
|
1923
|
+
self._plugins_manager.get_auth_plugins(
|
|
1924
|
+
search_plugin.provider,
|
|
1925
|
+
matching_url=matching_url,
|
|
1926
|
+
matching_conf=download_plugin.config,
|
|
1927
|
+
)
|
|
1928
|
+
)
|
|
1929
|
+
except StopIteration:
|
|
1930
|
+
auth_plugin = None
|
|
1885
1931
|
eo_product.register_downloader(download_plugin, auth_plugin)
|
|
1886
1932
|
|
|
1887
1933
|
results.extend(res)
|
|
@@ -1911,13 +1957,6 @@ class EODataAccessGateway:
|
|
|
1911
1957
|
"the total number of products matching the search criteria"
|
|
1912
1958
|
)
|
|
1913
1959
|
except Exception as e:
|
|
1914
|
-
log_msg = f"No result from provider '{search_plugin.provider}' due to an error during search."
|
|
1915
|
-
if not raise_errors:
|
|
1916
|
-
log_msg += " Raise verbosity of log messages for details"
|
|
1917
|
-
logger.info(log_msg)
|
|
1918
|
-
# keep only the message from exception args
|
|
1919
|
-
if len(e.args) > 1:
|
|
1920
|
-
e.args = (e.args[0],)
|
|
1921
1960
|
if raise_errors:
|
|
1922
1961
|
# Raise the error, letting the application wrapping eodag know that
|
|
1923
1962
|
# something went bad. This way it will be able to decide what to do next
|
|
@@ -1927,8 +1966,8 @@ class EODataAccessGateway:
|
|
|
1927
1966
|
"Error while searching on provider %s (ignored):",
|
|
1928
1967
|
search_plugin.provider,
|
|
1929
1968
|
)
|
|
1930
|
-
|
|
1931
|
-
return SearchResult(results, total_results)
|
|
1969
|
+
errors.append((search_plugin.provider, e))
|
|
1970
|
+
return SearchResult(results, total_results, errors)
|
|
1932
1971
|
|
|
1933
1972
|
def crunch(self, results: SearchResult, **kwargs: Any) -> SearchResult:
|
|
1934
1973
|
"""Apply the filters given through the keyword arguments to the results
|
|
@@ -1973,8 +2012,8 @@ class EODataAccessGateway:
|
|
|
1973
2012
|
search_result: SearchResult,
|
|
1974
2013
|
downloaded_callback: Optional[DownloadedCallback] = None,
|
|
1975
2014
|
progress_callback: Optional[ProgressCallback] = None,
|
|
1976
|
-
wait:
|
|
1977
|
-
timeout:
|
|
2015
|
+
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
2016
|
+
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
1978
2017
|
**kwargs: Unpack[DownloadConf],
|
|
1979
2018
|
) -> List[str]:
|
|
1980
2019
|
"""Download all products resulting from a search.
|
|
@@ -1982,7 +2021,7 @@ class EODataAccessGateway:
|
|
|
1982
2021
|
:param search_result: A collection of EO products resulting from a search
|
|
1983
2022
|
:param downloaded_callback: (optional) A method or a callable object which takes
|
|
1984
2023
|
as parameter the ``product``. You can use the base class
|
|
1985
|
-
:class:`~eodag.
|
|
2024
|
+
:class:`~eodag.utils.DownloadedCallback` and override
|
|
1986
2025
|
its ``__call__`` method. Will be called each time a product
|
|
1987
2026
|
finishes downloading
|
|
1988
2027
|
:param progress_callback: (optional) A method or a callable object
|
|
@@ -2061,12 +2100,12 @@ class EODataAccessGateway:
|
|
|
2061
2100
|
products = self.deserialize(filename)
|
|
2062
2101
|
for i, product in enumerate(products):
|
|
2063
2102
|
if product.downloader is None:
|
|
2103
|
+
downloader = self._plugins_manager.get_download_plugin(product)
|
|
2064
2104
|
auth = product.downloader_auth
|
|
2065
2105
|
if auth is None:
|
|
2066
|
-
auth = self._plugins_manager.get_auth_plugin(product
|
|
2067
|
-
products[i].register_downloader(
|
|
2068
|
-
|
|
2069
|
-
)
|
|
2106
|
+
auth = self._plugins_manager.get_auth_plugin(downloader, product)
|
|
2107
|
+
products[i].register_downloader(downloader, auth)
|
|
2108
|
+
|
|
2070
2109
|
return products
|
|
2071
2110
|
|
|
2072
2111
|
@_deprecated(
|
|
@@ -2090,7 +2129,7 @@ class EODataAccessGateway:
|
|
|
2090
2129
|
|
|
2091
2130
|
:param filename: A filename containing features encoded as a geojson
|
|
2092
2131
|
:param recursive: (optional) Browse recursively in child nodes if True
|
|
2093
|
-
:param max_connections: (optional) Maximum number of connections for HTTP requests
|
|
2132
|
+
:param max_connections: (optional) Maximum number of connections for concurrent HTTP requests
|
|
2094
2133
|
:param provider: (optional) Data provider
|
|
2095
2134
|
:param productType: (optional) Data product type
|
|
2096
2135
|
:param timeout: (optional) Timeout in seconds for each internal HTTP request
|
|
@@ -2136,8 +2175,8 @@ class EODataAccessGateway:
|
|
|
2136
2175
|
self,
|
|
2137
2176
|
product: EOProduct,
|
|
2138
2177
|
progress_callback: Optional[ProgressCallback] = None,
|
|
2139
|
-
wait:
|
|
2140
|
-
timeout:
|
|
2178
|
+
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
2179
|
+
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
2141
2180
|
**kwargs: Unpack[DownloadConf],
|
|
2142
2181
|
) -> str:
|
|
2143
2182
|
"""Download a single product.
|
|
@@ -2197,12 +2236,11 @@ class EODataAccessGateway:
|
|
|
2197
2236
|
|
|
2198
2237
|
def _setup_downloader(self, product: EOProduct) -> None:
|
|
2199
2238
|
if product.downloader is None:
|
|
2239
|
+
downloader = self._plugins_manager.get_download_plugin(product)
|
|
2200
2240
|
auth = product.downloader_auth
|
|
2201
2241
|
if auth is None:
|
|
2202
|
-
auth = self._plugins_manager.get_auth_plugin(product
|
|
2203
|
-
product.register_downloader(
|
|
2204
|
-
self._plugins_manager.get_download_plugin(product), auth
|
|
2205
|
-
)
|
|
2242
|
+
auth = self._plugins_manager.get_auth_plugin(downloader, product)
|
|
2243
|
+
product.register_downloader(downloader, auth)
|
|
2206
2244
|
|
|
2207
2245
|
def get_cruncher(self, name: str, **options: Any) -> Crunch:
|
|
2208
2246
|
"""Build a crunch plugin from a configuration
|
|
@@ -2216,67 +2254,96 @@ class EODataAccessGateway:
|
|
|
2216
2254
|
return self._plugins_manager.get_crunch_plugin(name, **plugin_conf)
|
|
2217
2255
|
|
|
2218
2256
|
def list_queryables(
|
|
2219
|
-
self,
|
|
2220
|
-
|
|
2257
|
+
self,
|
|
2258
|
+
provider: Optional[str] = None,
|
|
2259
|
+
fetch_providers: bool = True,
|
|
2260
|
+
**kwargs: Any,
|
|
2261
|
+
) -> QueryablesDict:
|
|
2221
2262
|
"""Fetch the queryable properties for a given product type and/or provider.
|
|
2222
2263
|
|
|
2223
2264
|
:param provider: (optional) The provider.
|
|
2265
|
+
:param fetch_providers: If new product types should be fetched from the providers; default: True
|
|
2224
2266
|
:param kwargs: additional filters for queryables (`productType` or other search
|
|
2225
2267
|
arguments)
|
|
2226
2268
|
|
|
2227
2269
|
:raises UnsupportedProductType: If the specified product type is not available for the
|
|
2228
2270
|
provider.
|
|
2229
2271
|
|
|
2230
|
-
:returns: A
|
|
2231
|
-
parameters to their annotated type
|
|
2272
|
+
:returns: A :class:`~eodag.api.product.queryables.QuerybalesDict` containing the EODAG queryable
|
|
2273
|
+
properties, associating parameters to their annotated type, and a additional_properties attribute
|
|
2232
2274
|
"""
|
|
2275
|
+
# only fetch providers if product type is not found
|
|
2233
2276
|
available_product_types = [
|
|
2234
2277
|
pt["ID"]
|
|
2235
2278
|
for pt in self.list_product_types(provider=provider, fetch_providers=False)
|
|
2236
2279
|
]
|
|
2237
|
-
product_type = kwargs.get("productType")
|
|
2280
|
+
product_type: Optional[str] = kwargs.get("productType")
|
|
2281
|
+
pt_alias: Optional[str] = product_type
|
|
2238
2282
|
|
|
2239
2283
|
if product_type:
|
|
2284
|
+
if product_type not in available_product_types:
|
|
2285
|
+
if fetch_providers:
|
|
2286
|
+
# fetch providers and try again
|
|
2287
|
+
available_product_types = [
|
|
2288
|
+
pt["ID"]
|
|
2289
|
+
for pt in self.list_product_types(
|
|
2290
|
+
provider=provider, fetch_providers=True
|
|
2291
|
+
)
|
|
2292
|
+
]
|
|
2293
|
+
raise UnsupportedProductType(f"{product_type} is not available.")
|
|
2240
2294
|
try:
|
|
2241
2295
|
kwargs["productType"] = product_type = self.get_product_type_from_alias(
|
|
2242
2296
|
product_type
|
|
2243
2297
|
)
|
|
2244
2298
|
except NoMatchingProductType as e:
|
|
2245
|
-
raise UnsupportedProductType(f"{product_type} is not available") from e
|
|
2246
|
-
|
|
2247
|
-
if product_type and product_type not in available_product_types:
|
|
2248
|
-
self.fetch_product_types_list()
|
|
2299
|
+
raise UnsupportedProductType(f"{product_type} is not available.") from e
|
|
2249
2300
|
|
|
2250
2301
|
if not provider and not product_type:
|
|
2251
|
-
return
|
|
2302
|
+
return QueryablesDict(
|
|
2303
|
+
additional_properties=True,
|
|
2304
|
+
**model_fields_to_annotated(CommonQueryables.model_fields),
|
|
2305
|
+
)
|
|
2252
2306
|
|
|
2253
|
-
|
|
2307
|
+
queryables: QueryablesDict = QueryablesDict(
|
|
2308
|
+
additional_properties=True, additional_information="", **{}
|
|
2309
|
+
)
|
|
2254
2310
|
|
|
2255
2311
|
for plugin in self._plugins_manager.get_search_plugins(product_type, provider):
|
|
2312
|
+
# attach product type config
|
|
2313
|
+
product_type_configs = {}
|
|
2314
|
+
if product_type:
|
|
2315
|
+
self._attach_product_type_config(plugin, product_type)
|
|
2316
|
+
product_type_configs[product_type] = plugin.config.product_type_config
|
|
2317
|
+
else:
|
|
2318
|
+
for pt in available_product_types:
|
|
2319
|
+
self._attach_product_type_config(plugin, pt)
|
|
2320
|
+
product_type_configs[pt] = plugin.config.product_type_config
|
|
2321
|
+
|
|
2322
|
+
# authenticate if required
|
|
2256
2323
|
if getattr(plugin.config, "need_auth", False) and (
|
|
2257
|
-
auth := self._plugins_manager.get_auth_plugin(plugin
|
|
2324
|
+
auth := self._plugins_manager.get_auth_plugin(plugin)
|
|
2258
2325
|
):
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2326
|
+
try:
|
|
2327
|
+
plugin.auth = auth.authenticate()
|
|
2328
|
+
except AuthenticationError:
|
|
2329
|
+
logger.debug(
|
|
2330
|
+
"queryables from provider %s could not be fetched due to an authentication error",
|
|
2331
|
+
plugin.provider,
|
|
2332
|
+
)
|
|
2333
|
+
plugin_queryables = plugin.list_queryables(
|
|
2334
|
+
kwargs,
|
|
2335
|
+
available_product_types,
|
|
2336
|
+
product_type_configs,
|
|
2337
|
+
product_type,
|
|
2338
|
+
pt_alias,
|
|
2262
2339
|
)
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
if k in queryable_keys
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
# always keep at least CommonQueryables
|
|
2274
|
-
common_queryables = copy_deepcopy(CommonQueryables.model_fields)
|
|
2275
|
-
for key, queryable in common_queryables.items():
|
|
2276
|
-
if key in kwargs:
|
|
2277
|
-
queryable.default = kwargs[key]
|
|
2278
|
-
|
|
2279
|
-
queryables.update(model_fields_to_annotated(common_queryables))
|
|
2340
|
+
queryables.update(plugin_queryables)
|
|
2341
|
+
if not plugin_queryables.additional_properties:
|
|
2342
|
+
queryables.additional_properties = False
|
|
2343
|
+
if plugin_queryables.additional_information:
|
|
2344
|
+
queryables.additional_information += (
|
|
2345
|
+
f"{provider}: {plugin_queryables.additional_information}"
|
|
2346
|
+
)
|
|
2280
2347
|
|
|
2281
2348
|
return queryables
|
|
2282
2349
|
|
|
@@ -2284,7 +2351,7 @@ class EODataAccessGateway:
|
|
|
2284
2351
|
"""For each provider, gives its available sortable parameter(s) and its maximum
|
|
2285
2352
|
number of them if it supports the sorting feature, otherwise gives None.
|
|
2286
2353
|
|
|
2287
|
-
:returns: A
|
|
2354
|
+
:returns: A dictionary with providers as keys and dictionary of sortable parameter(s) and
|
|
2288
2355
|
its (their) maximum number as value(s).
|
|
2289
2356
|
:raises: :class:`~eodag.utils.exceptions.UnsupportedProvider`
|
|
2290
2357
|
"""
|
|
@@ -2311,3 +2378,30 @@ class EODataAccessGateway:
|
|
|
2311
2378
|
],
|
|
2312
2379
|
}
|
|
2313
2380
|
return sortables
|
|
2381
|
+
|
|
2382
|
+
def _attach_product_type_config(self, plugin: Search, product_type: str) -> None:
|
|
2383
|
+
"""
|
|
2384
|
+
Attach product_types_config to plugin config. This dict contains product
|
|
2385
|
+
type metadata that will also be stored in each product's properties.
|
|
2386
|
+
"""
|
|
2387
|
+
try:
|
|
2388
|
+
plugin.config.product_type_config = dict(
|
|
2389
|
+
[
|
|
2390
|
+
p
|
|
2391
|
+
for p in self.list_product_types(
|
|
2392
|
+
plugin.provider, fetch_providers=False
|
|
2393
|
+
)
|
|
2394
|
+
if p["_id"] == product_type
|
|
2395
|
+
][0],
|
|
2396
|
+
**{"productType": product_type},
|
|
2397
|
+
)
|
|
2398
|
+
# If the product isn't in the catalog, it's a generic product type.
|
|
2399
|
+
except IndexError:
|
|
2400
|
+
# Construct the GENERIC_PRODUCT_TYPE metadata
|
|
2401
|
+
plugin.config.product_type_config = dict(
|
|
2402
|
+
ID=GENERIC_PRODUCT_TYPE,
|
|
2403
|
+
**self.product_types_config[GENERIC_PRODUCT_TYPE],
|
|
2404
|
+
productType=product_type,
|
|
2405
|
+
)
|
|
2406
|
+
# Remove the ID since this is equal to productType.
|
|
2407
|
+
plugin.config.product_type_config.pop("ID", None)
|