eodag 3.1.0b2__py3-none-any.whl → 3.2.0__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.
@@ -187,7 +187,7 @@ class DataRequestSearch(Search):
187
187
  )
188
188
  if other_product_for_mapping:
189
189
  other_product_type_def_params = self.get_product_type_def_params(
190
- other_product_for_mapping, # **kwargs
190
+ other_product_for_mapping,
191
191
  )
192
192
  product_type_metadata_mapping.update(
193
193
  other_product_type_def_params.get("metadata_mapping", {})
@@ -253,7 +253,7 @@ class DataRequestSearch(Search):
253
253
 
254
254
  # provider product type specific conf
255
255
  self.product_type_def_params = self.get_product_type_def_params(
256
- product_type, **kwargs
256
+ product_type, format_variables=kwargs
257
257
  )
258
258
 
259
259
  # update config using provider product type definition metadata_mapping
@@ -263,7 +263,7 @@ class DataRequestSearch(Search):
263
263
  )
264
264
  if other_product_for_mapping:
265
265
  other_product_type_def_params = self.get_product_type_def_params(
266
- other_product_for_mapping, **kwargs
266
+ other_product_for_mapping, format_variables=kwargs
267
267
  )
268
268
  self.config.metadata_mapping.update(
269
269
  other_product_type_def_params.get("metadata_mapping", {})
@@ -19,8 +19,8 @@ from __future__ import annotations
19
19
 
20
20
  import logging
21
21
  import re
22
+ import socket
22
23
  from copy import copy as copy_copy
23
- from datetime import datetime, timedelta
24
24
  from typing import (
25
25
  TYPE_CHECKING,
26
26
  Annotated,
@@ -48,7 +48,6 @@ import geojson
48
48
  import orjson
49
49
  import requests
50
50
  import yaml
51
- from dateutil.utils import today
52
51
  from jsonpath_ng import JSONPath
53
52
  from lxml import etree
54
53
  from pydantic import create_model
@@ -73,7 +72,6 @@ from eodag.plugins.search.base import Search
73
72
  from eodag.types import json_field_definition_to_python, model_fields_to_annotated
74
73
  from eodag.types.search_args import SortByList
75
74
  from eodag.utils import (
76
- DEFAULT_MISSION_START_DATE,
77
75
  DEFAULT_SEARCH_TIMEOUT,
78
76
  GENERIC_PRODUCT_TYPE,
79
77
  HTTP_REQ_TIMEOUT,
@@ -125,6 +123,8 @@ class QueryStringSearch(Search):
125
123
  authentication error; only used if ``need_auth=true``
126
124
  * :attr:`~eodag.config.PluginConfig.ssl_verify` (``bool``): if the ssl certificates should be verified in
127
125
  requests; default: ``True``
126
+ * :attr:`~eodag.config.PluginConfig.asset_key_from_href` (``bool``): guess assets keys using their ``href``. Use
127
+ their original key if ``False``; default: ``True``
128
128
  * :attr:`~eodag.config.PluginConfig.dont_quote` (``list[str]``): characters that should not be quoted in the
129
129
  url params
130
130
  * :attr:`~eodag.config.PluginConfig.timeout` (``int``): time to wait until request timeout in seconds;
@@ -533,7 +533,7 @@ class QueryStringSearch(Search):
533
533
 
534
534
  prep.info_message = "Fetching product types: {}".format(prep.url)
535
535
  prep.exception_message = (
536
- "Skipping error while fetching product types for " "{} {} instance:"
536
+ "Skipping error while fetching product types for {} {} instance:"
537
537
  ).format(self.provider, self.__class__.__name__)
538
538
 
539
539
  # Query using appropriate method
@@ -567,7 +567,7 @@ class QueryStringSearch(Search):
567
567
  result = result[0]
568
568
 
569
569
  def conf_update_from_product_type_result(
570
- product_type_result: dict[str, Any]
570
+ product_type_result: dict[str, Any],
571
571
  ) -> None:
572
572
  """Update ``conf_update_dict`` using given product type json response"""
573
573
  # providers_config extraction
@@ -751,7 +751,7 @@ class QueryStringSearch(Search):
751
751
 
752
752
  # provider product type specific conf
753
753
  prep.product_type_def_params = (
754
- self.get_product_type_def_params(product_type, **kwargs)
754
+ self.get_product_type_def_params(product_type, format_variables=kwargs)
755
755
  if product_type is not None
756
756
  else {}
757
757
  )
@@ -775,7 +775,7 @@ class QueryStringSearch(Search):
775
775
  }
776
776
  )
777
777
 
778
- qp, qs = self.build_query_string(product_type, **keywords)
778
+ qp, qs = self.build_query_string(product_type, keywords)
779
779
 
780
780
  prep.query_params = qp
781
781
  prep.query_string = qs
@@ -809,15 +809,15 @@ class QueryStringSearch(Search):
809
809
  self.config.metadata_mapping.update(metadata_mapping)
810
810
 
811
811
  def build_query_string(
812
- self, product_type: str, **kwargs: Any
812
+ self, product_type: str, query_dict: dict[str, Any]
813
813
  ) -> tuple[dict[str, Any], str]:
814
814
  """Build The query string using the search parameters"""
815
815
  logger.debug("Building the query string that will be used for search")
816
- query_params = format_query_params(product_type, self.config, kwargs)
816
+ query_params = format_query_params(product_type, self.config, query_dict)
817
817
 
818
818
  # Build the final query string, in one go without quoting it
819
819
  # (some providers do not operate well with urlencoded and quoted query strings)
820
- def quote_via(x: Any, *_args, **_kwargs) -> str:
820
+ def quote_via(x: Any, *_args: Any, **_kwargs: Any) -> str:
821
821
  return x
822
822
 
823
823
  return (
@@ -1074,6 +1074,7 @@ class QueryStringSearch(Search):
1074
1074
  % normalize_remaining_count
1075
1075
  )
1076
1076
  products: list[EOProduct] = []
1077
+ asset_key_from_href = getattr(self.config, "asset_key_from_href", True)
1077
1078
  for result in results:
1078
1079
  product = EOProduct(
1079
1080
  self.provider,
@@ -1091,7 +1092,8 @@ class QueryStringSearch(Search):
1091
1092
  # move assets from properties to product's attr, normalize keys & roles
1092
1093
  for key, asset in product.properties.pop("assets", {}).items():
1093
1094
  norm_key, asset["roles"] = product.driver.guess_asset_key_and_roles(
1094
- asset.get("href", ""), product
1095
+ asset.get("href", "") if asset_key_from_href else key,
1096
+ product,
1095
1097
  )
1096
1098
  if norm_key:
1097
1099
  product.assets[norm_key] = asset
@@ -1259,6 +1261,9 @@ class QueryStringSearch(Search):
1259
1261
  response.raise_for_status()
1260
1262
  except requests.exceptions.Timeout as exc:
1261
1263
  raise TimeOutError(exc, timeout=timeout) from exc
1264
+ except socket.timeout:
1265
+ err = requests.exceptions.Timeout(request=requests.Request(url=url))
1266
+ raise TimeOutError(err, timeout=timeout)
1262
1267
  except (requests.RequestException, URLError) as err:
1263
1268
  err_msg = err.readlines() if hasattr(err, "readlines") else ""
1264
1269
  if exception_message:
@@ -1434,82 +1439,6 @@ class PostJsonSearch(QueryStringSearch):
1434
1439
 
1435
1440
  """
1436
1441
 
1437
- def _get_default_end_date_from_start_date(
1438
- self, start_datetime: str, product_type_conf: dict[str, Any]
1439
- ) -> str:
1440
- try:
1441
- start_date = datetime.fromisoformat(start_datetime)
1442
- except ValueError:
1443
- start_date = datetime.strptime(start_datetime, "%Y-%m-%dT%H:%M:%SZ")
1444
- if "completionTimeFromAscendingNode" in product_type_conf:
1445
- mapping = product_type_conf["completionTimeFromAscendingNode"]
1446
- # if date is mapped to year/month/(day), use end_date = start_date else start_date + 1 day
1447
- # (default dates are only needed for ecmwf products where selected timespans should not be too large)
1448
- if isinstance(mapping, list) and "year" in mapping[0]:
1449
- end_date = start_date
1450
- else:
1451
- end_date = start_date + timedelta(days=1)
1452
- return end_date.isoformat()
1453
- return self.get_product_type_cfg_value("missionEndDate", today().isoformat())
1454
-
1455
- def _check_date_params(
1456
- self, keywords: dict[str, Any], product_type: Optional[str]
1457
- ) -> None:
1458
- """checks if start and end date are present in the keywords and adds them if not"""
1459
- if (
1460
- "startTimeFromAscendingNode"
1461
- and "completionTimeFromAscendingNode" in keywords
1462
- ):
1463
- return
1464
-
1465
- product_type_conf = getattr(self.config, "metadata_mapping", {})
1466
- if (
1467
- product_type
1468
- and product_type in self.config.products
1469
- and "metadata_mapping" in self.config.products[product_type]
1470
- ):
1471
- product_type_conf = self.config.products[product_type]["metadata_mapping"]
1472
- # start time given, end time missing
1473
- if "startTimeFromAscendingNode" in keywords:
1474
- keywords[
1475
- "completionTimeFromAscendingNode"
1476
- ] = self._get_default_end_date_from_start_date(
1477
- keywords["startTimeFromAscendingNode"], product_type_conf
1478
- )
1479
- return
1480
-
1481
- if "completionTimeFromAscendingNode" in product_type_conf:
1482
- mapping = product_type_conf["startTimeFromAscendingNode"]
1483
- if not isinstance(mapping, list):
1484
- mapping = product_type_conf["completionTimeFromAscendingNode"]
1485
- if isinstance(mapping, list):
1486
- # get time parameters (date, year, month, ...) from metadata mapping
1487
- input_mapping = mapping[0].replace("{{", "").replace("}}", "")
1488
- time_params = [
1489
- values.split(":")[0].strip() for values in input_mapping.split(",")
1490
- ]
1491
- time_params = [
1492
- tp.replace('"', "").replace("'", "") for tp in time_params
1493
- ]
1494
- # if startTime is not given but other time params (e.g. year/month/(day)) are given,
1495
- # no default date is required
1496
- in_keywords = True
1497
- for tp in time_params:
1498
- if tp not in keywords:
1499
- in_keywords = False
1500
- break
1501
- if not in_keywords:
1502
- keywords[
1503
- "startTimeFromAscendingNode"
1504
- ] = self.get_product_type_cfg_value(
1505
- "missionStartDate", DEFAULT_MISSION_START_DATE
1506
- )
1507
- keywords[
1508
- "completionTimeFromAscendingNode"
1509
- ] = self._get_default_end_date_from_start_date(
1510
- keywords["startTimeFromAscendingNode"], product_type_conf
1511
- )
1512
-
1513
1442
  def query(
1514
1443
  self,
1515
1444
  prep: PreparedSearch = PreparedSearch(),
@@ -1532,7 +1461,7 @@ class PostJsonSearch(QueryStringSearch):
1532
1461
 
1533
1462
  # provider product type specific conf
1534
1463
  prep.product_type_def_params = self.get_product_type_def_params(
1535
- product_type, **kwargs
1464
+ product_type, format_variables=kwargs
1536
1465
  )
1537
1466
  else:
1538
1467
  keywords = {
@@ -1546,7 +1475,7 @@ class PostJsonSearch(QueryStringSearch):
1546
1475
 
1547
1476
  # provider product type specific conf
1548
1477
  prep.product_type_def_params = self.get_product_type_def_params(
1549
- product_type, **kwargs
1478
+ product_type, format_variables=kwargs
1550
1479
  )
1551
1480
 
1552
1481
  # Add to the query, the queryable parameters set in the provider product type definition
@@ -1559,10 +1488,8 @@ class PostJsonSearch(QueryStringSearch):
1559
1488
  and isinstance(self.config.metadata_mapping[k], list)
1560
1489
  }
1561
1490
  )
1562
- if getattr(self.config, "dates_required", False):
1563
- self._check_date_params(keywords, product_type)
1564
1491
 
1565
- qp, _ = self.build_query_string(product_type, **keywords)
1492
+ qp, _ = self.build_query_string(product_type, keywords)
1566
1493
 
1567
1494
  for query_param, query_value in qp.items():
1568
1495
  if (
@@ -1845,24 +1772,24 @@ class StacSearch(PostJsonSearch):
1845
1772
  self.config.results_entry = results_entry
1846
1773
 
1847
1774
  def build_query_string(
1848
- self, product_type: str, **kwargs: Any
1775
+ self, product_type: str, query_dict: dict[str, Any]
1849
1776
  ) -> tuple[dict[str, Any], str]:
1850
1777
  """Build The query string using the search parameters"""
1851
1778
  logger.debug("Building the query string that will be used for search")
1852
1779
 
1853
1780
  # handle opened time intervals
1854
1781
  if any(
1855
- k in kwargs
1856
- for k in ("startTimeFromAscendingNode", "completionTimeFromAscendingNode")
1782
+ q in query_dict
1783
+ for q in ("startTimeFromAscendingNode", "completionTimeFromAscendingNode")
1857
1784
  ):
1858
- kwargs.setdefault("startTimeFromAscendingNode", "..")
1859
- kwargs.setdefault("completionTimeFromAscendingNode", "..")
1785
+ query_dict.setdefault("startTimeFromAscendingNode", "..")
1786
+ query_dict.setdefault("completionTimeFromAscendingNode", "..")
1860
1787
 
1861
- query_params = format_query_params(product_type, self.config, kwargs)
1788
+ query_params = format_query_params(product_type, self.config, query_dict)
1862
1789
 
1863
1790
  # Build the final query string, in one go without quoting it
1864
1791
  # (some providers do not operate well with urlencoded and quoted query strings)
1865
- def quote_via(x: Any, *_args, **_kwargs) -> str:
1792
+ def quote_via(x: Any, *_args: Any, **_kwargs: Any) -> str:
1866
1793
  return x
1867
1794
 
1868
1795
  return (
@@ -1919,7 +1846,8 @@ class StacSearch(PostJsonSearch):
1919
1846
  return None
1920
1847
 
1921
1848
  fetch_url = unparsed_fetch_url.format(
1922
- provider_product_type=provider_product_type, **self.config.__dict__
1849
+ provider_product_type=provider_product_type,
1850
+ **self.config.__dict__,
1923
1851
  )
1924
1852
  auth = (
1925
1853
  self.auth
@@ -1936,7 +1864,8 @@ class StacSearch(PostJsonSearch):
1936
1864
  "{} {} instance:".format(self.provider, self.__class__.__name__),
1937
1865
  ),
1938
1866
  )
1939
- except (RequestError, KeyError, AttributeError):
1867
+ except (RequestError, KeyError, AttributeError) as e:
1868
+ logger.warning("failure in queryables discovery: %s", e)
1940
1869
  return None
1941
1870
  else:
1942
1871
  json_queryables = dict()
@@ -2001,7 +1930,7 @@ class PostJsonSearchWithStacQueryables(StacSearch, PostJsonSearch):
2001
1930
  PostJsonSearch.__init__(self, provider, config)
2002
1931
 
2003
1932
  def build_query_string(
2004
- self, product_type: str, **kwargs: Any
1933
+ self, product_type: str, query_dict: dict[str, Any]
2005
1934
  ) -> tuple[dict[str, Any], str]:
2006
1935
  """Build The query string using the search parameters"""
2007
- return PostJsonSearch.build_query_string(self, product_type, **kwargs)
1936
+ return PostJsonSearch.build_query_string(self, product_type, query_dict)
@@ -142,7 +142,7 @@ class StaticStacSearch(StacSearch):
142
142
  product_type = kwargs.get("productType", prep.product_type)
143
143
  # provider product type specific conf
144
144
  self.product_type_def_params = (
145
- self.get_product_type_def_params(product_type, **kwargs)
145
+ self.get_product_type_def_params(product_type, format_variables=kwargs)
146
146
  if product_type is not None
147
147
  else {}
148
148
  )