eodag 3.1.0b1__py3-none-any.whl → 3.2.0__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 +69 -63
- eodag/api/product/_assets.py +49 -13
- eodag/api/product/_product.py +41 -30
- eodag/api/product/drivers/__init__.py +81 -4
- eodag/api/product/drivers/base.py +65 -4
- eodag/api/product/drivers/generic.py +65 -0
- eodag/api/product/drivers/sentinel1.py +97 -0
- eodag/api/product/drivers/sentinel2.py +95 -0
- eodag/api/product/metadata_mapping.py +85 -79
- eodag/api/search_result.py +13 -23
- eodag/cli.py +4 -4
- eodag/config.py +77 -80
- eodag/plugins/apis/base.py +1 -1
- eodag/plugins/apis/ecmwf.py +12 -15
- eodag/plugins/apis/usgs.py +12 -11
- eodag/plugins/authentication/aws_auth.py +16 -13
- eodag/plugins/authentication/base.py +5 -3
- eodag/plugins/authentication/header.py +3 -3
- eodag/plugins/authentication/keycloak.py +4 -4
- eodag/plugins/authentication/oauth.py +7 -3
- eodag/plugins/authentication/openid_connect.py +20 -14
- eodag/plugins/authentication/sas_auth.py +4 -4
- eodag/plugins/authentication/token.py +7 -7
- eodag/plugins/authentication/token_exchange.py +1 -1
- eodag/plugins/base.py +4 -4
- eodag/plugins/crunch/base.py +4 -4
- eodag/plugins/crunch/filter_date.py +4 -4
- eodag/plugins/crunch/filter_latest_intersect.py +6 -6
- eodag/plugins/crunch/filter_latest_tpl_name.py +7 -7
- eodag/plugins/crunch/filter_overlap.py +4 -4
- eodag/plugins/crunch/filter_property.py +4 -4
- eodag/plugins/download/aws.py +137 -77
- eodag/plugins/download/base.py +8 -17
- eodag/plugins/download/creodias_s3.py +2 -2
- eodag/plugins/download/http.py +30 -32
- eodag/plugins/download/s3rest.py +5 -4
- eodag/plugins/manager.py +10 -20
- eodag/plugins/search/__init__.py +6 -5
- eodag/plugins/search/base.py +38 -42
- eodag/plugins/search/build_search_result.py +286 -336
- eodag/plugins/search/cop_marine.py +22 -12
- eodag/plugins/search/creodias_s3.py +8 -78
- eodag/plugins/search/csw.py +11 -11
- eodag/plugins/search/data_request_search.py +19 -18
- eodag/plugins/search/qssearch.py +84 -151
- eodag/plugins/search/stac_list_assets.py +85 -0
- eodag/plugins/search/static_stac_search.py +4 -4
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +848 -398
- eodag/resources/providers.yml +1038 -1115
- eodag/resources/stac_api.yml +2 -2
- eodag/resources/user_conf_template.yml +10 -9
- eodag/rest/cache.py +2 -2
- eodag/rest/config.py +3 -3
- eodag/rest/core.py +24 -24
- eodag/rest/errors.py +5 -5
- eodag/rest/server.py +3 -11
- eodag/rest/stac.py +41 -38
- eodag/rest/types/collections_search.py +3 -3
- eodag/rest/types/eodag_search.py +23 -23
- eodag/rest/types/queryables.py +40 -28
- eodag/rest/types/stac_search.py +15 -25
- eodag/rest/utils/__init__.py +11 -21
- eodag/rest/utils/cql_evaluate.py +6 -6
- eodag/rest/utils/rfc3339.py +2 -2
- eodag/types/__init__.py +97 -29
- eodag/types/bbox.py +2 -2
- eodag/types/download_args.py +2 -2
- eodag/types/queryables.py +5 -2
- eodag/types/search_args.py +4 -4
- eodag/types/whoosh.py +1 -3
- eodag/utils/__init__.py +82 -41
- eodag/utils/exceptions.py +2 -2
- eodag/utils/import_system.py +2 -2
- eodag/utils/requests.py +2 -2
- eodag/utils/rest.py +2 -2
- eodag/utils/s3.py +231 -0
- eodag/utils/stac_reader.py +10 -10
- {eodag-3.1.0b1.dist-info → eodag-3.2.0.dist-info}/METADATA +12 -10
- eodag-3.2.0.dist-info/RECORD +113 -0
- {eodag-3.1.0b1.dist-info → eodag-3.2.0.dist-info}/WHEEL +1 -1
- {eodag-3.1.0b1.dist-info → eodag-3.2.0.dist-info}/entry_points.txt +1 -0
- eodag-3.1.0b1.dist-info/RECORD +0 -108
- {eodag-3.1.0b1.dist-info → eodag-3.2.0.dist-info/licenses}/LICENSE +0 -0
- {eodag-3.1.0b1.dist-info → eodag-3.2.0.dist-info}/top_level.txt +0 -0
eodag/api/core.py
CHANGED
|
@@ -23,13 +23,13 @@ import os
|
|
|
23
23
|
import re
|
|
24
24
|
import shutil
|
|
25
25
|
import tempfile
|
|
26
|
+
from importlib.metadata import version
|
|
27
|
+
from importlib.resources import files as res_files
|
|
26
28
|
from operator import itemgetter
|
|
27
|
-
from typing import TYPE_CHECKING, Any,
|
|
29
|
+
from typing import TYPE_CHECKING, Any, Iterator, Optional, Union
|
|
28
30
|
|
|
29
31
|
import geojson
|
|
30
|
-
import pkg_resources
|
|
31
32
|
import yaml.parser
|
|
32
|
-
from pkg_resources import resource_filename
|
|
33
33
|
from whoosh import analysis, fields
|
|
34
34
|
from whoosh.fields import Schema
|
|
35
35
|
from whoosh.index import exists_in, open_dir
|
|
@@ -119,8 +119,8 @@ class EODataAccessGateway:
|
|
|
119
119
|
user_conf_file_path: Optional[str] = None,
|
|
120
120
|
locations_conf_path: Optional[str] = None,
|
|
121
121
|
) -> None:
|
|
122
|
-
product_types_config_path =
|
|
123
|
-
"eodag"
|
|
122
|
+
product_types_config_path = os.getenv("EODAG_PRODUCT_TYPES_CFG_FILE") or str(
|
|
123
|
+
res_files("eodag") / "resources" / "product_types.yml"
|
|
124
124
|
)
|
|
125
125
|
self.product_types_config = SimpleYamlProxyConfig(product_types_config_path)
|
|
126
126
|
self.product_types_config_md5 = obj_md5sum(self.product_types_config.source)
|
|
@@ -161,8 +161,8 @@ class EODataAccessGateway:
|
|
|
161
161
|
user_conf_file_path = standard_configuration_path
|
|
162
162
|
if not os.path.isfile(standard_configuration_path):
|
|
163
163
|
shutil.copy(
|
|
164
|
-
|
|
165
|
-
"eodag"
|
|
164
|
+
str(
|
|
165
|
+
res_files("eodag") / "resources" / "user_conf_template.yml"
|
|
166
166
|
),
|
|
167
167
|
standard_configuration_path,
|
|
168
168
|
)
|
|
@@ -185,7 +185,7 @@ class EODataAccessGateway:
|
|
|
185
185
|
self._plugins_manager.rebuild(self.providers_config)
|
|
186
186
|
|
|
187
187
|
# store pruned providers configs
|
|
188
|
-
self._pruned_providers_config:
|
|
188
|
+
self._pruned_providers_config: dict[str, Any] = {}
|
|
189
189
|
# filter out providers needing auth that have no credentials set
|
|
190
190
|
self._prune_providers_list()
|
|
191
191
|
|
|
@@ -203,9 +203,8 @@ class EODataAccessGateway:
|
|
|
203
203
|
locations_conf_path = os.path.join(self.conf_dir, "locations.yml")
|
|
204
204
|
if not os.path.isfile(locations_conf_path):
|
|
205
205
|
# copy locations conf file and replace path example
|
|
206
|
-
locations_conf_template =
|
|
207
|
-
"eodag"
|
|
208
|
-
os.path.join("resources", "locations_conf_template.yml"),
|
|
206
|
+
locations_conf_template = str(
|
|
207
|
+
res_files("eodag") / "resources" / "locations_conf_template.yml"
|
|
209
208
|
)
|
|
210
209
|
with (
|
|
211
210
|
open(locations_conf_template) as infile,
|
|
@@ -222,14 +221,14 @@ class EODataAccessGateway:
|
|
|
222
221
|
outfile.write(line)
|
|
223
222
|
# copy sample shapefile dir
|
|
224
223
|
shutil.copytree(
|
|
225
|
-
|
|
224
|
+
str(res_files("eodag") / "resources" / "shp"),
|
|
226
225
|
os.path.join(self.conf_dir, "shp"),
|
|
227
226
|
)
|
|
228
227
|
self.set_locations_conf(locations_conf_path)
|
|
229
228
|
|
|
230
229
|
def get_version(self) -> str:
|
|
231
230
|
"""Get eodag package version"""
|
|
232
|
-
return
|
|
231
|
+
return version("eodag")
|
|
233
232
|
|
|
234
233
|
def build_index(self) -> None:
|
|
235
234
|
"""Build a `Whoosh <https://whoosh.readthedocs.io/en/latest/index.html>`_
|
|
@@ -335,7 +334,7 @@ class EODataAccessGateway:
|
|
|
335
334
|
new_priority = max_priority + 1
|
|
336
335
|
self._plugins_manager.set_priority(provider, new_priority)
|
|
337
336
|
|
|
338
|
-
def get_preferred_provider(self) ->
|
|
337
|
+
def get_preferred_provider(self) -> tuple[str, int]:
|
|
339
338
|
"""Get the provider currently set as the preferred one for searching
|
|
340
339
|
products, along with its priority.
|
|
341
340
|
|
|
@@ -351,7 +350,7 @@ class EODataAccessGateway:
|
|
|
351
350
|
def update_providers_config(
|
|
352
351
|
self,
|
|
353
352
|
yaml_conf: Optional[str] = None,
|
|
354
|
-
dict_conf: Optional[
|
|
353
|
+
dict_conf: Optional[dict[str, Any]] = None,
|
|
355
354
|
) -> None:
|
|
356
355
|
"""Update providers configuration with given input.
|
|
357
356
|
Can be used to add a provider to existing configuration or update
|
|
@@ -397,12 +396,12 @@ class EODataAccessGateway:
|
|
|
397
396
|
name: str,
|
|
398
397
|
url: Optional[str] = None,
|
|
399
398
|
priority: Optional[int] = None,
|
|
400
|
-
search:
|
|
401
|
-
products:
|
|
399
|
+
search: dict[str, Any] = {"type": "StacSearch"},
|
|
400
|
+
products: dict[str, Any] = {
|
|
402
401
|
GENERIC_PRODUCT_TYPE: {"productType": "{productType}"}
|
|
403
402
|
},
|
|
404
|
-
download:
|
|
405
|
-
**kwargs:
|
|
403
|
+
download: dict[str, Any] = {"type": "HTTPDownload", "auth_error_code": 401},
|
|
404
|
+
**kwargs: dict[str, Any],
|
|
406
405
|
):
|
|
407
406
|
"""Adds a new provider.
|
|
408
407
|
|
|
@@ -421,7 +420,7 @@ class EODataAccessGateway:
|
|
|
421
420
|
:param download: Download :class:`~eodag.config.PluginConfig` mapping
|
|
422
421
|
:param kwargs: Additional :class:`~eodag.config.ProviderConfig` mapping
|
|
423
422
|
"""
|
|
424
|
-
conf_dict:
|
|
423
|
+
conf_dict: dict[str, Any] = {
|
|
425
424
|
name: {
|
|
426
425
|
"url": url,
|
|
427
426
|
"search": {"type": "StacSearch", **search},
|
|
@@ -565,7 +564,7 @@ class EODataAccessGateway:
|
|
|
565
564
|
main_locations_config = locations_config[main_key]
|
|
566
565
|
|
|
567
566
|
logger.info("Locations configuration loaded from %s" % locations_conf_path)
|
|
568
|
-
self.locations_config:
|
|
567
|
+
self.locations_config: list[dict[str, Any]] = main_locations_config
|
|
569
568
|
else:
|
|
570
569
|
logger.info(
|
|
571
570
|
"Could not load locations configuration from %s" % locations_conf_path
|
|
@@ -574,7 +573,7 @@ class EODataAccessGateway:
|
|
|
574
573
|
|
|
575
574
|
def list_product_types(
|
|
576
575
|
self, provider: Optional[str] = None, fetch_providers: bool = True
|
|
577
|
-
) ->
|
|
576
|
+
) -> list[dict[str, Any]]:
|
|
578
577
|
"""Lists supported product types.
|
|
579
578
|
|
|
580
579
|
:param provider: (optional) The name of a provider that must support the product
|
|
@@ -588,7 +587,7 @@ class EODataAccessGateway:
|
|
|
588
587
|
# First, update product types list if possible
|
|
589
588
|
self.fetch_product_types_list(provider=provider)
|
|
590
589
|
|
|
591
|
-
product_types:
|
|
590
|
+
product_types: list[dict[str, Any]] = []
|
|
592
591
|
|
|
593
592
|
providers_configs = (
|
|
594
593
|
list(self.providers_config.values())
|
|
@@ -644,7 +643,7 @@ class EODataAccessGateway:
|
|
|
644
643
|
providers_to_fetch = [provider]
|
|
645
644
|
|
|
646
645
|
# providers discovery confs that are fetchable
|
|
647
|
-
providers_discovery_configs_fetchable:
|
|
646
|
+
providers_discovery_configs_fetchable: dict[str, Any] = {}
|
|
648
647
|
# check if any provider has not already been fetched for product types
|
|
649
648
|
already_fetched = True
|
|
650
649
|
for provider_to_fetch in providers_to_fetch:
|
|
@@ -767,7 +766,7 @@ class EODataAccessGateway:
|
|
|
767
766
|
|
|
768
767
|
def discover_product_types(
|
|
769
768
|
self, provider: Optional[str] = None
|
|
770
|
-
) -> Optional[
|
|
769
|
+
) -> Optional[dict[str, Any]]:
|
|
771
770
|
"""Fetch providers for product types
|
|
772
771
|
|
|
773
772
|
:param provider: The name of a provider or provider-group to fetch. Defaults to
|
|
@@ -787,7 +786,7 @@ class EODataAccessGateway:
|
|
|
787
786
|
raise UnsupportedProvider(
|
|
788
787
|
f"The requested provider is not (yet) supported: {provider}"
|
|
789
788
|
)
|
|
790
|
-
ext_product_types_conf:
|
|
789
|
+
ext_product_types_conf: dict[str, Any] = {}
|
|
791
790
|
providers_to_fetch = [
|
|
792
791
|
p
|
|
793
792
|
for p in (
|
|
@@ -800,7 +799,7 @@ class EODataAccessGateway:
|
|
|
800
799
|
else self.available_providers()
|
|
801
800
|
)
|
|
802
801
|
]
|
|
803
|
-
kwargs:
|
|
802
|
+
kwargs: dict[str, Any] = {}
|
|
804
803
|
for provider in providers_to_fetch:
|
|
805
804
|
if hasattr(self.providers_config[provider], "search"):
|
|
806
805
|
search_plugin_config = self.providers_config[provider].search
|
|
@@ -841,7 +840,7 @@ class EODataAccessGateway:
|
|
|
841
840
|
return sort_dict(ext_product_types_conf)
|
|
842
841
|
|
|
843
842
|
def update_product_types_list(
|
|
844
|
-
self, ext_product_types_conf:
|
|
843
|
+
self, ext_product_types_conf: dict[str, Optional[dict[str, dict[str, Any]]]]
|
|
845
844
|
) -> None:
|
|
846
845
|
"""Update eodag product types list
|
|
847
846
|
|
|
@@ -869,7 +868,7 @@ class EODataAccessGateway:
|
|
|
869
868
|
provider,
|
|
870
869
|
)
|
|
871
870
|
continue
|
|
872
|
-
new_product_types:
|
|
871
|
+
new_product_types: list[str] = []
|
|
873
872
|
for (
|
|
874
873
|
new_product_type,
|
|
875
874
|
new_product_type_conf,
|
|
@@ -932,7 +931,7 @@ class EODataAccessGateway:
|
|
|
932
931
|
|
|
933
932
|
def available_providers(
|
|
934
933
|
self, product_type: Optional[str] = None, by_group: bool = False
|
|
935
|
-
) ->
|
|
934
|
+
) -> list[str]:
|
|
936
935
|
"""Gives the sorted list of the available providers or groups
|
|
937
936
|
|
|
938
937
|
The providers or groups are sorted first by their priority level in descending order,
|
|
@@ -959,7 +958,7 @@ class EODataAccessGateway:
|
|
|
959
958
|
|
|
960
959
|
# If by_group is True, keep only the highest priority for each group
|
|
961
960
|
if by_group:
|
|
962
|
-
group_priority:
|
|
961
|
+
group_priority: dict[str, int] = {}
|
|
963
962
|
for name, priority in providers:
|
|
964
963
|
if name not in group_priority or priority > group_priority[name]:
|
|
965
964
|
group_priority[name] = priority
|
|
@@ -1026,7 +1025,7 @@ class EODataAccessGateway:
|
|
|
1026
1025
|
missionStartDate: Optional[str] = None,
|
|
1027
1026
|
missionEndDate: Optional[str] = None,
|
|
1028
1027
|
**kwargs: Any,
|
|
1029
|
-
) ->
|
|
1028
|
+
) -> list[str]:
|
|
1030
1029
|
"""
|
|
1031
1030
|
Find EODAG product type IDs that best match a set of search parameters.
|
|
1032
1031
|
|
|
@@ -1084,7 +1083,7 @@ class EODataAccessGateway:
|
|
|
1084
1083
|
query = p.parse(text)
|
|
1085
1084
|
results = searcher.search(query, limit=None)
|
|
1086
1085
|
|
|
1087
|
-
guesses:
|
|
1086
|
+
guesses: list[dict[str, str]] = [dict(r) for r in results or []]
|
|
1088
1087
|
|
|
1089
1088
|
# datetime filtering
|
|
1090
1089
|
if missionStartDate or missionEndDate:
|
|
@@ -1125,8 +1124,8 @@ class EODataAccessGateway:
|
|
|
1125
1124
|
raise_errors: bool = False,
|
|
1126
1125
|
start: Optional[str] = None,
|
|
1127
1126
|
end: Optional[str] = None,
|
|
1128
|
-
geom: Optional[Union[str,
|
|
1129
|
-
locations: Optional[
|
|
1127
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1128
|
+
locations: Optional[dict[str, str]] = None,
|
|
1130
1129
|
provider: Optional[str] = None,
|
|
1131
1130
|
count: bool = False,
|
|
1132
1131
|
**kwargs: Any,
|
|
@@ -1205,7 +1204,7 @@ class EODataAccessGateway:
|
|
|
1205
1204
|
items_per_page=items_per_page,
|
|
1206
1205
|
)
|
|
1207
1206
|
|
|
1208
|
-
errors:
|
|
1207
|
+
errors: list[tuple[str, Exception]] = []
|
|
1209
1208
|
# Loop over available providers and return the first non-empty results
|
|
1210
1209
|
for i, search_plugin in enumerate(search_plugins):
|
|
1211
1210
|
search_plugin.clear()
|
|
@@ -1234,8 +1233,8 @@ class EODataAccessGateway:
|
|
|
1234
1233
|
items_per_page: int = DEFAULT_ITEMS_PER_PAGE,
|
|
1235
1234
|
start: Optional[str] = None,
|
|
1236
1235
|
end: Optional[str] = None,
|
|
1237
|
-
geom: Optional[Union[str,
|
|
1238
|
-
locations: Optional[
|
|
1236
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1237
|
+
locations: Optional[dict[str, str]] = None,
|
|
1239
1238
|
**kwargs: Any,
|
|
1240
1239
|
) -> Iterator[SearchResult]:
|
|
1241
1240
|
"""Iterate over the pages of a products search.
|
|
@@ -1411,8 +1410,8 @@ class EODataAccessGateway:
|
|
|
1411
1410
|
items_per_page: Optional[int] = None,
|
|
1412
1411
|
start: Optional[str] = None,
|
|
1413
1412
|
end: Optional[str] = None,
|
|
1414
|
-
geom: Optional[Union[str,
|
|
1415
|
-
locations: Optional[
|
|
1413
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1414
|
+
locations: Optional[dict[str, str]] = None,
|
|
1416
1415
|
**kwargs: Any,
|
|
1417
1416
|
) -> SearchResult:
|
|
1418
1417
|
"""Search and return all the products matching the search criteria.
|
|
@@ -1633,7 +1632,7 @@ class EODataAccessGateway:
|
|
|
1633
1632
|
if not getattr(plugin.config, "discover_product_types", {}).get("fetch_url"):
|
|
1634
1633
|
return None
|
|
1635
1634
|
|
|
1636
|
-
kwargs:
|
|
1635
|
+
kwargs: dict[str, Any] = {"productType": product_type}
|
|
1637
1636
|
|
|
1638
1637
|
# append auth if needed
|
|
1639
1638
|
if getattr(plugin.config, "need_auth", False):
|
|
@@ -1651,11 +1650,11 @@ class EODataAccessGateway:
|
|
|
1651
1650
|
self,
|
|
1652
1651
|
start: Optional[str] = None,
|
|
1653
1652
|
end: Optional[str] = None,
|
|
1654
|
-
geom: Optional[Union[str,
|
|
1655
|
-
locations: Optional[
|
|
1653
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1654
|
+
locations: Optional[dict[str, str]] = None,
|
|
1656
1655
|
provider: Optional[str] = None,
|
|
1657
1656
|
**kwargs: Any,
|
|
1658
|
-
) ->
|
|
1657
|
+
) -> tuple[list[Union[Search, Api]], dict[str, Any]]:
|
|
1659
1658
|
"""Internal method to prepare the search kwargs and get the search plugins.
|
|
1660
1659
|
|
|
1661
1660
|
Product query:
|
|
@@ -1763,7 +1762,7 @@ class EODataAccessGateway:
|
|
|
1763
1762
|
|
|
1764
1763
|
preferred_provider = self.get_preferred_provider()[0]
|
|
1765
1764
|
|
|
1766
|
-
search_plugins:
|
|
1765
|
+
search_plugins: list[Union[Search, Api]] = []
|
|
1767
1766
|
for plugin in self._plugins_manager.get_search_plugins(
|
|
1768
1767
|
product_type=product_type, provider=provider
|
|
1769
1768
|
):
|
|
@@ -1833,10 +1832,10 @@ class EODataAccessGateway:
|
|
|
1833
1832
|
max_items_per_page,
|
|
1834
1833
|
)
|
|
1835
1834
|
|
|
1836
|
-
results:
|
|
1835
|
+
results: list[EOProduct] = []
|
|
1837
1836
|
total_results: Optional[int] = 0 if count else None
|
|
1838
1837
|
|
|
1839
|
-
errors:
|
|
1838
|
+
errors: list[tuple[str, Exception]] = []
|
|
1840
1839
|
|
|
1841
1840
|
try:
|
|
1842
1841
|
prep = PreparedSearch(count=count)
|
|
@@ -1984,7 +1983,7 @@ class EODataAccessGateway:
|
|
|
1984
1983
|
return results
|
|
1985
1984
|
|
|
1986
1985
|
@staticmethod
|
|
1987
|
-
def group_by_extent(searches:
|
|
1986
|
+
def group_by_extent(searches: list[SearchResult]) -> list[SearchResult]:
|
|
1988
1987
|
"""Combines multiple SearchResults and return a list of SearchResults grouped
|
|
1989
1988
|
by extent (i.e. bounding box).
|
|
1990
1989
|
|
|
@@ -1993,7 +1992,7 @@ class EODataAccessGateway:
|
|
|
1993
1992
|
"""
|
|
1994
1993
|
# Dict with extents as keys, each extent being defined by a str
|
|
1995
1994
|
# "{minx}{miny}{maxx}{maxy}" (each float rounded to 2 dec).
|
|
1996
|
-
products_grouped_by_extent:
|
|
1995
|
+
products_grouped_by_extent: dict[str, Any] = {}
|
|
1997
1996
|
|
|
1998
1997
|
for search in searches:
|
|
1999
1998
|
for product in search:
|
|
@@ -2015,7 +2014,7 @@ class EODataAccessGateway:
|
|
|
2015
2014
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
2016
2015
|
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
2017
2016
|
**kwargs: Unpack[DownloadConf],
|
|
2018
|
-
) ->
|
|
2017
|
+
) -> list[str]:
|
|
2019
2018
|
"""Download all products resulting from a search.
|
|
2020
2019
|
|
|
2021
2020
|
:param search_result: A collection of EO products resulting from a search
|
|
@@ -2273,7 +2272,7 @@ class EODataAccessGateway:
|
|
|
2273
2272
|
properties, associating parameters to their annotated type, and a additional_properties attribute
|
|
2274
2273
|
"""
|
|
2275
2274
|
# only fetch providers if product type is not found
|
|
2276
|
-
available_product_types = [
|
|
2275
|
+
available_product_types: list[str] = [
|
|
2277
2276
|
pt["ID"]
|
|
2278
2277
|
for pt in self.list_product_types(provider=provider, fetch_providers=False)
|
|
2279
2278
|
]
|
|
@@ -2304,13 +2303,13 @@ class EODataAccessGateway:
|
|
|
2304
2303
|
**model_fields_to_annotated(CommonQueryables.model_fields),
|
|
2305
2304
|
)
|
|
2306
2305
|
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2306
|
+
additional_properties = False
|
|
2307
|
+
additional_information = []
|
|
2308
|
+
queryable_properties: dict[str, Any] = {}
|
|
2310
2309
|
|
|
2311
2310
|
for plugin in self._plugins_manager.get_search_plugins(product_type, provider):
|
|
2312
2311
|
# attach product type config
|
|
2313
|
-
product_type_configs = {}
|
|
2312
|
+
product_type_configs: dict[str, Any] = {}
|
|
2314
2313
|
if product_type:
|
|
2315
2314
|
self._attach_product_type_config(plugin, product_type)
|
|
2316
2315
|
product_type_configs[product_type] = plugin.config.product_type_config
|
|
@@ -2330,6 +2329,7 @@ class EODataAccessGateway:
|
|
|
2330
2329
|
"queryables from provider %s could not be fetched due to an authentication error",
|
|
2331
2330
|
plugin.provider,
|
|
2332
2331
|
)
|
|
2332
|
+
|
|
2333
2333
|
plugin_queryables = plugin.list_queryables(
|
|
2334
2334
|
kwargs,
|
|
2335
2335
|
available_product_types,
|
|
@@ -2337,17 +2337,23 @@ class EODataAccessGateway:
|
|
|
2337
2337
|
product_type,
|
|
2338
2338
|
pt_alias,
|
|
2339
2339
|
)
|
|
2340
|
-
|
|
2341
|
-
if not plugin_queryables.additional_properties:
|
|
2342
|
-
queryables.additional_properties = False
|
|
2340
|
+
|
|
2343
2341
|
if plugin_queryables.additional_information:
|
|
2344
|
-
|
|
2345
|
-
f"{provider}: {plugin_queryables.additional_information}"
|
|
2342
|
+
additional_information.append(
|
|
2343
|
+
f"{plugin.provider}: {plugin_queryables.additional_information}"
|
|
2346
2344
|
)
|
|
2345
|
+
queryable_properties = {**plugin_queryables, **queryable_properties}
|
|
2346
|
+
additional_properties = (
|
|
2347
|
+
additional_properties or plugin_queryables.additional_properties
|
|
2348
|
+
)
|
|
2347
2349
|
|
|
2348
|
-
return
|
|
2350
|
+
return QueryablesDict(
|
|
2351
|
+
additional_properties=additional_properties,
|
|
2352
|
+
additional_information=" | ".join(additional_information),
|
|
2353
|
+
**queryable_properties,
|
|
2354
|
+
)
|
|
2349
2355
|
|
|
2350
|
-
def available_sortables(self) ->
|
|
2356
|
+
def available_sortables(self) -> dict[str, Optional[ProviderSortables]]:
|
|
2351
2357
|
"""For each provider, gives its available sortable parameter(s) and its maximum
|
|
2352
2358
|
number of them if it supports the sorting feature, otherwise gives None.
|
|
2353
2359
|
|
|
@@ -2355,7 +2361,7 @@ class EODataAccessGateway:
|
|
|
2355
2361
|
its (their) maximum number as value(s).
|
|
2356
2362
|
:raises: :class:`~eodag.utils.exceptions.UnsupportedProvider`
|
|
2357
2363
|
"""
|
|
2358
|
-
sortables:
|
|
2364
|
+
sortables: dict[str, Optional[ProviderSortables]] = {}
|
|
2359
2365
|
provider_search_plugins = self._plugins_manager.get_search_plugins()
|
|
2360
2366
|
for provider_search_plugin in provider_search_plugins:
|
|
2361
2367
|
provider = provider_search_plugin.provider
|
eodag/api/product/_assets.py
CHANGED
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import re
|
|
21
21
|
from collections import UserDict
|
|
22
|
-
from typing import TYPE_CHECKING, Any,
|
|
22
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
23
23
|
|
|
24
24
|
from eodag.utils.exceptions import NotAvailableError
|
|
25
25
|
from eodag.utils.repr import dict_to_html_table
|
|
@@ -31,12 +31,27 @@ if TYPE_CHECKING:
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class AssetsDict(UserDict):
|
|
34
|
-
"""A UserDict object
|
|
35
|
-
:class:`~eodag.api.product._product.EOProduct` resulting from a
|
|
34
|
+
"""A UserDict object which values are :class:`~eodag.api.product._assets.Asset`
|
|
35
|
+
contained in a :class:`~eodag.api.product._product.EOProduct` resulting from a
|
|
36
|
+
search.
|
|
36
37
|
|
|
37
38
|
:param product: Product resulting from a search
|
|
38
39
|
:param args: (optional) Arguments used to init the dictionary
|
|
39
40
|
:param kwargs: (optional) Additional named-arguments used to init the dictionary
|
|
41
|
+
|
|
42
|
+
Example
|
|
43
|
+
-------
|
|
44
|
+
|
|
45
|
+
>>> from eodag.api.product import EOProduct
|
|
46
|
+
>>> product = EOProduct(
|
|
47
|
+
... provider="foo",
|
|
48
|
+
... properties={"id": "bar", "geometry": "POINT (0 0)"}
|
|
49
|
+
... )
|
|
50
|
+
>>> type(product.assets)
|
|
51
|
+
<class 'eodag.api.product._assets.AssetsDict'>
|
|
52
|
+
>>> product.assets.update({"foo": {"href": "http://somewhere/something"}})
|
|
53
|
+
>>> product.assets
|
|
54
|
+
{'foo': {'href': 'http://somewhere/something'}}
|
|
40
55
|
"""
|
|
41
56
|
|
|
42
57
|
product: EOProduct
|
|
@@ -45,10 +60,10 @@ class AssetsDict(UserDict):
|
|
|
45
60
|
self.product = product
|
|
46
61
|
super(AssetsDict, self).__init__(*args, **kwargs)
|
|
47
62
|
|
|
48
|
-
def __setitem__(self, key: str, value:
|
|
63
|
+
def __setitem__(self, key: str, value: dict[str, Any]) -> None:
|
|
49
64
|
super().__setitem__(key, Asset(self.product, key, value))
|
|
50
65
|
|
|
51
|
-
def as_dict(self) ->
|
|
66
|
+
def as_dict(self) -> dict[str, Any]:
|
|
52
67
|
"""Builds a representation of AssetsDict to enable its serialization
|
|
53
68
|
|
|
54
69
|
:returns: The representation of a :class:`~eodag.api.product._assets.AssetsDict`
|
|
@@ -56,22 +71,29 @@ class AssetsDict(UserDict):
|
|
|
56
71
|
"""
|
|
57
72
|
return {k: v.as_dict() for k, v in self.data.items()}
|
|
58
73
|
|
|
59
|
-
def get_values(self, asset_filter: str = "") ->
|
|
74
|
+
def get_values(self, asset_filter: str = "", regex=True) -> list[Asset]:
|
|
60
75
|
"""
|
|
61
76
|
retrieves the assets matching the given filter
|
|
62
77
|
|
|
63
78
|
:param asset_filter: regex filter with which the assets should be matched
|
|
79
|
+
:param regex: Uses regex to match the asset key or simply compare strings
|
|
64
80
|
:return: list of assets
|
|
65
81
|
"""
|
|
66
82
|
if asset_filter:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
if regex:
|
|
84
|
+
filter_regex = re.compile(asset_filter)
|
|
85
|
+
assets_keys = list(self.keys())
|
|
86
|
+
assets_keys = list(filter(filter_regex.fullmatch, assets_keys))
|
|
87
|
+
else:
|
|
88
|
+
assets_keys = [a for a in self.keys() if a == asset_filter]
|
|
70
89
|
filtered_assets = {}
|
|
71
90
|
if len(assets_keys) > 0:
|
|
72
91
|
filtered_assets = {a_key: self.get(a_key) for a_key in assets_keys}
|
|
73
92
|
assets_values = [a for a in filtered_assets.values() if a and "href" in a]
|
|
74
|
-
if not assets_values:
|
|
93
|
+
if not assets_values and regex:
|
|
94
|
+
# retry without regex
|
|
95
|
+
return self.get_values(asset_filter, regex=False)
|
|
96
|
+
elif not assets_values:
|
|
75
97
|
raise NotAvailableError(
|
|
76
98
|
rf"No asset key matching re.fullmatch(r'{asset_filter}') was found in {self.product}"
|
|
77
99
|
)
|
|
@@ -119,13 +141,27 @@ class AssetsDict(UserDict):
|
|
|
119
141
|
|
|
120
142
|
|
|
121
143
|
class Asset(UserDict):
|
|
122
|
-
"""A UserDict object containg one of the
|
|
123
|
-
:
|
|
144
|
+
"""A UserDict object containg one of the
|
|
145
|
+
:attr:`~eodag.api.product._product.EOProduct.assets` resulting from a search.
|
|
124
146
|
|
|
125
147
|
:param product: Product resulting from a search
|
|
126
148
|
:param key: asset key
|
|
127
149
|
:param args: (optional) Arguments used to init the dictionary
|
|
128
150
|
:param kwargs: (optional) Additional named-arguments used to init the dictionary
|
|
151
|
+
|
|
152
|
+
Example
|
|
153
|
+
-------
|
|
154
|
+
|
|
155
|
+
>>> from eodag.api.product import EOProduct
|
|
156
|
+
>>> product = EOProduct(
|
|
157
|
+
... provider="foo",
|
|
158
|
+
... properties={"id": "bar", "geometry": "POINT (0 0)"}
|
|
159
|
+
... )
|
|
160
|
+
>>> product.assets.update({"foo": {"href": "http://somewhere/something"}})
|
|
161
|
+
>>> type(product.assets["foo"])
|
|
162
|
+
<class 'eodag.api.product._assets.Asset'>
|
|
163
|
+
>>> product.assets["foo"]
|
|
164
|
+
{'href': 'http://somewhere/something'}
|
|
129
165
|
"""
|
|
130
166
|
|
|
131
167
|
product: EOProduct
|
|
@@ -138,7 +174,7 @@ class Asset(UserDict):
|
|
|
138
174
|
self.key = key
|
|
139
175
|
super(Asset, self).__init__(*args, **kwargs)
|
|
140
176
|
|
|
141
|
-
def as_dict(self) ->
|
|
177
|
+
def as_dict(self) -> dict[str, Any]:
|
|
142
178
|
"""Builds a representation of Asset to enable its serialization
|
|
143
179
|
|
|
144
180
|
:returns: The representation of a :class:`~eodag.api.product._assets.Asset` as a
|