eodag 4.0.0a4__py3-none-any.whl → 4.0.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/collection.py +65 -1
- eodag/api/core.py +65 -19
- eodag/api/product/_assets.py +1 -1
- eodag/api/product/_product.py +133 -18
- eodag/api/product/drivers/__init__.py +3 -1
- eodag/api/product/drivers/base.py +3 -1
- eodag/api/product/drivers/generic.py +9 -5
- eodag/api/product/drivers/sentinel1.py +14 -9
- eodag/api/product/drivers/sentinel2.py +14 -7
- eodag/api/product/metadata_mapping.py +5 -2
- eodag/api/provider.py +1 -0
- eodag/api/search_result.py +4 -1
- eodag/cli.py +17 -8
- eodag/config.py +22 -4
- eodag/plugins/apis/ecmwf.py +3 -24
- eodag/plugins/apis/usgs.py +3 -24
- eodag/plugins/download/aws.py +85 -44
- eodag/plugins/download/base.py +117 -41
- eodag/plugins/download/http.py +88 -65
- eodag/plugins/search/base.py +8 -3
- eodag/plugins/search/build_search_result.py +108 -120
- eodag/plugins/search/cop_marine.py +3 -1
- eodag/plugins/search/qssearch.py +7 -6
- eodag/resources/collections.yml +255 -0
- eodag/resources/ext_collections.json +1 -1
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/providers.yml +62 -25
- eodag/resources/user_conf_template.yml +6 -0
- eodag/types/__init__.py +22 -16
- eodag/types/download_args.py +3 -1
- eodag/types/queryables.py +125 -55
- eodag/types/stac_extensions.py +408 -0
- eodag/types/stac_metadata.py +312 -0
- eodag/utils/__init__.py +42 -4
- eodag/utils/dates.py +202 -2
- eodag/utils/s3.py +4 -4
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/METADATA +7 -13
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/RECORD +42 -40
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/WHEEL +1 -1
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/entry_points.txt +1 -1
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/licenses/LICENSE +0 -0
- {eodag-4.0.0a4.dist-info → eodag-4.0.0b1.dist-info}/top_level.txt +0 -0
|
@@ -21,9 +21,9 @@ import hashlib
|
|
|
21
21
|
import logging
|
|
22
22
|
import re
|
|
23
23
|
from collections import OrderedDict
|
|
24
|
-
from datetime import
|
|
24
|
+
from datetime import datetime, timedelta
|
|
25
25
|
from types import MethodType
|
|
26
|
-
from typing import TYPE_CHECKING, Annotated, Any, Optional
|
|
26
|
+
from typing import TYPE_CHECKING, Annotated, Any, Optional
|
|
27
27
|
from urllib.parse import quote_plus, unquote_plus
|
|
28
28
|
|
|
29
29
|
import geojson
|
|
@@ -31,6 +31,7 @@ import orjson
|
|
|
31
31
|
from dateutil.parser import isoparse
|
|
32
32
|
from dateutil.tz import tzutc
|
|
33
33
|
from dateutil.utils import today
|
|
34
|
+
from pydantic import AliasChoices
|
|
34
35
|
from pydantic.fields import FieldInfo
|
|
35
36
|
from requests.auth import AuthBase
|
|
36
37
|
from typing_extensions import get_args # noqa: F401
|
|
@@ -58,10 +59,18 @@ from eodag.utils import (
|
|
|
58
59
|
format_string,
|
|
59
60
|
get_geometry_from_ecmwf_area,
|
|
60
61
|
get_geometry_from_ecmwf_feature,
|
|
62
|
+
get_geometry_from_ecmwf_location,
|
|
61
63
|
get_geometry_from_various,
|
|
62
64
|
)
|
|
63
65
|
from eodag.utils.cache import instance_cached_method
|
|
64
|
-
from eodag.utils.dates import
|
|
66
|
+
from eodag.utils.dates import (
|
|
67
|
+
COMPACT_DATE_RANGE_PATTERN,
|
|
68
|
+
DATE_RANGE_PATTERN,
|
|
69
|
+
format_date,
|
|
70
|
+
is_range_in_range,
|
|
71
|
+
parse_date,
|
|
72
|
+
parse_year_month_day,
|
|
73
|
+
)
|
|
65
74
|
from eodag.utils.exceptions import DownloadError, NotAvailableError, ValidationError
|
|
66
75
|
from eodag.utils.requests import fetch_json
|
|
67
76
|
|
|
@@ -184,6 +193,7 @@ COP_DS_KEYWORDS = {
|
|
|
184
193
|
"region",
|
|
185
194
|
"release_version",
|
|
186
195
|
"satellite",
|
|
196
|
+
"satellite_mission",
|
|
187
197
|
"sensor",
|
|
188
198
|
"sensor_and_algorithm",
|
|
189
199
|
"soil_level",
|
|
@@ -285,6 +295,27 @@ def _update_properties_from_element(
|
|
|
285
295
|
if element["type"] == "DateRangeWidget":
|
|
286
296
|
prop["description"] = "date formatted like yyyy-mm-dd/yyyy-mm-dd"
|
|
287
297
|
|
|
298
|
+
# a single geographic location
|
|
299
|
+
if element["type"] == "GeographicLocationWidget":
|
|
300
|
+
prop.update(
|
|
301
|
+
{
|
|
302
|
+
"type": "object",
|
|
303
|
+
"description": "Longitude and latitude of a single location",
|
|
304
|
+
"properties": {
|
|
305
|
+
"longitude": {
|
|
306
|
+
"type": "number",
|
|
307
|
+
"maximum": 180,
|
|
308
|
+
"minimum": -180,
|
|
309
|
+
},
|
|
310
|
+
"latitude": {
|
|
311
|
+
"type": "number",
|
|
312
|
+
"maximum": 90,
|
|
313
|
+
"minimum": -90,
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
}
|
|
317
|
+
)
|
|
318
|
+
|
|
288
319
|
if description := element.get("help"):
|
|
289
320
|
prop["description"] = description
|
|
290
321
|
|
|
@@ -307,93 +338,6 @@ def ecmwf_format(v: str, alias: bool = True) -> str:
|
|
|
307
338
|
return f"{ECMWF_PREFIX[:-1]}{separator}{v}" if v in ALLOWED_KEYWORDS else v
|
|
308
339
|
|
|
309
340
|
|
|
310
|
-
def get_min_max(
|
|
311
|
-
value: Optional[Union[str, list[str]]] = None,
|
|
312
|
-
) -> tuple[Optional[str], Optional[str]]:
|
|
313
|
-
"""Returns the min and max from a list of strings or the same string if a single string is given."""
|
|
314
|
-
if isinstance(value, list):
|
|
315
|
-
sorted_values = sorted(value)
|
|
316
|
-
return sorted_values[0], sorted_values[-1]
|
|
317
|
-
return value, value
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
def append_time(input_date: date, time: Optional[str]) -> datetime:
|
|
321
|
-
"""
|
|
322
|
-
Parses a time string in format HHMM and appends it to a date.
|
|
323
|
-
|
|
324
|
-
if the time string is in format HH:MM or HH_MM we convert it to HHMM
|
|
325
|
-
"""
|
|
326
|
-
if not time:
|
|
327
|
-
time = "0000"
|
|
328
|
-
time = re.sub(":|_", "", time)
|
|
329
|
-
if time == "2400":
|
|
330
|
-
time = "0000"
|
|
331
|
-
dt = datetime.combine(input_date, datetime.strptime(time, "%H%M").time())
|
|
332
|
-
dt.replace(tzinfo=timezone.utc)
|
|
333
|
-
return dt
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
def parse_date(
|
|
337
|
-
date: str, time: Optional[Union[str, list[str]]]
|
|
338
|
-
) -> tuple[datetime, datetime]:
|
|
339
|
-
"""Parses a date string in formats YYYY-MM-DD, YYYMMDD, solo or in start/end or start/to/end intervals."""
|
|
340
|
-
if "to" in date:
|
|
341
|
-
start_date_str, end_date_str = date.split("/to/")
|
|
342
|
-
elif "/" in date:
|
|
343
|
-
dates = date.split("/")
|
|
344
|
-
start_date_str = dates[0]
|
|
345
|
-
end_date_str = dates[-1]
|
|
346
|
-
else:
|
|
347
|
-
start_date_str = end_date_str = date
|
|
348
|
-
|
|
349
|
-
# Update YYYYMMDD formatted dates
|
|
350
|
-
if re.match(r"^\d{8}$", start_date_str):
|
|
351
|
-
start_date_str = (
|
|
352
|
-
f"{start_date_str[:4]}-{start_date_str[4:6]}-{start_date_str[6:]}"
|
|
353
|
-
)
|
|
354
|
-
if re.match(r"^\d{8}$", end_date_str):
|
|
355
|
-
end_date_str = f"{end_date_str[:4]}-{end_date_str[4:6]}-{end_date_str[6:]}"
|
|
356
|
-
|
|
357
|
-
start_date = datetime.fromisoformat(start_date_str.rstrip("Z"))
|
|
358
|
-
end_date = datetime.fromisoformat(end_date_str.rstrip("Z"))
|
|
359
|
-
|
|
360
|
-
if time:
|
|
361
|
-
start_t, end_t = get_min_max(time)
|
|
362
|
-
start_date = append_time(start_date.date(), start_t)
|
|
363
|
-
end_date = append_time(end_date.date(), end_t)
|
|
364
|
-
|
|
365
|
-
return start_date, end_date
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
def parse_year_month_day(
|
|
369
|
-
year: Union[str, list[str]],
|
|
370
|
-
month: Optional[Union[str, list[str]]] = None,
|
|
371
|
-
day: Optional[Union[str, list[str]]] = None,
|
|
372
|
-
time: Optional[Union[str, list[str]]] = None,
|
|
373
|
-
) -> tuple[datetime, datetime]:
|
|
374
|
-
"""Extracts and returns the year, month, day, and time from the parameters."""
|
|
375
|
-
|
|
376
|
-
def build_date(year, month=None, day=None, time=None) -> datetime:
|
|
377
|
-
"""Datetime from default_date with updated year, month, day and time."""
|
|
378
|
-
updated_date = datetime(int(year), 1, 1).replace(
|
|
379
|
-
month=int(month) if month is not None else 1,
|
|
380
|
-
day=int(day) if day is not None else 1,
|
|
381
|
-
)
|
|
382
|
-
if time is not None:
|
|
383
|
-
updated_date = append_time(updated_date.date(), time)
|
|
384
|
-
return updated_date
|
|
385
|
-
|
|
386
|
-
start_y, end_y = get_min_max(year)
|
|
387
|
-
start_m, end_m = get_min_max(month)
|
|
388
|
-
start_d, end_d = get_min_max(day)
|
|
389
|
-
start_t, end_t = get_min_max(time)
|
|
390
|
-
|
|
391
|
-
start_date = build_date(start_y, start_m, start_d, start_t)
|
|
392
|
-
end_date = build_date(end_y, end_m, end_d, end_t)
|
|
393
|
-
|
|
394
|
-
return start_date, end_date
|
|
395
|
-
|
|
396
|
-
|
|
397
341
|
def ecmwf_temporal_to_eodag(
|
|
398
342
|
params: dict[str, Any]
|
|
399
343
|
) -> tuple[Optional[str], Optional[str]]:
|
|
@@ -627,6 +571,12 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
627
571
|
if getattr(self.config, "dates_required", False):
|
|
628
572
|
self._check_date_params(params, collection)
|
|
629
573
|
|
|
574
|
+
# read 'start_datetime' and 'end_datetime' from 'date' range
|
|
575
|
+
if "date" in params:
|
|
576
|
+
start_date, end_date = parse_date(params["date"])
|
|
577
|
+
params[START] = format_date(start_date)
|
|
578
|
+
params[END] = format_date(end_date)
|
|
579
|
+
|
|
630
580
|
# adapt end date if it is midnight
|
|
631
581
|
if END in params:
|
|
632
582
|
end_date_excluded = getattr(self.config, "end_date_excluded", True)
|
|
@@ -666,6 +616,10 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
666
616
|
if "area" in params:
|
|
667
617
|
params["geometry"] = get_geometry_from_ecmwf_area(params["area"])
|
|
668
618
|
params.pop("area")
|
|
619
|
+
# single location
|
|
620
|
+
if "location" in params:
|
|
621
|
+
params["geometry"] = get_geometry_from_ecmwf_location(params["location"])
|
|
622
|
+
params.pop("location")
|
|
669
623
|
|
|
670
624
|
return params
|
|
671
625
|
|
|
@@ -870,9 +824,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
870
824
|
)
|
|
871
825
|
not in set(list(available_values.keys()) + [f["name"] for f in form])
|
|
872
826
|
):
|
|
873
|
-
raise ValidationError(
|
|
874
|
-
f"'{keyword}' is not a queryable parameter", {keyword}
|
|
875
|
-
)
|
|
827
|
+
raise ValidationError("'%s' is not a queryable parameter" % keyword)
|
|
876
828
|
|
|
877
829
|
# generate queryables
|
|
878
830
|
if form:
|
|
@@ -890,7 +842,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
890
842
|
# start and end filters are supported whenever combinations of "year", "month", "day" filters exist
|
|
891
843
|
queryable_prefix = f"{ECMWF_PREFIX[:-1]}_"
|
|
892
844
|
if (
|
|
893
|
-
|
|
845
|
+
f"{queryable_prefix}date" in queryables
|
|
894
846
|
or f"{queryable_prefix}year" in queryables
|
|
895
847
|
or f"{queryable_prefix}hyear" in queryables
|
|
896
848
|
):
|
|
@@ -959,13 +911,21 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
959
911
|
)
|
|
960
912
|
|
|
961
913
|
# We convert every single value to a list of string
|
|
962
|
-
filter_v = values if isinstance(values,
|
|
914
|
+
filter_v = list(values) if isinstance(values, tuple) else values
|
|
915
|
+
filter_v = filter_v if isinstance(filter_v, list) else [filter_v]
|
|
963
916
|
|
|
964
917
|
# We strip values of superfluous quotes (added by mapping converter to_geojson).
|
|
965
|
-
# ECMWF accept
|
|
966
|
-
# ECMWF accept
|
|
967
|
-
|
|
968
|
-
|
|
918
|
+
# ECMWF accept date ranges with /to/. We need to split it to an array
|
|
919
|
+
# ECMWF accept date ranges in format val1/val2. We need to split it to an array
|
|
920
|
+
date_regex = [
|
|
921
|
+
re.compile(p) for p in (DATE_RANGE_PATTERN, COMPACT_DATE_RANGE_PATTERN)
|
|
922
|
+
]
|
|
923
|
+
is_date = any(
|
|
924
|
+
any(r.match(v) is not None for r in date_regex) for v in filter_v
|
|
925
|
+
)
|
|
926
|
+
if is_date:
|
|
927
|
+
sep = re.compile(r"/to/|/")
|
|
928
|
+
filter_v = [i for v in filter_v for i in sep.split(str(v))]
|
|
969
929
|
|
|
970
930
|
# special handling for time 0000 converted to 0 by pre-formating with metadata_mapping
|
|
971
931
|
if keyword.split(":")[-1] == "time":
|
|
@@ -976,23 +936,35 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
976
936
|
|
|
977
937
|
# Filter constraints and check for missing values
|
|
978
938
|
filtered_constraints = []
|
|
939
|
+
# True if some constraint is defined for this keyword.
|
|
940
|
+
# In other words: if no constraint defines a list of values
|
|
941
|
+
# then any value is allowed for this keyword
|
|
942
|
+
keyword_constrained = False
|
|
979
943
|
for entry in constraints:
|
|
980
944
|
# Filter based on the presence of any value in filter_v
|
|
981
945
|
entry_values = entry.get(keyword, [])
|
|
946
|
+
if entry_values:
|
|
947
|
+
keyword_constrained = True
|
|
982
948
|
|
|
983
|
-
# date constraint may be intervals. We identify intervals with a "/" in the value
|
|
984
|
-
#
|
|
949
|
+
# date constraint may be intervals. We identify intervals with a "/" in the value.
|
|
950
|
+
# date constraint can be a mixed list of single values (e.g "2023-06-27")
|
|
951
|
+
# and intervals (e.g. "2024-11-12/2025-11-20").
|
|
952
|
+
# collections with mixed values: CAMS_GAC_FORECAST, CAMS_EU_AIR_QUALITY_FORECAST
|
|
985
953
|
present_values = []
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
954
|
+
for entry_value in entry_values:
|
|
955
|
+
if keyword == "date" and "/" in entry_value:
|
|
956
|
+
input_range = values
|
|
957
|
+
if isinstance(values, list):
|
|
958
|
+
input_range = values[0]
|
|
959
|
+
if "/" not in input_range:
|
|
960
|
+
input_range = f"{input_range}/{input_range}"
|
|
961
|
+
if is_range_in_range(entry_value, input_range):
|
|
962
|
+
present_values.extend(filter_v)
|
|
963
|
+
else:
|
|
964
|
+
new_values = [
|
|
965
|
+
value for value in filter_v if value == entry_value
|
|
966
|
+
]
|
|
967
|
+
present_values.extend(new_values)
|
|
996
968
|
|
|
997
969
|
# Remove present values from the missing_values set
|
|
998
970
|
missing_values -= set(present_values)
|
|
@@ -1002,7 +974,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1002
974
|
|
|
1003
975
|
# raise an error as no constraint entry matched the input keywords
|
|
1004
976
|
# raise an error if one value from input is not allowed
|
|
1005
|
-
if not filtered_constraints or missing_values:
|
|
977
|
+
if keyword_constrained and (not filtered_constraints or missing_values):
|
|
1006
978
|
allowed_values = list(
|
|
1007
979
|
{value for c in constraints for value in c.get(keyword, [])}
|
|
1008
980
|
)
|
|
@@ -1028,7 +1000,9 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1028
1000
|
)
|
|
1029
1001
|
|
|
1030
1002
|
parsed_keywords.append(keyword)
|
|
1031
|
-
|
|
1003
|
+
# if the keyword is not constrained then any value is allowed
|
|
1004
|
+
if keyword_constrained:
|
|
1005
|
+
constraints = filtered_constraints
|
|
1032
1006
|
|
|
1033
1007
|
available_values: dict[str, Any] = {k: set() for k in ordered_keywords}
|
|
1034
1008
|
|
|
@@ -1100,9 +1074,21 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1100
1074
|
if default and prop.get("type") == "string" and isinstance(default, list):
|
|
1101
1075
|
default = ",".join(default)
|
|
1102
1076
|
|
|
1103
|
-
is_required
|
|
1104
|
-
|
|
1105
|
-
|
|
1077
|
+
is_required: bool
|
|
1078
|
+
if available_values.get(name):
|
|
1079
|
+
# required by the filtered constraints (available_values[name] is a not empty list)
|
|
1080
|
+
is_required = True
|
|
1081
|
+
elif bool(element.get("required")):
|
|
1082
|
+
if name in available_values and not available_values[name]:
|
|
1083
|
+
# not required by the filtered constraints (available_values[name] is an empty list)
|
|
1084
|
+
is_required = False
|
|
1085
|
+
else:
|
|
1086
|
+
# required only by form
|
|
1087
|
+
is_required = True
|
|
1088
|
+
else:
|
|
1089
|
+
# not required by form
|
|
1090
|
+
is_required = False
|
|
1091
|
+
|
|
1106
1092
|
if is_required:
|
|
1107
1093
|
required_list.append(name)
|
|
1108
1094
|
|
|
@@ -1114,7 +1100,8 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1114
1100
|
prop,
|
|
1115
1101
|
default_value=default,
|
|
1116
1102
|
required=is_required,
|
|
1117
|
-
|
|
1103
|
+
validation_alias=AliasChoices(formatted_alias, name),
|
|
1104
|
+
serialization_alias=formatted_alias,
|
|
1118
1105
|
)
|
|
1119
1106
|
)
|
|
1120
1107
|
]
|
|
@@ -1153,7 +1140,8 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1153
1140
|
{"type": "string", "title": name, "enum": values},
|
|
1154
1141
|
default_value=defaults.get(name),
|
|
1155
1142
|
required=bool(formatted_alias in required),
|
|
1156
|
-
|
|
1143
|
+
validation_alias=AliasChoices(formatted_alias, name),
|
|
1144
|
+
serialization_alias=formatted_alias,
|
|
1157
1145
|
)
|
|
1158
1146
|
)
|
|
1159
1147
|
]
|
|
@@ -1279,7 +1267,7 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
1279
1267
|
|
|
1280
1268
|
# collection alias (required by opentelemetry-instrumentation-eodag)
|
|
1281
1269
|
if alias := getattr(self.config, "collection_config", {}).get("alias"):
|
|
1282
|
-
|
|
1270
|
+
kwargs["collection"] = alias
|
|
1283
1271
|
|
|
1284
1272
|
qs = geojson.dumps(sorted_unpaginated_qp)
|
|
1285
1273
|
|
|
@@ -1521,7 +1509,7 @@ class MeteoblueSearch(ECMWFSearch):
|
|
|
1521
1509
|
properties = {ecmwf_format(k): v for k, v in parsed_properties.items()}
|
|
1522
1510
|
# collection alias (required by opentelemetry-instrumentation-eodag)
|
|
1523
1511
|
if alias := getattr(self.config, "collection_config", {}).get("alias"):
|
|
1524
|
-
|
|
1512
|
+
collection = alias
|
|
1525
1513
|
|
|
1526
1514
|
def slugify(date_str: str) -> str:
|
|
1527
1515
|
return date_str.split("T")[0].replace("-", "")
|
|
@@ -512,9 +512,11 @@ class CopMarineSearch(StaticStacSearch):
|
|
|
512
512
|
else {}
|
|
513
513
|
)
|
|
514
514
|
|
|
515
|
+
number_matched = num_total if prep.count else None
|
|
516
|
+
|
|
515
517
|
formated_result = SearchResult(
|
|
516
518
|
products,
|
|
517
|
-
|
|
519
|
+
number_matched,
|
|
518
520
|
search_params=search_params,
|
|
519
521
|
next_page_token=str(start_index + 1),
|
|
520
522
|
)
|
eodag/plugins/search/qssearch.py
CHANGED
|
@@ -28,7 +28,6 @@ from typing import (
|
|
|
28
28
|
Callable,
|
|
29
29
|
Optional,
|
|
30
30
|
Sequence,
|
|
31
|
-
TypedDict,
|
|
32
31
|
cast,
|
|
33
32
|
get_args,
|
|
34
33
|
)
|
|
@@ -58,6 +57,7 @@ from pydantic.fields import FieldInfo
|
|
|
58
57
|
from requests import Response
|
|
59
58
|
from requests.adapters import HTTPAdapter
|
|
60
59
|
from requests.auth import AuthBase
|
|
60
|
+
from typing_extensions import TypedDict
|
|
61
61
|
from urllib3 import Retry
|
|
62
62
|
|
|
63
63
|
from eodag.api.product import EOProduct
|
|
@@ -1283,7 +1283,7 @@ class QueryStringSearch(Search):
|
|
|
1283
1283
|
)
|
|
1284
1284
|
# collection alias (required by opentelemetry-instrumentation-eodag)
|
|
1285
1285
|
if alias := getattr(self.config, "collection_config", {}).get("alias"):
|
|
1286
|
-
|
|
1286
|
+
kwargs["collection"] = alias
|
|
1287
1287
|
product = EOProduct(self.provider, properties, **kwargs)
|
|
1288
1288
|
|
|
1289
1289
|
additional_assets = self.get_assets_from_mapping(result)
|
|
@@ -2166,17 +2166,18 @@ class StacSearch(PostJsonSearch):
|
|
|
2166
2166
|
# convert json results to pydantic model fields
|
|
2167
2167
|
field_definitions: dict[str, Any] = dict()
|
|
2168
2168
|
eodag_queryables_and_defaults: list[tuple[str, Any]] = []
|
|
2169
|
+
StacQueryables = Queryables.from_stac_models()
|
|
2169
2170
|
for json_param, json_mtd in json_queryables.items():
|
|
2170
2171
|
param = get_queryable_from_provider(
|
|
2171
2172
|
json_param, self.get_metadata_mapping(collection)
|
|
2172
|
-
) or
|
|
2173
|
+
) or StacQueryables.get_queryable_from_alias(json_param)
|
|
2173
2174
|
# do not expose internal parameters, neither datetime
|
|
2174
2175
|
if param == "datetime" or param.startswith("_"):
|
|
2175
2176
|
continue
|
|
2176
2177
|
|
|
2177
2178
|
default = kwargs.get(param, json_mtd.get("default"))
|
|
2178
2179
|
|
|
2179
|
-
if param in
|
|
2180
|
+
if param in StacQueryables.model_fields:
|
|
2180
2181
|
# use eodag queryable as default
|
|
2181
2182
|
eodag_queryables_and_defaults += [(param, default)]
|
|
2182
2183
|
continue
|
|
@@ -2195,12 +2196,12 @@ class StacSearch(PostJsonSearch):
|
|
|
2195
2196
|
|
|
2196
2197
|
# append eodag queryables
|
|
2197
2198
|
for param, default in eodag_queryables_and_defaults:
|
|
2198
|
-
queryables_dict[param] =
|
|
2199
|
+
queryables_dict[param] = StacQueryables.get_with_default(param, default)
|
|
2199
2200
|
|
|
2200
2201
|
# append "datetime" as "start" & "end" if needed
|
|
2201
2202
|
if "datetime" in json_queryables:
|
|
2202
2203
|
eodag_queryables = copy_deepcopy(
|
|
2203
|
-
model_fields_to_annotated(
|
|
2204
|
+
model_fields_to_annotated(StacQueryables.model_fields)
|
|
2204
2205
|
)
|
|
2205
2206
|
queryables_dict.setdefault("start", eodag_queryables["start"])
|
|
2206
2207
|
queryables_dict.setdefault("end", eodag_queryables["end"])
|