eodag 3.1.0b1__py3-none-any.whl → 3.1.0b2__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 +59 -52
- eodag/api/product/_assets.py +5 -5
- eodag/api/product/_product.py +27 -12
- 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 +62 -74
- eodag/api/search_result.py +13 -23
- eodag/cli.py +4 -4
- eodag/config.py +66 -69
- eodag/plugins/apis/base.py +1 -1
- eodag/plugins/apis/ecmwf.py +10 -9
- eodag/plugins/apis/usgs.py +11 -10
- 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 +14 -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 +47 -66
- 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 +35 -40
- eodag/plugins/search/build_search_result.py +69 -68
- 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 +16 -15
- eodag/plugins/search/qssearch.py +56 -52
- eodag/plugins/search/stac_list_assets.py +85 -0
- eodag/plugins/search/static_stac_search.py +3 -3
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +288 -288
- eodag/resources/providers.yml +146 -6
- eodag/resources/stac_api.yml +2 -2
- eodag/resources/user_conf_template.yml +11 -0
- 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 +40 -38
- eodag/rest/types/collections_search.py +3 -3
- eodag/rest/types/eodag_search.py +23 -23
- eodag/rest/types/queryables.py +13 -13
- 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 +24 -18
- 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 +81 -40
- 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 +208 -0
- eodag/utils/stac_reader.py +10 -10
- {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/METADATA +5 -4
- eodag-3.1.0b2.dist-info/RECORD +113 -0
- {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/entry_points.txt +1 -0
- eodag-3.1.0b1.dist-info/RECORD +0 -108
- {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/LICENSE +0 -0
- {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/WHEEL +0 -0
- {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/top_level.txt +0 -0
eodag/api/core.py
CHANGED
|
@@ -24,7 +24,7 @@ import re
|
|
|
24
24
|
import shutil
|
|
25
25
|
import tempfile
|
|
26
26
|
from operator import itemgetter
|
|
27
|
-
from typing import TYPE_CHECKING, Any,
|
|
27
|
+
from typing import TYPE_CHECKING, Any, Iterator, Optional, Union
|
|
28
28
|
|
|
29
29
|
import geojson
|
|
30
30
|
import pkg_resources
|
|
@@ -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
|
|
|
@@ -335,7 +335,7 @@ class EODataAccessGateway:
|
|
|
335
335
|
new_priority = max_priority + 1
|
|
336
336
|
self._plugins_manager.set_priority(provider, new_priority)
|
|
337
337
|
|
|
338
|
-
def get_preferred_provider(self) ->
|
|
338
|
+
def get_preferred_provider(self) -> tuple[str, int]:
|
|
339
339
|
"""Get the provider currently set as the preferred one for searching
|
|
340
340
|
products, along with its priority.
|
|
341
341
|
|
|
@@ -351,7 +351,7 @@ class EODataAccessGateway:
|
|
|
351
351
|
def update_providers_config(
|
|
352
352
|
self,
|
|
353
353
|
yaml_conf: Optional[str] = None,
|
|
354
|
-
dict_conf: Optional[
|
|
354
|
+
dict_conf: Optional[dict[str, Any]] = None,
|
|
355
355
|
) -> None:
|
|
356
356
|
"""Update providers configuration with given input.
|
|
357
357
|
Can be used to add a provider to existing configuration or update
|
|
@@ -397,12 +397,12 @@ class EODataAccessGateway:
|
|
|
397
397
|
name: str,
|
|
398
398
|
url: Optional[str] = None,
|
|
399
399
|
priority: Optional[int] = None,
|
|
400
|
-
search:
|
|
401
|
-
products:
|
|
400
|
+
search: dict[str, Any] = {"type": "StacSearch"},
|
|
401
|
+
products: dict[str, Any] = {
|
|
402
402
|
GENERIC_PRODUCT_TYPE: {"productType": "{productType}"}
|
|
403
403
|
},
|
|
404
|
-
download:
|
|
405
|
-
**kwargs:
|
|
404
|
+
download: dict[str, Any] = {"type": "HTTPDownload", "auth_error_code": 401},
|
|
405
|
+
**kwargs: dict[str, Any],
|
|
406
406
|
):
|
|
407
407
|
"""Adds a new provider.
|
|
408
408
|
|
|
@@ -421,7 +421,7 @@ class EODataAccessGateway:
|
|
|
421
421
|
:param download: Download :class:`~eodag.config.PluginConfig` mapping
|
|
422
422
|
:param kwargs: Additional :class:`~eodag.config.ProviderConfig` mapping
|
|
423
423
|
"""
|
|
424
|
-
conf_dict:
|
|
424
|
+
conf_dict: dict[str, Any] = {
|
|
425
425
|
name: {
|
|
426
426
|
"url": url,
|
|
427
427
|
"search": {"type": "StacSearch", **search},
|
|
@@ -565,7 +565,7 @@ class EODataAccessGateway:
|
|
|
565
565
|
main_locations_config = locations_config[main_key]
|
|
566
566
|
|
|
567
567
|
logger.info("Locations configuration loaded from %s" % locations_conf_path)
|
|
568
|
-
self.locations_config:
|
|
568
|
+
self.locations_config: list[dict[str, Any]] = main_locations_config
|
|
569
569
|
else:
|
|
570
570
|
logger.info(
|
|
571
571
|
"Could not load locations configuration from %s" % locations_conf_path
|
|
@@ -574,7 +574,7 @@ class EODataAccessGateway:
|
|
|
574
574
|
|
|
575
575
|
def list_product_types(
|
|
576
576
|
self, provider: Optional[str] = None, fetch_providers: bool = True
|
|
577
|
-
) ->
|
|
577
|
+
) -> list[dict[str, Any]]:
|
|
578
578
|
"""Lists supported product types.
|
|
579
579
|
|
|
580
580
|
:param provider: (optional) The name of a provider that must support the product
|
|
@@ -588,7 +588,7 @@ class EODataAccessGateway:
|
|
|
588
588
|
# First, update product types list if possible
|
|
589
589
|
self.fetch_product_types_list(provider=provider)
|
|
590
590
|
|
|
591
|
-
product_types:
|
|
591
|
+
product_types: list[dict[str, Any]] = []
|
|
592
592
|
|
|
593
593
|
providers_configs = (
|
|
594
594
|
list(self.providers_config.values())
|
|
@@ -644,7 +644,7 @@ class EODataAccessGateway:
|
|
|
644
644
|
providers_to_fetch = [provider]
|
|
645
645
|
|
|
646
646
|
# providers discovery confs that are fetchable
|
|
647
|
-
providers_discovery_configs_fetchable:
|
|
647
|
+
providers_discovery_configs_fetchable: dict[str, Any] = {}
|
|
648
648
|
# check if any provider has not already been fetched for product types
|
|
649
649
|
already_fetched = True
|
|
650
650
|
for provider_to_fetch in providers_to_fetch:
|
|
@@ -767,7 +767,7 @@ class EODataAccessGateway:
|
|
|
767
767
|
|
|
768
768
|
def discover_product_types(
|
|
769
769
|
self, provider: Optional[str] = None
|
|
770
|
-
) -> Optional[
|
|
770
|
+
) -> Optional[dict[str, Any]]:
|
|
771
771
|
"""Fetch providers for product types
|
|
772
772
|
|
|
773
773
|
:param provider: The name of a provider or provider-group to fetch. Defaults to
|
|
@@ -787,7 +787,7 @@ class EODataAccessGateway:
|
|
|
787
787
|
raise UnsupportedProvider(
|
|
788
788
|
f"The requested provider is not (yet) supported: {provider}"
|
|
789
789
|
)
|
|
790
|
-
ext_product_types_conf:
|
|
790
|
+
ext_product_types_conf: dict[str, Any] = {}
|
|
791
791
|
providers_to_fetch = [
|
|
792
792
|
p
|
|
793
793
|
for p in (
|
|
@@ -800,7 +800,7 @@ class EODataAccessGateway:
|
|
|
800
800
|
else self.available_providers()
|
|
801
801
|
)
|
|
802
802
|
]
|
|
803
|
-
kwargs:
|
|
803
|
+
kwargs: dict[str, Any] = {}
|
|
804
804
|
for provider in providers_to_fetch:
|
|
805
805
|
if hasattr(self.providers_config[provider], "search"):
|
|
806
806
|
search_plugin_config = self.providers_config[provider].search
|
|
@@ -841,7 +841,7 @@ class EODataAccessGateway:
|
|
|
841
841
|
return sort_dict(ext_product_types_conf)
|
|
842
842
|
|
|
843
843
|
def update_product_types_list(
|
|
844
|
-
self, ext_product_types_conf:
|
|
844
|
+
self, ext_product_types_conf: dict[str, Optional[dict[str, dict[str, Any]]]]
|
|
845
845
|
) -> None:
|
|
846
846
|
"""Update eodag product types list
|
|
847
847
|
|
|
@@ -869,7 +869,7 @@ class EODataAccessGateway:
|
|
|
869
869
|
provider,
|
|
870
870
|
)
|
|
871
871
|
continue
|
|
872
|
-
new_product_types:
|
|
872
|
+
new_product_types: list[str] = []
|
|
873
873
|
for (
|
|
874
874
|
new_product_type,
|
|
875
875
|
new_product_type_conf,
|
|
@@ -932,7 +932,7 @@ class EODataAccessGateway:
|
|
|
932
932
|
|
|
933
933
|
def available_providers(
|
|
934
934
|
self, product_type: Optional[str] = None, by_group: bool = False
|
|
935
|
-
) ->
|
|
935
|
+
) -> list[str]:
|
|
936
936
|
"""Gives the sorted list of the available providers or groups
|
|
937
937
|
|
|
938
938
|
The providers or groups are sorted first by their priority level in descending order,
|
|
@@ -959,7 +959,7 @@ class EODataAccessGateway:
|
|
|
959
959
|
|
|
960
960
|
# If by_group is True, keep only the highest priority for each group
|
|
961
961
|
if by_group:
|
|
962
|
-
group_priority:
|
|
962
|
+
group_priority: dict[str, int] = {}
|
|
963
963
|
for name, priority in providers:
|
|
964
964
|
if name not in group_priority or priority > group_priority[name]:
|
|
965
965
|
group_priority[name] = priority
|
|
@@ -1026,7 +1026,7 @@ class EODataAccessGateway:
|
|
|
1026
1026
|
missionStartDate: Optional[str] = None,
|
|
1027
1027
|
missionEndDate: Optional[str] = None,
|
|
1028
1028
|
**kwargs: Any,
|
|
1029
|
-
) ->
|
|
1029
|
+
) -> list[str]:
|
|
1030
1030
|
"""
|
|
1031
1031
|
Find EODAG product type IDs that best match a set of search parameters.
|
|
1032
1032
|
|
|
@@ -1084,7 +1084,7 @@ class EODataAccessGateway:
|
|
|
1084
1084
|
query = p.parse(text)
|
|
1085
1085
|
results = searcher.search(query, limit=None)
|
|
1086
1086
|
|
|
1087
|
-
guesses:
|
|
1087
|
+
guesses: list[dict[str, str]] = [dict(r) for r in results or []]
|
|
1088
1088
|
|
|
1089
1089
|
# datetime filtering
|
|
1090
1090
|
if missionStartDate or missionEndDate:
|
|
@@ -1125,8 +1125,8 @@ class EODataAccessGateway:
|
|
|
1125
1125
|
raise_errors: bool = False,
|
|
1126
1126
|
start: Optional[str] = None,
|
|
1127
1127
|
end: Optional[str] = None,
|
|
1128
|
-
geom: Optional[Union[str,
|
|
1129
|
-
locations: Optional[
|
|
1128
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1129
|
+
locations: Optional[dict[str, str]] = None,
|
|
1130
1130
|
provider: Optional[str] = None,
|
|
1131
1131
|
count: bool = False,
|
|
1132
1132
|
**kwargs: Any,
|
|
@@ -1205,7 +1205,7 @@ class EODataAccessGateway:
|
|
|
1205
1205
|
items_per_page=items_per_page,
|
|
1206
1206
|
)
|
|
1207
1207
|
|
|
1208
|
-
errors:
|
|
1208
|
+
errors: list[tuple[str, Exception]] = []
|
|
1209
1209
|
# Loop over available providers and return the first non-empty results
|
|
1210
1210
|
for i, search_plugin in enumerate(search_plugins):
|
|
1211
1211
|
search_plugin.clear()
|
|
@@ -1234,8 +1234,8 @@ class EODataAccessGateway:
|
|
|
1234
1234
|
items_per_page: int = DEFAULT_ITEMS_PER_PAGE,
|
|
1235
1235
|
start: Optional[str] = None,
|
|
1236
1236
|
end: Optional[str] = None,
|
|
1237
|
-
geom: Optional[Union[str,
|
|
1238
|
-
locations: Optional[
|
|
1237
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1238
|
+
locations: Optional[dict[str, str]] = None,
|
|
1239
1239
|
**kwargs: Any,
|
|
1240
1240
|
) -> Iterator[SearchResult]:
|
|
1241
1241
|
"""Iterate over the pages of a products search.
|
|
@@ -1411,8 +1411,8 @@ class EODataAccessGateway:
|
|
|
1411
1411
|
items_per_page: Optional[int] = None,
|
|
1412
1412
|
start: Optional[str] = None,
|
|
1413
1413
|
end: Optional[str] = None,
|
|
1414
|
-
geom: Optional[Union[str,
|
|
1415
|
-
locations: Optional[
|
|
1414
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1415
|
+
locations: Optional[dict[str, str]] = None,
|
|
1416
1416
|
**kwargs: Any,
|
|
1417
1417
|
) -> SearchResult:
|
|
1418
1418
|
"""Search and return all the products matching the search criteria.
|
|
@@ -1633,7 +1633,7 @@ class EODataAccessGateway:
|
|
|
1633
1633
|
if not getattr(plugin.config, "discover_product_types", {}).get("fetch_url"):
|
|
1634
1634
|
return None
|
|
1635
1635
|
|
|
1636
|
-
kwargs:
|
|
1636
|
+
kwargs: dict[str, Any] = {"productType": product_type}
|
|
1637
1637
|
|
|
1638
1638
|
# append auth if needed
|
|
1639
1639
|
if getattr(plugin.config, "need_auth", False):
|
|
@@ -1651,11 +1651,11 @@ class EODataAccessGateway:
|
|
|
1651
1651
|
self,
|
|
1652
1652
|
start: Optional[str] = None,
|
|
1653
1653
|
end: Optional[str] = None,
|
|
1654
|
-
geom: Optional[Union[str,
|
|
1655
|
-
locations: Optional[
|
|
1654
|
+
geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
|
|
1655
|
+
locations: Optional[dict[str, str]] = None,
|
|
1656
1656
|
provider: Optional[str] = None,
|
|
1657
1657
|
**kwargs: Any,
|
|
1658
|
-
) ->
|
|
1658
|
+
) -> tuple[list[Union[Search, Api]], dict[str, Any]]:
|
|
1659
1659
|
"""Internal method to prepare the search kwargs and get the search plugins.
|
|
1660
1660
|
|
|
1661
1661
|
Product query:
|
|
@@ -1763,7 +1763,7 @@ class EODataAccessGateway:
|
|
|
1763
1763
|
|
|
1764
1764
|
preferred_provider = self.get_preferred_provider()[0]
|
|
1765
1765
|
|
|
1766
|
-
search_plugins:
|
|
1766
|
+
search_plugins: list[Union[Search, Api]] = []
|
|
1767
1767
|
for plugin in self._plugins_manager.get_search_plugins(
|
|
1768
1768
|
product_type=product_type, provider=provider
|
|
1769
1769
|
):
|
|
@@ -1833,10 +1833,10 @@ class EODataAccessGateway:
|
|
|
1833
1833
|
max_items_per_page,
|
|
1834
1834
|
)
|
|
1835
1835
|
|
|
1836
|
-
results:
|
|
1836
|
+
results: list[EOProduct] = []
|
|
1837
1837
|
total_results: Optional[int] = 0 if count else None
|
|
1838
1838
|
|
|
1839
|
-
errors:
|
|
1839
|
+
errors: list[tuple[str, Exception]] = []
|
|
1840
1840
|
|
|
1841
1841
|
try:
|
|
1842
1842
|
prep = PreparedSearch(count=count)
|
|
@@ -1984,7 +1984,7 @@ class EODataAccessGateway:
|
|
|
1984
1984
|
return results
|
|
1985
1985
|
|
|
1986
1986
|
@staticmethod
|
|
1987
|
-
def group_by_extent(searches:
|
|
1987
|
+
def group_by_extent(searches: list[SearchResult]) -> list[SearchResult]:
|
|
1988
1988
|
"""Combines multiple SearchResults and return a list of SearchResults grouped
|
|
1989
1989
|
by extent (i.e. bounding box).
|
|
1990
1990
|
|
|
@@ -1993,7 +1993,7 @@ class EODataAccessGateway:
|
|
|
1993
1993
|
"""
|
|
1994
1994
|
# Dict with extents as keys, each extent being defined by a str
|
|
1995
1995
|
# "{minx}{miny}{maxx}{maxy}" (each float rounded to 2 dec).
|
|
1996
|
-
products_grouped_by_extent:
|
|
1996
|
+
products_grouped_by_extent: dict[str, Any] = {}
|
|
1997
1997
|
|
|
1998
1998
|
for search in searches:
|
|
1999
1999
|
for product in search:
|
|
@@ -2015,7 +2015,7 @@ class EODataAccessGateway:
|
|
|
2015
2015
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
2016
2016
|
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
2017
2017
|
**kwargs: Unpack[DownloadConf],
|
|
2018
|
-
) ->
|
|
2018
|
+
) -> list[str]:
|
|
2019
2019
|
"""Download all products resulting from a search.
|
|
2020
2020
|
|
|
2021
2021
|
:param search_result: A collection of EO products resulting from a search
|
|
@@ -2273,7 +2273,7 @@ class EODataAccessGateway:
|
|
|
2273
2273
|
properties, associating parameters to their annotated type, and a additional_properties attribute
|
|
2274
2274
|
"""
|
|
2275
2275
|
# only fetch providers if product type is not found
|
|
2276
|
-
available_product_types = [
|
|
2276
|
+
available_product_types: list[str] = [
|
|
2277
2277
|
pt["ID"]
|
|
2278
2278
|
for pt in self.list_product_types(provider=provider, fetch_providers=False)
|
|
2279
2279
|
]
|
|
@@ -2304,13 +2304,13 @@ class EODataAccessGateway:
|
|
|
2304
2304
|
**model_fields_to_annotated(CommonQueryables.model_fields),
|
|
2305
2305
|
)
|
|
2306
2306
|
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2307
|
+
additional_properties = False
|
|
2308
|
+
additional_information = []
|
|
2309
|
+
queryable_properties: dict[str, Any] = {}
|
|
2310
2310
|
|
|
2311
2311
|
for plugin in self._plugins_manager.get_search_plugins(product_type, provider):
|
|
2312
2312
|
# attach product type config
|
|
2313
|
-
product_type_configs = {}
|
|
2313
|
+
product_type_configs: dict[str, Any] = {}
|
|
2314
2314
|
if product_type:
|
|
2315
2315
|
self._attach_product_type_config(plugin, product_type)
|
|
2316
2316
|
product_type_configs[product_type] = plugin.config.product_type_config
|
|
@@ -2330,6 +2330,7 @@ class EODataAccessGateway:
|
|
|
2330
2330
|
"queryables from provider %s could not be fetched due to an authentication error",
|
|
2331
2331
|
plugin.provider,
|
|
2332
2332
|
)
|
|
2333
|
+
|
|
2333
2334
|
plugin_queryables = plugin.list_queryables(
|
|
2334
2335
|
kwargs,
|
|
2335
2336
|
available_product_types,
|
|
@@ -2337,17 +2338,23 @@ class EODataAccessGateway:
|
|
|
2337
2338
|
product_type,
|
|
2338
2339
|
pt_alias,
|
|
2339
2340
|
)
|
|
2340
|
-
|
|
2341
|
-
if not plugin_queryables.additional_properties:
|
|
2342
|
-
queryables.additional_properties = False
|
|
2341
|
+
|
|
2343
2342
|
if plugin_queryables.additional_information:
|
|
2344
|
-
|
|
2345
|
-
f"{provider}: {plugin_queryables.additional_information}"
|
|
2343
|
+
additional_information.append(
|
|
2344
|
+
f"{plugin.provider}: {plugin_queryables.additional_information}"
|
|
2346
2345
|
)
|
|
2346
|
+
queryable_properties = {**plugin_queryables, **queryable_properties}
|
|
2347
|
+
additional_properties = (
|
|
2348
|
+
additional_properties or plugin_queryables.additional_properties
|
|
2349
|
+
)
|
|
2347
2350
|
|
|
2348
|
-
return
|
|
2351
|
+
return QueryablesDict(
|
|
2352
|
+
additional_properties=additional_properties,
|
|
2353
|
+
additional_information=" | ".join(additional_information),
|
|
2354
|
+
**queryable_properties,
|
|
2355
|
+
)
|
|
2349
2356
|
|
|
2350
|
-
def available_sortables(self) ->
|
|
2357
|
+
def available_sortables(self) -> dict[str, Optional[ProviderSortables]]:
|
|
2351
2358
|
"""For each provider, gives its available sortable parameter(s) and its maximum
|
|
2352
2359
|
number of them if it supports the sorting feature, otherwise gives None.
|
|
2353
2360
|
|
|
@@ -2355,7 +2362,7 @@ class EODataAccessGateway:
|
|
|
2355
2362
|
its (their) maximum number as value(s).
|
|
2356
2363
|
:raises: :class:`~eodag.utils.exceptions.UnsupportedProvider`
|
|
2357
2364
|
"""
|
|
2358
|
-
sortables:
|
|
2365
|
+
sortables: dict[str, Optional[ProviderSortables]] = {}
|
|
2359
2366
|
provider_search_plugins = self._plugins_manager.get_search_plugins()
|
|
2360
2367
|
for provider_search_plugin in provider_search_plugins:
|
|
2361
2368
|
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
|
|
@@ -45,10 +45,10 @@ class AssetsDict(UserDict):
|
|
|
45
45
|
self.product = product
|
|
46
46
|
super(AssetsDict, self).__init__(*args, **kwargs)
|
|
47
47
|
|
|
48
|
-
def __setitem__(self, key: str, value:
|
|
48
|
+
def __setitem__(self, key: str, value: dict[str, Any]) -> None:
|
|
49
49
|
super().__setitem__(key, Asset(self.product, key, value))
|
|
50
50
|
|
|
51
|
-
def as_dict(self) ->
|
|
51
|
+
def as_dict(self) -> dict[str, Any]:
|
|
52
52
|
"""Builds a representation of AssetsDict to enable its serialization
|
|
53
53
|
|
|
54
54
|
:returns: The representation of a :class:`~eodag.api.product._assets.AssetsDict`
|
|
@@ -56,7 +56,7 @@ class AssetsDict(UserDict):
|
|
|
56
56
|
"""
|
|
57
57
|
return {k: v.as_dict() for k, v in self.data.items()}
|
|
58
58
|
|
|
59
|
-
def get_values(self, asset_filter: str = "") ->
|
|
59
|
+
def get_values(self, asset_filter: str = "") -> list[Asset]:
|
|
60
60
|
"""
|
|
61
61
|
retrieves the assets matching the given filter
|
|
62
62
|
|
|
@@ -138,7 +138,7 @@ class Asset(UserDict):
|
|
|
138
138
|
self.key = key
|
|
139
139
|
super(Asset, self).__init__(*args, **kwargs)
|
|
140
140
|
|
|
141
|
-
def as_dict(self) ->
|
|
141
|
+
def as_dict(self) -> dict[str, Any]:
|
|
142
142
|
"""Builds a representation of Asset to enable its serialization
|
|
143
143
|
|
|
144
144
|
:returns: The representation of a :class:`~eodag.api.product._assets.Asset` as a
|
eodag/api/product/_product.py
CHANGED
|
@@ -22,7 +22,7 @@ import logging
|
|
|
22
22
|
import os
|
|
23
23
|
import re
|
|
24
24
|
import tempfile
|
|
25
|
-
from typing import TYPE_CHECKING, Any,
|
|
25
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
26
26
|
|
|
27
27
|
import requests
|
|
28
28
|
from requests import RequestException
|
|
@@ -38,7 +38,7 @@ try:
|
|
|
38
38
|
except ImportError:
|
|
39
39
|
from eodag.api.product._assets import AssetsDict
|
|
40
40
|
|
|
41
|
-
from eodag.api.product.drivers import DRIVERS, NoDriver
|
|
41
|
+
from eodag.api.product.drivers import DRIVERS, LEGACY_DRIVERS, NoDriver
|
|
42
42
|
from eodag.api.product.metadata_mapping import (
|
|
43
43
|
DEFAULT_GEOMETRY,
|
|
44
44
|
NOT_AVAILABLE,
|
|
@@ -113,7 +113,7 @@ class EOProduct:
|
|
|
113
113
|
"""
|
|
114
114
|
|
|
115
115
|
provider: str
|
|
116
|
-
properties:
|
|
116
|
+
properties: dict[str, Any]
|
|
117
117
|
product_type: Optional[str]
|
|
118
118
|
location: str
|
|
119
119
|
filename: str
|
|
@@ -122,9 +122,11 @@ class EOProduct:
|
|
|
122
122
|
geometry: BaseGeometry
|
|
123
123
|
search_intersection: Optional[BaseGeometry]
|
|
124
124
|
assets: AssetsDict
|
|
125
|
+
#: Driver enables additional methods to be called on the EOProduct
|
|
126
|
+
driver: DatasetDriver
|
|
125
127
|
|
|
126
128
|
def __init__(
|
|
127
|
-
self, provider: str, properties:
|
|
129
|
+
self, provider: str, properties: dict[str, Any], **kwargs: Any
|
|
128
130
|
) -> None:
|
|
129
131
|
self.provider = provider
|
|
130
132
|
self.product_type = kwargs.get("productType")
|
|
@@ -175,7 +177,7 @@ class EOProduct:
|
|
|
175
177
|
self.downloader: Optional[Union[Api, Download]] = None
|
|
176
178
|
self.downloader_auth: Optional[Authentication] = None
|
|
177
179
|
|
|
178
|
-
def as_dict(self) ->
|
|
180
|
+
def as_dict(self) -> dict[str, Any]:
|
|
179
181
|
"""Builds a representation of EOProduct as a dictionary to enable its geojson
|
|
180
182
|
serialization
|
|
181
183
|
|
|
@@ -186,7 +188,7 @@ class EOProduct:
|
|
|
186
188
|
if self.search_intersection is not None:
|
|
187
189
|
search_intersection = geometry.mapping(self.search_intersection)
|
|
188
190
|
|
|
189
|
-
geojson_repr:
|
|
191
|
+
geojson_repr: dict[str, Any] = {
|
|
190
192
|
"type": "Feature",
|
|
191
193
|
"geometry": geometry.mapping(self.geometry),
|
|
192
194
|
"id": self.properties["id"],
|
|
@@ -206,7 +208,7 @@ class EOProduct:
|
|
|
206
208
|
return geojson_repr
|
|
207
209
|
|
|
208
210
|
@classmethod
|
|
209
|
-
def from_geojson(cls, feature:
|
|
211
|
+
def from_geojson(cls, feature: dict[str, Any]) -> EOProduct:
|
|
210
212
|
"""Builds an :class:`~eodag.api.product._product.EOProduct` object from its
|
|
211
213
|
representation as geojson
|
|
212
214
|
|
|
@@ -356,7 +358,7 @@ class EOProduct:
|
|
|
356
358
|
|
|
357
359
|
def _init_progress_bar(
|
|
358
360
|
self, progress_callback: Optional[ProgressCallback]
|
|
359
|
-
) ->
|
|
361
|
+
) -> tuple[ProgressCallback, bool]:
|
|
360
362
|
# progress bar init
|
|
361
363
|
if progress_callback is None:
|
|
362
364
|
progress_callback = ProgressCallback(position=1)
|
|
@@ -463,12 +465,20 @@ class EOProduct:
|
|
|
463
465
|
)
|
|
464
466
|
if not isinstance(auth, AuthBase):
|
|
465
467
|
auth = None
|
|
468
|
+
# Read the ssl_verify parameter used on the provider config
|
|
469
|
+
# to ensure the same behavior for get_quicklook as other download functions
|
|
470
|
+
ssl_verify = (
|
|
471
|
+
getattr(self.downloader.config, "ssl_verify", True)
|
|
472
|
+
if self.downloader
|
|
473
|
+
else True
|
|
474
|
+
)
|
|
466
475
|
with requests.get(
|
|
467
476
|
self.properties["quicklook"],
|
|
468
477
|
stream=True,
|
|
469
478
|
auth=auth,
|
|
470
479
|
headers=USER_AGENT,
|
|
471
480
|
timeout=DEFAULT_STREAM_REQUESTS_TIMEOUT,
|
|
481
|
+
verify=ssl_verify,
|
|
472
482
|
) as stream:
|
|
473
483
|
try:
|
|
474
484
|
stream.raise_for_status()
|
|
@@ -498,11 +508,16 @@ class EOProduct:
|
|
|
498
508
|
try:
|
|
499
509
|
for driver_conf in DRIVERS:
|
|
500
510
|
if all([criteria(self) for criteria in driver_conf["criteria"]]):
|
|
501
|
-
|
|
511
|
+
driver = driver_conf["driver"]
|
|
512
|
+
break
|
|
513
|
+
# use legacy driver for deprecated get_data method usage
|
|
514
|
+
for lecacy_conf in LEGACY_DRIVERS:
|
|
515
|
+
if all([criteria(self) for criteria in lecacy_conf["criteria"]]):
|
|
516
|
+
driver.legacy = lecacy_conf["driver"]
|
|
517
|
+
break
|
|
518
|
+
return driver
|
|
502
519
|
except TypeError:
|
|
503
|
-
logger.
|
|
504
|
-
"Drivers definition seems out-of-date, please update eodag-cube"
|
|
505
|
-
)
|
|
520
|
+
logger.info("No driver matching")
|
|
506
521
|
pass
|
|
507
522
|
return NoDriver()
|
|
508
523
|
|
|
@@ -16,14 +16,91 @@
|
|
|
16
16
|
# See the License for the specific language governing permissions and
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
"""EODAG drivers package"""
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
from typing import Callable, TypedDict
|
|
22
|
+
|
|
19
23
|
from eodag.api.product.drivers.base import DatasetDriver, NoDriver
|
|
24
|
+
from eodag.api.product.drivers.generic import GenericDriver
|
|
25
|
+
from eodag.api.product.drivers.sentinel1 import Sentinel1Driver
|
|
26
|
+
from eodag.api.product.drivers.sentinel2 import Sentinel2Driver
|
|
20
27
|
|
|
21
28
|
try:
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
# import from eodag-cube if installed
|
|
30
|
+
from eodag_cube.api.product.drivers.generic import ( # pyright: ignore[reportMissingImports]; isort: skip
|
|
31
|
+
GenericDriver as GenericDriver_cube,
|
|
32
|
+
)
|
|
33
|
+
from eodag_cube.api.product.drivers.sentinel2_l1c import ( # pyright: ignore[reportMissingImports]; isort: skip
|
|
34
|
+
Sentinel2L1C as Sentinel2L1C_cube,
|
|
35
|
+
)
|
|
36
|
+
from eodag_cube.api.product.drivers.stac_assets import ( # pyright: ignore[reportMissingImports]; isort: skip
|
|
37
|
+
StacAssets as StacAssets_cube,
|
|
24
38
|
)
|
|
25
39
|
except ImportError:
|
|
26
|
-
|
|
40
|
+
GenericDriver_cube = NoDriver
|
|
41
|
+
Sentinel2L1C_cube = NoDriver
|
|
42
|
+
StacAssets_cube = NoDriver
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DriverCriteria(TypedDict):
|
|
46
|
+
"""Driver criteria definition"""
|
|
47
|
+
|
|
48
|
+
#: Function that returns True if the driver is suitable for the given :class:`~eodag.api.product._product.EOProduct`
|
|
49
|
+
criteria: list[Callable[..., bool]]
|
|
50
|
+
#: driver to use
|
|
51
|
+
driver: DatasetDriver
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#: list of drivers and their criteria
|
|
55
|
+
DRIVERS: list[DriverCriteria] = [
|
|
56
|
+
{
|
|
57
|
+
"criteria": [
|
|
58
|
+
lambda prod: True
|
|
59
|
+
if (prod.product_type or "").startswith("S2_MSI_")
|
|
60
|
+
else False
|
|
61
|
+
],
|
|
62
|
+
"driver": Sentinel2Driver(),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"criteria": [
|
|
66
|
+
lambda prod: True
|
|
67
|
+
if (prod.product_type or "").startswith("S1_SAR_")
|
|
68
|
+
else False
|
|
69
|
+
],
|
|
70
|
+
"driver": Sentinel1Driver(),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"criteria": [lambda prod: True],
|
|
74
|
+
"driver": GenericDriver(),
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
#: list of legacy drivers and their criteria
|
|
80
|
+
LEGACY_DRIVERS: list[DriverCriteria] = [
|
|
81
|
+
{
|
|
82
|
+
"criteria": [
|
|
83
|
+
lambda prod: True if len(getattr(prod, "assets", {})) > 0 else False
|
|
84
|
+
],
|
|
85
|
+
"driver": StacAssets_cube(),
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"criteria": [lambda prod: True if "assets" in prod.properties else False],
|
|
89
|
+
"driver": StacAssets_cube(),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"criteria": [
|
|
93
|
+
lambda prod: True
|
|
94
|
+
if getattr(prod, "product_type") == "S2_MSI_L1C"
|
|
95
|
+
else False
|
|
96
|
+
],
|
|
97
|
+
"driver": Sentinel2L1C_cube(),
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"criteria": [lambda prod: True],
|
|
101
|
+
"driver": GenericDriver_cube(),
|
|
102
|
+
},
|
|
103
|
+
]
|
|
27
104
|
|
|
28
105
|
# exportable content
|
|
29
|
-
__all__ = ["DRIVERS", "DatasetDriver", "NoDriver"]
|
|
106
|
+
__all__ = ["DRIVERS", "DatasetDriver", "GenericDriver", "NoDriver", "Sentinel2Driver"]
|