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.
@@ -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
- in_keywords = True
511
- for tp in time_params:
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]
@@ -1554,10 +1554,10 @@
1554
1554
  auth_endpoint: https://api.ecmwf.int/v1
1555
1555
  metadata_mapping:
1556
1556
  productType: $.productType
1557
- startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#to_iso_date}'
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#to_iso_date}'
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#to_iso_date}'
1648
+ startTimeFromAscendingNode: '{$.startTimeFromAscendingNode#to_iso_utc_datetime}'
1649
1649
  completionTimeFromAscendingNode:
1650
1650
  - 'date={startTimeFromAscendingNode#to_iso_date}/{completionTimeFromAscendingNode#to_iso_date}'
1651
- - '{$.completionTimeFromAscendingNode#to_iso_date}'
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:CLMS:DAT:CORINE
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:CLMS:DAT:CORINE"}}'
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#to_iso_date}'
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#to_iso_date}'
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.CLMS.DAT.CORINE
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:00Z"
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")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eodag
3
- Version: 3.2.0
3
+ Version: 3.2.1
4
4
  Summary: Earth Observation Data Access Gateway
5
5
  Home-page: https://github.com/CS-SI/eodag
6
6
  Author: CS GROUP - France
@@ -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=FbVJvviyhSU-cuY7ctoJbXR0QKMbUFfTVpt7WsHx4mE,45426
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=dHhapMifpnq_Rc85ykGxNWZekP6-tN0QpVehxyoDHrQ,221207
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=bdV7WMU9Zz9c6a7D63bTTNKuZmu7aEIyCm9QoS8rj9Y,52779
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.0.dist-info/licenses/LICENSE,sha256=4MAecetnRTQw5DlHtiikDSzKWO1xVLwzM5_DsPMYlnE,10172
109
- eodag-3.2.0.dist-info/METADATA,sha256=IDnRE0sHZTq6_wB4UCIcScGoRZU1wBkvtjT3RR_oLKA,15476
110
- eodag-3.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
111
- eodag-3.2.0.dist-info/entry_points.txt,sha256=krdrBOQso6kAcSekV9ItEYAkE8syTC4Ev75bI781VgE,2561
112
- eodag-3.2.0.dist-info/top_level.txt,sha256=025IMTmVe5eDjIPP4KEFQKespOPMQdne4U4jOy8nftM,6
113
- eodag-3.2.0.dist-info/RECORD,,
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