eodag 3.2.0__py3-none-any.whl → 3.2.1__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/plugins/search/build_search_result.py +125 -7
- eodag/resources/providers.yml +9 -9
- eodag/utils/__init__.py +1 -1
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/METADATA +1 -1
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/RECORD +9 -9
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/WHEEL +0 -0
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/entry_points.txt +0 -0
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/licenses/LICENSE +0 -0
- {eodag-3.2.0.dist-info → eodag-3.2.1.dist-info}/top_level.txt +0 -0
|
@@ -22,7 +22,7 @@ import hashlib
|
|
|
22
22
|
import logging
|
|
23
23
|
import re
|
|
24
24
|
from collections import OrderedDict
|
|
25
|
-
from datetime import datetime, timedelta
|
|
25
|
+
from datetime import date, datetime, timedelta, timezone
|
|
26
26
|
from typing import TYPE_CHECKING, Annotated, Any, Optional, Union
|
|
27
27
|
from urllib.parse import quote_plus, unquote_plus
|
|
28
28
|
|
|
@@ -286,6 +286,125 @@ def ecmwf_format(v: str) -> str:
|
|
|
286
286
|
return ECMWF_PREFIX + v if v in ALLOWED_KEYWORDS else v
|
|
287
287
|
|
|
288
288
|
|
|
289
|
+
def get_min_max(
|
|
290
|
+
value: Optional[Union[str, list[str]]] = None,
|
|
291
|
+
) -> tuple[Optional[str], Optional[str]]:
|
|
292
|
+
"""Returns the min and max from a list of strings or the same string if a single string is given."""
|
|
293
|
+
if isinstance(value, list):
|
|
294
|
+
sorted_values = sorted(value)
|
|
295
|
+
return sorted_values[0], sorted_values[-1]
|
|
296
|
+
return value, value
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def append_time(input_date: date, time: Optional[str]) -> datetime:
|
|
300
|
+
"""
|
|
301
|
+
Parses a time string in format HHMM and appends it to a date.
|
|
302
|
+
|
|
303
|
+
if the time string is in format HH:MM we convert it to HHMM
|
|
304
|
+
"""
|
|
305
|
+
if not time:
|
|
306
|
+
time = "0000"
|
|
307
|
+
time = time.replace(":", "")
|
|
308
|
+
if time == "2400":
|
|
309
|
+
time = "0000"
|
|
310
|
+
dt = datetime.combine(input_date, datetime.strptime(time, "%H%M").time())
|
|
311
|
+
dt.replace(tzinfo=timezone.utc)
|
|
312
|
+
return dt
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def parse_date(
|
|
316
|
+
date_str: str, time: Optional[Union[str, list[str]]]
|
|
317
|
+
) -> tuple[datetime, datetime]:
|
|
318
|
+
"""Parses a date string in format YYYY-MM-DD or YYYY-MM-DD/YYYY-MM-DD or YYYY-MM-DD/to/YYYY-MM-DD."""
|
|
319
|
+
if "to" in date_str:
|
|
320
|
+
start_date_str, end_date_str = date_str.split("/to/")
|
|
321
|
+
elif "/" in date_str:
|
|
322
|
+
dates = date_str.split("/")
|
|
323
|
+
start_date_str = dates[0]
|
|
324
|
+
end_date_str = dates[-1]
|
|
325
|
+
else:
|
|
326
|
+
start_date_str = end_date_str = date_str
|
|
327
|
+
|
|
328
|
+
start_date = datetime.fromisoformat(start_date_str.rstrip("Z"))
|
|
329
|
+
end_date = datetime.fromisoformat(end_date_str.rstrip("Z"))
|
|
330
|
+
|
|
331
|
+
if time:
|
|
332
|
+
start_t, end_t = get_min_max(time)
|
|
333
|
+
start_date = append_time(start_date.date(), start_t)
|
|
334
|
+
end_date = append_time(end_date.date(), end_t)
|
|
335
|
+
|
|
336
|
+
return start_date, end_date
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def parse_year_month_day(
|
|
340
|
+
year: Union[str, list[str]],
|
|
341
|
+
month: Optional[Union[str, list[str]]] = None,
|
|
342
|
+
day: Optional[Union[str, list[str]]] = None,
|
|
343
|
+
time: Optional[Union[str, list[str]]] = None,
|
|
344
|
+
) -> tuple[datetime, datetime]:
|
|
345
|
+
"""Extracts and returns the year, month, day, and time from the parameters."""
|
|
346
|
+
|
|
347
|
+
def build_date(year, month=None, day=None, time=None) -> datetime:
|
|
348
|
+
"""Datetime from default_date with updated year, month, day and time."""
|
|
349
|
+
updated_date = datetime(int(year), 1, 1).replace(
|
|
350
|
+
month=int(month) if month is not None else 1,
|
|
351
|
+
day=int(day) if day is not None else 1,
|
|
352
|
+
)
|
|
353
|
+
if time is not None:
|
|
354
|
+
updated_date = append_time(updated_date.date(), time)
|
|
355
|
+
return updated_date
|
|
356
|
+
|
|
357
|
+
start_y, end_y = get_min_max(year)
|
|
358
|
+
start_m, end_m = get_min_max(month)
|
|
359
|
+
start_d, end_d = get_min_max(day)
|
|
360
|
+
start_t, end_t = get_min_max(time)
|
|
361
|
+
|
|
362
|
+
start_date = build_date(start_y, start_m, start_d, start_t)
|
|
363
|
+
end_date = build_date(end_y, end_m, end_d, end_t)
|
|
364
|
+
|
|
365
|
+
return start_date, end_date
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def ecmwf_temporal_to_eodag(
|
|
369
|
+
params: dict[str, Any]
|
|
370
|
+
) -> tuple[Optional[str], Optional[str]]:
|
|
371
|
+
"""
|
|
372
|
+
Converts ECMWF temporal parameters to EODAG temporal parameters.
|
|
373
|
+
|
|
374
|
+
ECMWF temporal parameters:
|
|
375
|
+
- **year** or **hyear**: Union[str, list[str]] — Year(s) as a string or list of strings.
|
|
376
|
+
- **month** or **hmonth**: Union[str, list[str]] — Month(s) as a string or list of strings.
|
|
377
|
+
- **day** or **hday**: Union[str, list[str]] — Day(s) as a string or list of strings.
|
|
378
|
+
- **time**: str — A string representing the time in the format `HHMM` (e.g., `0200`, `0800`, `1400`).
|
|
379
|
+
- **date**: str — A string in one of the formats:
|
|
380
|
+
- `YYYY-MM-DD`
|
|
381
|
+
- `YYYY-MM-DD/YYYY-MM-DD`
|
|
382
|
+
- `YYYY-MM-DD/to/YYYY-MM-DD`
|
|
383
|
+
|
|
384
|
+
:param params: Dictionary containing ECMWF temporal parameters.
|
|
385
|
+
:return: A tuple with:
|
|
386
|
+
- **start**: A string in the format `YYYY-MM-DDTHH:MM:SSZ`.
|
|
387
|
+
- **end**: A string in the format `YYYY-MM-DDTHH:MM:SSZ`.
|
|
388
|
+
"""
|
|
389
|
+
start = end = None
|
|
390
|
+
|
|
391
|
+
if date := params.get("date"):
|
|
392
|
+
start, end = parse_date(date, params.get("time"))
|
|
393
|
+
|
|
394
|
+
elif year := params.get("year") or params.get("hyear"):
|
|
395
|
+
year = params.get("year") or params.get("hyear")
|
|
396
|
+
month = params.get("month") or params.get("hmonth")
|
|
397
|
+
day = params.get("day") or params.get("hday")
|
|
398
|
+
time = params.get("time")
|
|
399
|
+
|
|
400
|
+
start, end = parse_year_month_day(year, month, day, time)
|
|
401
|
+
|
|
402
|
+
if start and end:
|
|
403
|
+
return start.strftime("%Y-%m-%dT%H:%M:%SZ"), end.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
404
|
+
else:
|
|
405
|
+
return None, None
|
|
406
|
+
|
|
407
|
+
|
|
289
408
|
class ECMWFSearch(PostJsonSearch):
|
|
290
409
|
"""ECMWF search plugin.
|
|
291
410
|
|
|
@@ -507,12 +626,8 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
507
626
|
]
|
|
508
627
|
# if startTime is not given but other time params (e.g. year/month/(day)) are given,
|
|
509
628
|
# no default date is required
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if tp not in keywords:
|
|
513
|
-
in_keywords = False
|
|
514
|
-
break
|
|
515
|
-
if not in_keywords:
|
|
629
|
+
start, end = ecmwf_temporal_to_eodag(keywords)
|
|
630
|
+
if start is None:
|
|
516
631
|
keywords[START] = self.get_product_type_cfg_value(
|
|
517
632
|
"missionStartDate", DEFAULT_MISSION_START_DATE
|
|
518
633
|
)
|
|
@@ -523,6 +638,9 @@ class ECMWFSearch(PostJsonSearch):
|
|
|
523
638
|
"missionEndDate", today().isoformat()
|
|
524
639
|
)
|
|
525
640
|
)
|
|
641
|
+
else:
|
|
642
|
+
keywords[START] = start
|
|
643
|
+
keywords[END] = end
|
|
526
644
|
|
|
527
645
|
def _get_product_type_queryables(
|
|
528
646
|
self, product_type: Optional[str], alias: Optional[str], filters: dict[str, Any]
|
eodag/resources/providers.yml
CHANGED
|
@@ -1554,10 +1554,10 @@
|
|
|
1554
1554
|
auth_endpoint: https://api.ecmwf.int/v1
|
|
1555
1555
|
metadata_mapping:
|
|
1556
1556
|
productType: $.productType
|
|
1557
|
-
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#
|
|
1557
|
+
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
1558
1558
|
completionTimeFromAscendingNode:
|
|
1559
1559
|
- 'date={startTimeFromAscendingNode#to_iso_date}/to/{completionTimeFromAscendingNode#to_iso_date(-1,)}'
|
|
1560
|
-
- '{$.completionTimeFromAscendingNode#
|
|
1560
|
+
- '{$.completionTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
1561
1561
|
# The geographic extent of the product
|
|
1562
1562
|
geometry:
|
|
1563
1563
|
- 'area={geometry#to_nwse_bounds_str(/)}'
|
|
@@ -1645,10 +1645,10 @@
|
|
|
1645
1645
|
form_url: https://ads.atmosphere.copernicus.eu/api/catalogue/v1/collections/{dataset}/form.json
|
|
1646
1646
|
metadata_mapping:
|
|
1647
1647
|
productType: $.productType
|
|
1648
|
-
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#
|
|
1648
|
+
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
1649
1649
|
completionTimeFromAscendingNode:
|
|
1650
1650
|
- 'date={startTimeFromAscendingNode#to_iso_date}/{completionTimeFromAscendingNode#to_iso_date}'
|
|
1651
|
-
- '{$.completionTimeFromAscendingNode#
|
|
1651
|
+
- '{$.completionTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
1652
1652
|
# The geographic extent of the product
|
|
1653
1653
|
geometry:
|
|
1654
1654
|
- '{{"area": {geometry#to_nwse_bounds}}}'
|
|
@@ -3379,7 +3379,7 @@
|
|
|
3379
3379
|
<<: *id_from_date
|
|
3380
3380
|
orderLink: 'https://gateway.prod.wekeo2.eu/hda-broker/api/v1/dataaccess/download?{{"location": "{downloadLink}","product_id":"{id}", "dataset_id": "EO:CLMS:DAT:CLMS_GLOBAL_NDVI_1KM_V2_10DAILY_NETCDF"}}'
|
|
3381
3381
|
CLMS_CORINE:
|
|
3382
|
-
productType: EO:
|
|
3382
|
+
productType: EO:EEA:DAT:CORINE
|
|
3383
3383
|
providerProductType: Corine Land Cover 2018
|
|
3384
3384
|
format: GeoTiff100mt
|
|
3385
3385
|
metadata_mapping:
|
|
@@ -3388,7 +3388,7 @@
|
|
|
3388
3388
|
- '{{"product_type": "{providerProductType}"}}'
|
|
3389
3389
|
- '$.null'
|
|
3390
3390
|
defaultGeometry: 'POLYGON((180 -90, 180 90, -180 90, -180 -90, 180 -90))'
|
|
3391
|
-
orderLink: 'https://gateway.prod.wekeo2.eu/hda-broker/api/v1/dataaccess/download?{{"location": "{downloadLink}","product_id":"{id}", "dataset_id": "EO:
|
|
3391
|
+
orderLink: 'https://gateway.prod.wekeo2.eu/hda-broker/api/v1/dataaccess/download?{{"location": "{downloadLink}","product_id":"{id}", "dataset_id": "EO:EEA:DAT:CORINE"}}'
|
|
3392
3392
|
CLMS_GLO_FCOVER_333M:
|
|
3393
3393
|
productType: EO:CLMS:DAT:CLMS_GLOBAL_FCOVER_300M_V1_10DAILY_NETCDF
|
|
3394
3394
|
providerProductType: FCOVER300
|
|
@@ -4434,10 +4434,10 @@
|
|
|
4434
4434
|
product_type_fetch_url: null
|
|
4435
4435
|
constraints_url: "https://s3.central.data.destination-earth.eu/swift/v1/dedt-lumi-constraints/{dataset}.json"
|
|
4436
4436
|
metadata_mapping:
|
|
4437
|
-
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#
|
|
4437
|
+
startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
4438
4438
|
completionTimeFromAscendingNode:
|
|
4439
4439
|
- '{{"date": "{startTimeFromAscendingNode#to_non_separated_date}/to/{completionTimeFromAscendingNode#to_non_separated_date}"}}'
|
|
4440
|
-
- '{$.completionTimeFromAscendingNode#
|
|
4440
|
+
- '{$.completionTimeFromAscendingNode#to_iso_utc_datetime}'
|
|
4441
4441
|
qs: $.qs
|
|
4442
4442
|
orderLink: 'https://polytope.lumi.apps.dte.destination-earth.eu/api/v1/requests/destination-earth?{{"verb": "retrieve", "request": {qs#to_geojson} }}'
|
|
4443
4443
|
products:
|
|
@@ -4911,7 +4911,7 @@
|
|
|
4911
4911
|
productType: EO.MO.DAT.WAVE_GLO_PHY_SPC_FWK_L3_NRT_014_002
|
|
4912
4912
|
# CLMS
|
|
4913
4913
|
CLMS_CORINE:
|
|
4914
|
-
productType: EO.
|
|
4914
|
+
productType: EO.EEA.DAT.CORINE
|
|
4915
4915
|
CLMS_GLO_DMP_333M:
|
|
4916
4916
|
productType: EO.CLMS.DAT.GLO.DMP300_V1
|
|
4917
4917
|
CLMS_GLO_FAPAR_333M:
|
eodag/utils/__init__.py
CHANGED
|
@@ -138,7 +138,7 @@ DEFAULT_ITEMS_PER_PAGE = 20
|
|
|
138
138
|
DEFAULT_MAX_ITEMS_PER_PAGE = 50
|
|
139
139
|
|
|
140
140
|
# default product-types start date
|
|
141
|
-
DEFAULT_MISSION_START_DATE = "2015-01-01T00:00:
|
|
141
|
+
DEFAULT_MISSION_START_DATE = "2015-01-01T00:00:00.000Z"
|
|
142
142
|
|
|
143
143
|
# update missing mimetypes
|
|
144
144
|
mimetypes.add_type("text/xml", ".xsd")
|
|
@@ -49,7 +49,7 @@ eodag/plugins/download/http.py,sha256=FhvkCVxj_ENV31Nm2ulT3DRlPQYBM6eQtf2of9M0T2
|
|
|
49
49
|
eodag/plugins/download/s3rest.py,sha256=BYkKglGhTVyR0A-8ls5gLhWOPwc_DgB4aydj79wpqoM,14825
|
|
50
50
|
eodag/plugins/search/__init__.py,sha256=bBrl3TffoU1wVpaeXmTEIailoh9W6fla4IP-8SWqA9U,2019
|
|
51
51
|
eodag/plugins/search/base.py,sha256=b9zAPLQITBSOJ9n5zBxtiHlPkQwACjjJkD894oYZ7L8,18555
|
|
52
|
-
eodag/plugins/search/build_search_result.py,sha256=
|
|
52
|
+
eodag/plugins/search/build_search_result.py,sha256=ZovCC2t8CpQuycXX8Tc6oY4v7VSzqFaGjbfkmB5XxXM,49777
|
|
53
53
|
eodag/plugins/search/cop_marine.py,sha256=pRWNY9MXY-XzlpQjqOI8ImOiNUehv9pwNl6oR9r171w,19720
|
|
54
54
|
eodag/plugins/search/creodias_s3.py,sha256=rBZf3Uza7z3VuBdoUJQ9kuufGgACKVsEvK3phUo7C7M,3379
|
|
55
55
|
eodag/plugins/search/csw.py,sha256=de8CNjz4bjEny27V0RXC7V8LRz0Ik3yqQVjTAc_JlyA,12548
|
|
@@ -60,7 +60,7 @@ eodag/plugins/search/static_stac_search.py,sha256=rfcKBD-0-gDFg6jbR_XCsVH1t9Yf9H
|
|
|
60
60
|
eodag/resources/ext_product_types.json,sha256=bXZ3hzLAUgHac5yxff0fQD2hD0KYBu_VoiH5Jpu1EfA,3160813
|
|
61
61
|
eodag/resources/locations_conf_template.yml,sha256=_eBv-QKHYMIKhY0b0kp4Ee33RsayxN8LWH3kDXxfFSk,986
|
|
62
62
|
eodag/resources/product_types.yml,sha256=vN-VNxKmRbMmRfdjMI3Tc3vs66yhU3Oep8_v2AXWH9Y,409966
|
|
63
|
-
eodag/resources/providers.yml,sha256=
|
|
63
|
+
eodag/resources/providers.yml,sha256=3c6aQy3rSUuKt6E6vFUt9i7dn2bh-anbcRuf_i2-beg,221252
|
|
64
64
|
eodag/resources/stac.yml,sha256=XgQFkJEfu_f2ZiVM5L1flkew7wq55p_PJmDuVkOG3fs,10442
|
|
65
65
|
eodag/resources/stac_api.yml,sha256=2FdQL_qBTIUlu6KH836T4CXBKO9AvVxA_Ub3J1RP81A,68881
|
|
66
66
|
eodag/resources/stac_provider.yml,sha256=2yfdnuhJYV1f5el3aFkunoPqHAcD8oCDzvASbmldIvY,6703
|
|
@@ -95,7 +95,7 @@ eodag/types/download_args.py,sha256=urSl5KbLRN1XetMa2XzxYltny8CCFmHpjxU3j3BEGO8,
|
|
|
95
95
|
eodag/types/queryables.py,sha256=9Jllvoq0SgCKQUmnhVNqj55_xdMq2Yw49-1SWFh_nI8,9880
|
|
96
96
|
eodag/types/search_args.py,sha256=EtG8nXnApBnYrFo5FVvsvvEqRlqTxJ0lrmIem9Wtg8c,5649
|
|
97
97
|
eodag/types/whoosh.py,sha256=VXpWAZaXLR_RRnI9gh5iwkqn1n63krVGj2SX0rB2mQo,7225
|
|
98
|
-
eodag/utils/__init__.py,sha256
|
|
98
|
+
eodag/utils/__init__.py,sha256=-IjKfvuAgTSiRC8aCMp9xAcdrwNB_J9XDQuAvafKE4s,52783
|
|
99
99
|
eodag/utils/exceptions.py,sha256=hYeq5GzMqW50o6mSUUlvOpsfU0eRjwhpqXTSE5MFv9Q,4452
|
|
100
100
|
eodag/utils/import_system.py,sha256=1vwcSRlsZwuaP8ssrpRBP5jldZ54eLv2ttNCdLf0TtA,3901
|
|
101
101
|
eodag/utils/logging.py,sha256=KoMsyS1f6O1hr_SMDOIxvt842mOJgmu_yLUk0-0EKFs,3507
|
|
@@ -105,9 +105,9 @@ eodag/utils/requests.py,sha256=avNHKrOZ7Kp6lUA7u4kqupIth9MoirLzDsMrrmQDt4s,4560
|
|
|
105
105
|
eodag/utils/rest.py,sha256=a9tlG_Y9iQXLeyeLyecxFNbopGHV-8URecMSRs0UXu0,3348
|
|
106
106
|
eodag/utils/s3.py,sha256=2mspYgEYGA1IDbruMMDdJ2DoxyX3riSlV7PDIu7carg,7989
|
|
107
107
|
eodag/utils/stac_reader.py,sha256=d1tv82_E5dEmK9Vlw3TQfU1ndXg_iUGatxMeWMnIWPo,9236
|
|
108
|
-
eodag-3.2.
|
|
109
|
-
eodag-3.2.
|
|
110
|
-
eodag-3.2.
|
|
111
|
-
eodag-3.2.
|
|
112
|
-
eodag-3.2.
|
|
113
|
-
eodag-3.2.
|
|
108
|
+
eodag-3.2.1.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
|
|
109
|
+
eodag-3.2.1.dist-info/METADATA,sha256=xsfi9gG8iD7y-PyDarM0qEsLHvf3FXxtmS8RMPqUnNI,15476
|
|
110
|
+
eodag-3.2.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
111
|
+
eodag-3.2.1.dist-info/entry_points.txt,sha256=krdrBOQso6kAcSekV9ItEYAkE8syTC4Ev75bI781VgE,2561
|
|
112
|
+
eodag-3.2.1.dist-info/top_level.txt,sha256=025IMTmVe5eDjIPP4KEFQKespOPMQdne4U4jOy8nftM,6
|
|
113
|
+
eodag-3.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|