eodag 3.9.1__py3-none-any.whl → 4.0.0a1__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 +378 -419
- eodag/api/product/__init__.py +3 -3
- eodag/api/product/_product.py +68 -40
- eodag/api/product/drivers/__init__.py +3 -5
- eodag/api/product/drivers/base.py +1 -18
- eodag/api/product/metadata_mapping.py +151 -215
- eodag/api/search_result.py +13 -7
- eodag/cli.py +72 -395
- eodag/config.py +46 -50
- eodag/plugins/apis/base.py +2 -2
- eodag/plugins/apis/ecmwf.py +20 -21
- eodag/plugins/apis/usgs.py +37 -33
- eodag/plugins/authentication/aws_auth.py +36 -1
- eodag/plugins/authentication/base.py +18 -3
- eodag/plugins/authentication/sas_auth.py +15 -0
- eodag/plugins/crunch/filter_date.py +3 -3
- eodag/plugins/crunch/filter_latest_intersect.py +2 -2
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/download/aws.py +45 -41
- eodag/plugins/download/base.py +13 -14
- eodag/plugins/download/http.py +65 -65
- eodag/plugins/manager.py +28 -29
- eodag/plugins/search/__init__.py +3 -4
- eodag/plugins/search/base.py +128 -77
- eodag/plugins/search/build_search_result.py +105 -107
- eodag/plugins/search/cop_marine.py +44 -47
- eodag/plugins/search/csw.py +33 -33
- eodag/plugins/search/qssearch.py +335 -354
- eodag/plugins/search/stac_list_assets.py +1 -1
- eodag/plugins/search/static_stac_search.py +31 -31
- eodag/resources/{product_types.yml → collections.yml} +2353 -2429
- eodag/resources/ext_collections.json +1 -0
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/providers.yml +2432 -2714
- eodag/resources/stac_provider.yml +46 -90
- eodag/types/queryables.py +55 -91
- eodag/types/search_args.py +1 -1
- eodag/utils/__init__.py +94 -21
- eodag/utils/exceptions.py +6 -6
- eodag/utils/free_text_search.py +3 -3
- {eodag-3.9.1.dist-info → eodag-4.0.0a1.dist-info}/METADATA +11 -88
- eodag-4.0.0a1.dist-info/RECORD +92 -0
- {eodag-3.9.1.dist-info → eodag-4.0.0a1.dist-info}/entry_points.txt +0 -4
- eodag/plugins/authentication/oauth.py +0 -60
- eodag/plugins/download/creodias_s3.py +0 -64
- eodag/plugins/download/s3rest.py +0 -351
- eodag/plugins/search/data_request_search.py +0 -565
- eodag/resources/stac.yml +0 -294
- eodag/resources/stac_api.yml +0 -2105
- eodag/rest/__init__.py +0 -24
- eodag/rest/cache.py +0 -70
- eodag/rest/config.py +0 -67
- eodag/rest/constants.py +0 -26
- eodag/rest/core.py +0 -764
- eodag/rest/errors.py +0 -210
- eodag/rest/server.py +0 -604
- eodag/rest/server.wsgi +0 -6
- eodag/rest/stac.py +0 -1032
- eodag/rest/templates/README +0 -1
- eodag/rest/types/__init__.py +0 -18
- eodag/rest/types/collections_search.py +0 -44
- eodag/rest/types/eodag_search.py +0 -386
- eodag/rest/types/queryables.py +0 -174
- eodag/rest/types/stac_search.py +0 -272
- eodag/rest/utils/__init__.py +0 -207
- eodag/rest/utils/cql_evaluate.py +0 -119
- eodag/rest/utils/rfc3339.py +0 -64
- eodag-3.9.1.dist-info/RECORD +0 -115
- {eodag-3.9.1.dist-info → eodag-4.0.0a1.dist-info}/WHEEL +0 -0
- {eodag-3.9.1.dist-info → eodag-4.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {eodag-3.9.1.dist-info → eodag-4.0.0a1.dist-info}/top_level.txt +0 -0
|
@@ -57,6 +57,7 @@ from eodag.utils import (
|
|
|
57
57
|
DEFAULT_SEARCH_TIMEOUT,
|
|
58
58
|
deepcopy,
|
|
59
59
|
dict_items_recursive_sort,
|
|
60
|
+
format_string,
|
|
60
61
|
get_geometry_from_various,
|
|
61
62
|
)
|
|
62
63
|
from eodag.utils.cache import instance_cached_method
|
|
@@ -144,7 +145,6 @@ ECMWF_KEYWORDS = {
|
|
|
144
145
|
COP_DS_KEYWORDS = {
|
|
145
146
|
"aerosol_type",
|
|
146
147
|
"altitude",
|
|
147
|
-
"product_type",
|
|
148
148
|
"band",
|
|
149
149
|
"cdr_type",
|
|
150
150
|
"data_format",
|
|
@@ -176,6 +176,7 @@ COP_DS_KEYWORDS = {
|
|
|
176
176
|
"pressure_level",
|
|
177
177
|
"processing_level",
|
|
178
178
|
"processing_type",
|
|
179
|
+
"product_type",
|
|
179
180
|
"product_version",
|
|
180
181
|
"quantity",
|
|
181
182
|
"rcm",
|
|
@@ -200,9 +201,9 @@ COP_DS_KEYWORDS = {
|
|
|
200
201
|
|
|
201
202
|
ALLOWED_KEYWORDS = ECMWF_KEYWORDS | COP_DS_KEYWORDS
|
|
202
203
|
|
|
203
|
-
END = "
|
|
204
|
+
END = "end_datetime"
|
|
204
205
|
|
|
205
|
-
START = "
|
|
206
|
+
START = "start_datetime"
|
|
206
207
|
|
|
207
208
|
|
|
208
209
|
def ecmwf_mtd() -> dict[str, Any]:
|
|
@@ -305,11 +306,11 @@ def append_time(input_date: date, time: Optional[str]) -> datetime:
|
|
|
305
306
|
"""
|
|
306
307
|
Parses a time string in format HHMM and appends it to a date.
|
|
307
308
|
|
|
308
|
-
if the time string is in format HH:MM we convert it to HHMM
|
|
309
|
+
if the time string is in format HH:MM or HH_MM we convert it to HHMM
|
|
309
310
|
"""
|
|
310
311
|
if not time:
|
|
311
312
|
time = "0000"
|
|
312
|
-
time =
|
|
313
|
+
time = re.sub(":|_", "", time)
|
|
313
314
|
if time == "2400":
|
|
314
315
|
time = "0000"
|
|
315
316
|
dt = datetime.combine(input_date, datetime.strptime(time, "%H%M").time())
|
|
@@ -435,14 +436,15 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
435
436
|
used to parse metadata but that must not be included to the query
|
|
436
437
|
* :attr:`~eodag.config.PluginConfig.end_date_excluded` (``bool``): Set to `False` if
|
|
437
438
|
provider does not include end date to search
|
|
439
|
+
* :attr:`~eodag.config.PluginConfig.dates_required` (``bool``): if date parameters are mandatory in the request
|
|
438
440
|
* :attr:`~eodag.config.PluginConfig.discover_queryables`
|
|
439
441
|
(:class:`~eodag.config.PluginConfig.DiscoverQueryables`): configuration to fetch the queryables from a
|
|
440
442
|
provider queryables endpoint; It has the following keys:
|
|
441
443
|
|
|
442
444
|
* :attr:`~eodag.config.PluginConfig.DiscoverQueryables.fetch_url` (``str``): url to fetch the queryables valid
|
|
443
|
-
for all
|
|
444
|
-
* :attr:`~eodag.config.PluginConfig.DiscoverQueryables.
|
|
445
|
-
queryables for a specific
|
|
445
|
+
for all collections
|
|
446
|
+
* :attr:`~eodag.config.PluginConfig.DiscoverQueryables.collection_fetch_url` (``str``): url to fetch the
|
|
447
|
+
queryables for a specific collection
|
|
446
448
|
* :attr:`~eodag.config.PluginConfig.DiscoverQueryables.constraints_url` (``str``): url of the constraint file
|
|
447
449
|
used to build queryables
|
|
448
450
|
"""
|
|
@@ -453,10 +455,10 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
453
455
|
**{
|
|
454
456
|
"id": "$.id",
|
|
455
457
|
"title": "$.id",
|
|
456
|
-
"
|
|
457
|
-
"
|
|
458
|
+
"order:status": OFFLINE_STATUS,
|
|
459
|
+
"eodag:download_link": "$.null",
|
|
458
460
|
"geometry": ["feature", "$.geometry"],
|
|
459
|
-
"
|
|
461
|
+
"eodag:default_geometry": "POLYGON((180 -90, 180 90, -180 90, -180 -90, 180 -90))",
|
|
460
462
|
},
|
|
461
463
|
**config.metadata_mapping,
|
|
462
464
|
}
|
|
@@ -499,10 +501,10 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
499
501
|
:param kwargs: keyword arguments to be used in the search
|
|
500
502
|
:returns: list of products and number of products (optional)
|
|
501
503
|
"""
|
|
502
|
-
|
|
503
|
-
if not
|
|
504
|
-
|
|
505
|
-
kwargs = self._preprocess_search_params(kwargs,
|
|
504
|
+
collection = prep.collection
|
|
505
|
+
if not collection:
|
|
506
|
+
collection = kwargs.get("collection")
|
|
507
|
+
kwargs = self._preprocess_search_params(kwargs, collection)
|
|
506
508
|
result, num_items = super().query(prep, **kwargs)
|
|
507
509
|
if prep.count and not num_items:
|
|
508
510
|
num_items = 1
|
|
@@ -514,11 +516,11 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
514
516
|
super().clear()
|
|
515
517
|
|
|
516
518
|
def build_query_string(
|
|
517
|
-
self,
|
|
519
|
+
self, collection: str, query_dict: dict[str, Any]
|
|
518
520
|
) -> tuple[dict[str, Any], str]:
|
|
519
521
|
"""Build The query string using the search parameters
|
|
520
522
|
|
|
521
|
-
:param
|
|
523
|
+
:param collection: collection id
|
|
522
524
|
:param query_dict: keyword arguments to be used in the query string
|
|
523
525
|
:return: formatted query params and encode query string
|
|
524
526
|
"""
|
|
@@ -533,21 +535,21 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
533
535
|
ordered_kwargs.update(query_dict)
|
|
534
536
|
|
|
535
537
|
return super().build_query_string(
|
|
536
|
-
|
|
538
|
+
collection=collection, query_dict=ordered_kwargs
|
|
537
539
|
)
|
|
538
540
|
|
|
539
541
|
def _preprocess_search_params(
|
|
540
|
-
self, params: dict[str, Any],
|
|
542
|
+
self, params: dict[str, Any], collection: Optional[str]
|
|
541
543
|
) -> dict[str, Any]:
|
|
542
544
|
"""Preprocess search parameters before making a request to the CDS API.
|
|
543
545
|
|
|
544
546
|
This method is responsible for checking and updating the provided search parameters
|
|
545
|
-
to ensure that required parameters like '
|
|
546
|
-
'
|
|
547
|
+
to ensure that required parameters like 'collection', 'start_datetime',
|
|
548
|
+
'end_datetime', and 'geometry' are properly set. If not specified
|
|
547
549
|
in the input parameters, default values or values from the configuration are used.
|
|
548
550
|
|
|
549
551
|
:param params: Search parameters to be preprocessed.
|
|
550
|
-
:param
|
|
552
|
+
:param collection: (optional) collection id
|
|
551
553
|
"""
|
|
552
554
|
|
|
553
555
|
_dc_qs = params.get("_dc_qs")
|
|
@@ -574,7 +576,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
574
576
|
# dates
|
|
575
577
|
# check if default dates have to be added
|
|
576
578
|
if getattr(self.config, "dates_required", False):
|
|
577
|
-
self._check_date_params(params,
|
|
579
|
+
self._check_date_params(params, collection)
|
|
578
580
|
|
|
579
581
|
# adapt end date if it is midnight
|
|
580
582
|
if END in params:
|
|
@@ -611,65 +613,61 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
611
613
|
return params
|
|
612
614
|
|
|
613
615
|
def _check_date_params(
|
|
614
|
-
self, keywords: dict[str, Any],
|
|
616
|
+
self, keywords: dict[str, Any], collection: Optional[str]
|
|
615
617
|
) -> None:
|
|
616
618
|
"""checks if start and end date are present in the keywords and adds them if not"""
|
|
617
619
|
|
|
618
620
|
if START and END in keywords:
|
|
619
621
|
return
|
|
620
622
|
|
|
621
|
-
|
|
623
|
+
collection_conf = getattr(self.config, "metadata_mapping", {})
|
|
622
624
|
if (
|
|
623
|
-
|
|
624
|
-
and
|
|
625
|
-
and "metadata_mapping" in self.config.products[
|
|
625
|
+
collection
|
|
626
|
+
and collection in self.config.products
|
|
627
|
+
and "metadata_mapping" in self.config.products[collection]
|
|
626
628
|
):
|
|
627
|
-
|
|
629
|
+
collection_conf = self.config.products[collection]["metadata_mapping"]
|
|
628
630
|
|
|
629
631
|
# start time given, end time missing
|
|
630
632
|
if START in keywords:
|
|
631
633
|
keywords[END] = (
|
|
632
634
|
keywords[START]
|
|
633
|
-
if END in
|
|
634
|
-
else self.
|
|
635
|
-
|
|
636
|
-
)
|
|
635
|
+
if END in collection_conf
|
|
636
|
+
# else self.get_collection_cfg_value(
|
|
637
|
+
else self.get_collection_cfg_dates(None, today().isoformat())[1]
|
|
637
638
|
)
|
|
638
639
|
return
|
|
639
640
|
|
|
640
|
-
if END in
|
|
641
|
-
mapping =
|
|
641
|
+
if END in collection_conf:
|
|
642
|
+
mapping = collection_conf[START]
|
|
642
643
|
if not isinstance(mapping, list):
|
|
643
|
-
mapping =
|
|
644
|
+
mapping = collection_conf[END]
|
|
644
645
|
if isinstance(mapping, list):
|
|
645
646
|
# if startTime is not given but other time params (e.g. year/month/(day)) are given,
|
|
646
647
|
# no default date is required
|
|
647
648
|
start, end = ecmwf_temporal_to_eodag(keywords)
|
|
648
649
|
if start is None:
|
|
649
|
-
|
|
650
|
-
|
|
650
|
+
col_start, col_end = self.get_collection_cfg_dates(
|
|
651
|
+
DEFAULT_MISSION_START_DATE, today().isoformat()
|
|
651
652
|
)
|
|
653
|
+
keywords[START] = col_start
|
|
652
654
|
keywords[END] = (
|
|
653
|
-
keywords[START]
|
|
654
|
-
if END in product_type_conf
|
|
655
|
-
else self.get_product_type_cfg_value(
|
|
656
|
-
"missionEndDate", today().isoformat()
|
|
657
|
-
)
|
|
655
|
+
keywords[START] if END in collection_conf else col_end
|
|
658
656
|
)
|
|
659
657
|
else:
|
|
660
658
|
keywords[START] = start
|
|
661
659
|
keywords[END] = end
|
|
662
660
|
|
|
663
|
-
def
|
|
664
|
-
self,
|
|
661
|
+
def _get_collection_queryables(
|
|
662
|
+
self, collection: Optional[str], alias: Optional[str], filters: dict[str, Any]
|
|
665
663
|
) -> QueryablesDict:
|
|
666
664
|
"""Override to set additional_properties to false."""
|
|
667
665
|
default_values: dict[str, Any] = deepcopy(
|
|
668
|
-
getattr(self.config, "products", {}).get(
|
|
666
|
+
getattr(self.config, "products", {}).get(collection, {})
|
|
669
667
|
)
|
|
670
668
|
default_values.pop("metadata_mapping", None)
|
|
671
669
|
|
|
672
|
-
filters["
|
|
670
|
+
filters["collection"] = collection
|
|
673
671
|
queryables = self.discover_queryables(**{**default_values, **filters}) or {}
|
|
674
672
|
|
|
675
673
|
return QueryablesDict(additional_properties=False, **queryables)
|
|
@@ -679,13 +677,13 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
679
677
|
) -> Optional[dict[str, Annotated[Any, FieldInfo]]]:
|
|
680
678
|
"""Fetch queryables list from provider using its constraints file
|
|
681
679
|
|
|
682
|
-
:param kwargs: additional filters for queryables (`
|
|
680
|
+
:param kwargs: additional filters for queryables (`collection` and other search
|
|
683
681
|
arguments)
|
|
684
682
|
:returns: fetched queryable parameters dict
|
|
685
683
|
"""
|
|
686
|
-
|
|
684
|
+
collection = kwargs.pop("collection")
|
|
687
685
|
|
|
688
|
-
pt_config = self.
|
|
686
|
+
pt_config = self.get_collection_def_params(collection)
|
|
689
687
|
|
|
690
688
|
default_values = deepcopy(pt_config)
|
|
691
689
|
default_values.pop("metadata_mapping", None)
|
|
@@ -698,7 +696,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
698
696
|
|
|
699
697
|
# extract default datetime
|
|
700
698
|
processed_filters = self._preprocess_search_params(
|
|
701
|
-
deepcopy(filters),
|
|
699
|
+
deepcopy(filters), collection
|
|
702
700
|
)
|
|
703
701
|
|
|
704
702
|
constraints_url = format_metadata(
|
|
@@ -714,7 +712,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
714
712
|
form: list[dict[str, Any]] = self._fetch_data(form_url)
|
|
715
713
|
|
|
716
714
|
formated_filters = self.format_as_provider_keyword(
|
|
717
|
-
|
|
715
|
+
collection, processed_filters
|
|
718
716
|
)
|
|
719
717
|
# we re-apply kwargs input to consider override of year, month, day and time.
|
|
720
718
|
for k, v in {**default_values, **kwargs}.items():
|
|
@@ -762,15 +760,15 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
762
760
|
else:
|
|
763
761
|
values_url = getattr(self.config, "available_values_url", "")
|
|
764
762
|
if not values_url:
|
|
765
|
-
return self.queryables_from_metadata_mapping(
|
|
763
|
+
return self.queryables_from_metadata_mapping(collection)
|
|
766
764
|
if "{" in values_url:
|
|
767
|
-
values_url = values_url
|
|
765
|
+
values_url = format_string(None, values_url, **filters)
|
|
768
766
|
data = self._fetch_data(values_url)
|
|
769
767
|
available_values = data["constraints"]
|
|
770
768
|
required_keywords = data.get("required", [])
|
|
771
769
|
|
|
772
770
|
# To check if all keywords are queryable parameters, we check if they are in the
|
|
773
|
-
# available values or the
|
|
771
|
+
# available values or the collection config (available values calculated from the
|
|
774
772
|
# constraints might not include all queryables)
|
|
775
773
|
for keyword in filters:
|
|
776
774
|
if (
|
|
@@ -781,6 +779,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
781
779
|
START,
|
|
782
780
|
END,
|
|
783
781
|
"geom",
|
|
782
|
+
"geometry",
|
|
784
783
|
}
|
|
785
784
|
and keyword not in [f["name"] for f in form]
|
|
786
785
|
and keyword.removeprefix(ECMWF_PREFIX)
|
|
@@ -1021,7 +1020,9 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1021
1020
|
if default and prop.get("type") == "string" and isinstance(default, list):
|
|
1022
1021
|
default = ",".join(default)
|
|
1023
1022
|
|
|
1024
|
-
is_required = bool(element.get("required"))
|
|
1023
|
+
is_required = bool(element.get("required")) and bool(
|
|
1024
|
+
available_values.get(name)
|
|
1025
|
+
)
|
|
1025
1026
|
if is_required:
|
|
1026
1027
|
required_list.append(name)
|
|
1027
1028
|
|
|
@@ -1075,32 +1076,32 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1075
1076
|
return queryables
|
|
1076
1077
|
|
|
1077
1078
|
def format_as_provider_keyword(
|
|
1078
|
-
self,
|
|
1079
|
+
self, collection: str, properties: dict[str, Any]
|
|
1079
1080
|
) -> dict[str, Any]:
|
|
1080
1081
|
"""Return provider equivalent keyword names from EODAG keywords.
|
|
1081
1082
|
|
|
1082
|
-
:param
|
|
1083
|
+
:param collection: collection id
|
|
1083
1084
|
:param properties: dict of properties to be formatted
|
|
1084
1085
|
:return: dict of formatted properties
|
|
1085
1086
|
"""
|
|
1086
|
-
properties["
|
|
1087
|
+
properties["collection"] = collection
|
|
1087
1088
|
|
|
1088
|
-
# provider
|
|
1089
|
-
|
|
1090
|
-
|
|
1089
|
+
# provider collection specific conf
|
|
1090
|
+
collection_def_params = self.get_collection_def_params(
|
|
1091
|
+
collection, format_variables=properties
|
|
1091
1092
|
)
|
|
1092
1093
|
|
|
1093
|
-
# Add to the query, the queryable parameters set in the provider
|
|
1094
|
+
# Add to the query, the queryable parameters set in the provider collection definition
|
|
1094
1095
|
properties.update(
|
|
1095
1096
|
{
|
|
1096
1097
|
k: v
|
|
1097
|
-
for k, v in
|
|
1098
|
+
for k, v in collection_def_params.items()
|
|
1098
1099
|
if k not in properties.keys()
|
|
1099
1100
|
and k in self.config.metadata_mapping.keys()
|
|
1100
1101
|
and isinstance(self.config.metadata_mapping[k], list)
|
|
1101
1102
|
}
|
|
1102
1103
|
)
|
|
1103
|
-
qp, _ = self.build_query_string(
|
|
1104
|
+
qp, _ = self.build_query_string(collection, properties)
|
|
1104
1105
|
|
|
1105
1106
|
return qp
|
|
1106
1107
|
|
|
@@ -1133,7 +1134,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1133
1134
|
:returns: list of single :class:`~eodag.api.product._product.EOProduct`
|
|
1134
1135
|
"""
|
|
1135
1136
|
|
|
1136
|
-
|
|
1137
|
+
collection = kwargs.get("collection")
|
|
1137
1138
|
|
|
1138
1139
|
result = results[0]
|
|
1139
1140
|
|
|
@@ -1151,27 +1152,27 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1151
1152
|
|
|
1152
1153
|
if result:
|
|
1153
1154
|
properties = result
|
|
1154
|
-
properties.update(result.pop("request_params", None) or {})
|
|
1155
|
+
properties.update(result.pop("eodag:request_params", None) or {})
|
|
1155
1156
|
|
|
1156
1157
|
properties = {k: v for k, v in properties.items() if not k.startswith("__")}
|
|
1157
1158
|
|
|
1158
1159
|
properties["geometry"] = properties.get("area") or DEFAULT_GEOMETRY
|
|
1159
1160
|
|
|
1160
1161
|
start, end = ecmwf_temporal_to_eodag(properties)
|
|
1161
|
-
properties["
|
|
1162
|
-
properties["
|
|
1162
|
+
properties["start_datetime"] = start
|
|
1163
|
+
properties["end_datetime"] = end
|
|
1163
1164
|
|
|
1164
1165
|
else:
|
|
1165
1166
|
# use all available query_params to parse properties
|
|
1166
1167
|
result_data: dict[str, Any] = {
|
|
1167
|
-
**results.
|
|
1168
|
+
**results.collection_def_params,
|
|
1168
1169
|
**sorted_unpaginated_qp,
|
|
1169
1170
|
**{"qs": sorted_unpaginated_qp},
|
|
1170
1171
|
}
|
|
1171
1172
|
|
|
1172
|
-
# update result with
|
|
1173
|
+
# update result with collection_def_params and search args if not None (and not auth)
|
|
1173
1174
|
kwargs.pop("auth", None)
|
|
1174
|
-
result_data.update(results.
|
|
1175
|
+
result_data.update(results.collection_def_params)
|
|
1175
1176
|
result_data = {
|
|
1176
1177
|
**result_data,
|
|
1177
1178
|
**{k: v for k, v in kwargs.items() if v is not None},
|
|
@@ -1186,17 +1187,18 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1186
1187
|
query_hash = hashlib.sha1(str(result_data).encode("UTF-8")).hexdigest()
|
|
1187
1188
|
|
|
1188
1189
|
properties["title"] = properties["id"] = (
|
|
1189
|
-
(
|
|
1190
|
+
(collection or kwargs.get("dataset", self.provider)).upper()
|
|
1190
1191
|
+ "_ORDERABLE_"
|
|
1191
1192
|
+ query_hash
|
|
1192
1193
|
)
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1194
|
+
|
|
1195
|
+
# collection alias (required by opentelemetry-instrumentation-eodag)
|
|
1196
|
+
if alias := getattr(self.config, "collection_config", {}).get("alias"):
|
|
1197
|
+
properties["eodag:alias"] = alias
|
|
1196
1198
|
|
|
1197
1199
|
qs = geojson.dumps(sorted_unpaginated_qp)
|
|
1198
1200
|
|
|
1199
|
-
# used by server mode to generate
|
|
1201
|
+
# used by server mode to generate eodag:download_link href
|
|
1200
1202
|
# TODO: to remove once the legacy server is removed
|
|
1201
1203
|
properties["_dc_qs"] = quote_plus(qs)
|
|
1202
1204
|
|
|
@@ -1245,12 +1247,12 @@ def _check_id(product: EOProduct) -> EOProduct:
|
|
|
1245
1247
|
if not on_response_mm:
|
|
1246
1248
|
return product
|
|
1247
1249
|
|
|
1248
|
-
logger.debug(f"Update product properties using given
|
|
1250
|
+
logger.debug(f"Update product properties using given eodag:order_id {product_id}")
|
|
1249
1251
|
on_response_mm_jsonpath = mtd_cfg_as_conversion_and_querypath(
|
|
1250
1252
|
on_response_mm,
|
|
1251
1253
|
)
|
|
1252
1254
|
properties_update = properties_from_json(
|
|
1253
|
-
{}, {**on_response_mm_jsonpath, **{"
|
|
1255
|
+
{}, {**on_response_mm_jsonpath, **{"eodag:order_id": (None, product_id)}}
|
|
1254
1256
|
)
|
|
1255
1257
|
product.properties.update(
|
|
1256
1258
|
{k: v for k, v in properties_update.items() if v != NOT_AVAILABLE}
|
|
@@ -1263,7 +1265,7 @@ def _check_id(product: EOProduct) -> EOProduct:
|
|
|
1263
1265
|
product.downloader._order_status(product=product, auth=auth) # type: ignore
|
|
1264
1266
|
# when a NotAvailableError is catched, it means the product is not ready and still needs to be polled
|
|
1265
1267
|
except NotAvailableError:
|
|
1266
|
-
product.properties["
|
|
1268
|
+
product.properties["order:status"] = STAGING_STATUS
|
|
1267
1269
|
except Exception as e:
|
|
1268
1270
|
if (
|
|
1269
1271
|
isinstance(e, DownloadError) or isinstance(e, ValidationError)
|
|
@@ -1275,16 +1277,16 @@ def _check_id(product: EOProduct) -> EOProduct:
|
|
|
1275
1277
|
|
|
1276
1278
|
# update product id
|
|
1277
1279
|
product.properties["id"] = product_id
|
|
1278
|
-
# update
|
|
1279
|
-
if product.
|
|
1280
|
-
product.
|
|
1280
|
+
# update collection if needed
|
|
1281
|
+
if product.collection is None:
|
|
1282
|
+
product.collection = product.properties.get("ecmwf:dataset")
|
|
1281
1283
|
# update product title
|
|
1282
1284
|
product.properties["title"] = (
|
|
1283
|
-
(product.
|
|
1285
|
+
(product.collection or product.provider).upper() + "_" + product_id
|
|
1284
1286
|
)
|
|
1285
|
-
# use NOT_AVAILABLE as fallback
|
|
1286
|
-
if product.
|
|
1287
|
-
product.
|
|
1287
|
+
# use NOT_AVAILABLE as fallback collection to avoid using guess_collection
|
|
1288
|
+
if product.collection is None:
|
|
1289
|
+
product.collection = NOT_AVAILABLE
|
|
1288
1290
|
|
|
1289
1291
|
return product
|
|
1290
1292
|
|
|
@@ -1363,15 +1365,15 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1363
1365
|
return [response.json()]
|
|
1364
1366
|
|
|
1365
1367
|
def build_query_string(
|
|
1366
|
-
self,
|
|
1368
|
+
self, collection: str, query_dict: dict[str, Any]
|
|
1367
1369
|
) -> tuple[dict[str, Any], str]:
|
|
1368
1370
|
"""Build The query string using the search parameters
|
|
1369
1371
|
|
|
1370
|
-
:param
|
|
1372
|
+
:param collection: collection id
|
|
1371
1373
|
:param query_dict: keyword arguments to be used in the query string
|
|
1372
1374
|
:return: formatted query params and encode query string
|
|
1373
1375
|
"""
|
|
1374
|
-
return QueryStringSearch.build_query_string(self,
|
|
1376
|
+
return QueryStringSearch.build_query_string(self, collection, query_dict)
|
|
1375
1377
|
|
|
1376
1378
|
def normalize_results(self, results, **kwargs):
|
|
1377
1379
|
"""Build :class:`~eodag.api.product._product.EOProduct` from provider result
|
|
@@ -1381,7 +1383,7 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1381
1383
|
:returns: list of single :class:`~eodag.api.product._product.EOProduct`
|
|
1382
1384
|
"""
|
|
1383
1385
|
|
|
1384
|
-
|
|
1386
|
+
collection = kwargs.get("collection")
|
|
1385
1387
|
|
|
1386
1388
|
result = results[0]
|
|
1387
1389
|
|
|
@@ -1415,9 +1417,9 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1415
1417
|
|
|
1416
1418
|
query_hash = hashlib.sha1(str(qs).encode("UTF-8")).hexdigest()
|
|
1417
1419
|
|
|
1418
|
-
# update result with
|
|
1420
|
+
# update result with collection_def_params and search args if not None (and not auth)
|
|
1419
1421
|
kwargs.pop("auth", None)
|
|
1420
|
-
result.update(results.
|
|
1422
|
+
result.update(results.collection_def_params)
|
|
1421
1423
|
result = dict(result, **{k: v for k, v in kwargs.items() if v is not None})
|
|
1422
1424
|
|
|
1423
1425
|
# parse properties
|
|
@@ -1427,17 +1429,16 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1427
1429
|
discovery_config=getattr(self.config, "discover_metadata", {}),
|
|
1428
1430
|
)
|
|
1429
1431
|
|
|
1430
|
-
properties = {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
}
|
|
1432
|
+
properties = {ecmwf_format(k): v for k, v in parsed_properties.items()}
|
|
1433
|
+
# collection alias (required by opentelemetry-instrumentation-eodag)
|
|
1434
|
+
if alias := getattr(self.config, "collection_config", {}).get("alias"):
|
|
1435
|
+
properties["eodag:alias"] = alias
|
|
1435
1436
|
|
|
1436
1437
|
def slugify(date_str: str) -> str:
|
|
1437
1438
|
return date_str.split("T")[0].replace("-", "")
|
|
1438
1439
|
|
|
1439
1440
|
# build product id
|
|
1440
|
-
product_id = (
|
|
1441
|
+
product_id = (collection or self.provider).upper()
|
|
1441
1442
|
|
|
1442
1443
|
start = properties.get(START, NOT_AVAILABLE)
|
|
1443
1444
|
end = properties.get(END, NOT_AVAILABLE)
|
|
@@ -1451,17 +1452,14 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1451
1452
|
|
|
1452
1453
|
properties["id"] = properties["title"] = product_id
|
|
1453
1454
|
|
|
1454
|
-
# used by server mode to generate
|
|
1455
|
+
# used by server mode to generate eodag:download_link href
|
|
1455
1456
|
properties["_dc_qs"] = quote_plus(qs)
|
|
1456
1457
|
|
|
1457
1458
|
product = EOProduct(
|
|
1458
1459
|
provider=self.provider,
|
|
1459
|
-
|
|
1460
|
+
collection=collection,
|
|
1460
1461
|
properties=properties,
|
|
1461
1462
|
)
|
|
1462
|
-
# use product_type_config as default properties
|
|
1463
|
-
product_type_config = getattr(self.config, "product_type_config", {})
|
|
1464
|
-
product.properties = dict(product_type_config, **product.properties)
|
|
1465
1463
|
|
|
1466
1464
|
return [
|
|
1467
1465
|
product,
|
|
@@ -1507,9 +1505,9 @@ class WekeoECMWFSearch(ECMWFSearch):
|
|
|
1507
1505
|
# id is order id (only letters and numbers) -> use parent normalize results
|
|
1508
1506
|
return super().normalize_results(results, **kwargs)
|
|
1509
1507
|
|
|
1510
|
-
# formating of
|
|
1508
|
+
# formating of eodag:order_link requires access to the collection value.
|
|
1511
1509
|
results.data = [
|
|
1512
|
-
{**result, **results.
|
|
1510
|
+
{**result, **results.collection_def_params} for result in results
|
|
1513
1511
|
]
|
|
1514
1512
|
|
|
1515
1513
|
normalized = QueryStringSearch.normalize_results(self, results, **kwargs)
|
|
@@ -1534,7 +1532,7 @@ class WekeoECMWFSearch(ECMWFSearch):
|
|
|
1534
1532
|
dataset = "_".join(splitted_id[:-1])
|
|
1535
1533
|
query_hash = splitted_id[-1]
|
|
1536
1534
|
product.properties["title"] = product.properties["id"] = (
|
|
1537
|
-
(product.
|
|
1535
|
+
(product.collection or dataset or self.provider).upper()
|
|
1538
1536
|
+ "_ORDERABLE_"
|
|
1539
1537
|
+ query_hash
|
|
1540
1538
|
)
|