eodag 3.1.0b1__py3-none-any.whl → 3.1.0b2__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.
Files changed (85) hide show
  1. eodag/api/core.py +59 -52
  2. eodag/api/product/_assets.py +5 -5
  3. eodag/api/product/_product.py +27 -12
  4. eodag/api/product/drivers/__init__.py +81 -4
  5. eodag/api/product/drivers/base.py +65 -4
  6. eodag/api/product/drivers/generic.py +65 -0
  7. eodag/api/product/drivers/sentinel1.py +97 -0
  8. eodag/api/product/drivers/sentinel2.py +95 -0
  9. eodag/api/product/metadata_mapping.py +62 -74
  10. eodag/api/search_result.py +13 -23
  11. eodag/cli.py +4 -4
  12. eodag/config.py +66 -69
  13. eodag/plugins/apis/base.py +1 -1
  14. eodag/plugins/apis/ecmwf.py +10 -9
  15. eodag/plugins/apis/usgs.py +11 -10
  16. eodag/plugins/authentication/aws_auth.py +16 -13
  17. eodag/plugins/authentication/base.py +5 -3
  18. eodag/plugins/authentication/header.py +3 -3
  19. eodag/plugins/authentication/keycloak.py +4 -4
  20. eodag/plugins/authentication/oauth.py +7 -3
  21. eodag/plugins/authentication/openid_connect.py +14 -14
  22. eodag/plugins/authentication/sas_auth.py +4 -4
  23. eodag/plugins/authentication/token.py +7 -7
  24. eodag/plugins/authentication/token_exchange.py +1 -1
  25. eodag/plugins/base.py +4 -4
  26. eodag/plugins/crunch/base.py +4 -4
  27. eodag/plugins/crunch/filter_date.py +4 -4
  28. eodag/plugins/crunch/filter_latest_intersect.py +6 -6
  29. eodag/plugins/crunch/filter_latest_tpl_name.py +7 -7
  30. eodag/plugins/crunch/filter_overlap.py +4 -4
  31. eodag/plugins/crunch/filter_property.py +4 -4
  32. eodag/plugins/download/aws.py +47 -66
  33. eodag/plugins/download/base.py +8 -17
  34. eodag/plugins/download/creodias_s3.py +2 -2
  35. eodag/plugins/download/http.py +30 -32
  36. eodag/plugins/download/s3rest.py +5 -4
  37. eodag/plugins/manager.py +10 -20
  38. eodag/plugins/search/__init__.py +6 -5
  39. eodag/plugins/search/base.py +35 -40
  40. eodag/plugins/search/build_search_result.py +69 -68
  41. eodag/plugins/search/cop_marine.py +22 -12
  42. eodag/plugins/search/creodias_s3.py +8 -78
  43. eodag/plugins/search/csw.py +11 -11
  44. eodag/plugins/search/data_request_search.py +16 -15
  45. eodag/plugins/search/qssearch.py +56 -52
  46. eodag/plugins/search/stac_list_assets.py +85 -0
  47. eodag/plugins/search/static_stac_search.py +3 -3
  48. eodag/resources/ext_product_types.json +1 -1
  49. eodag/resources/product_types.yml +288 -288
  50. eodag/resources/providers.yml +146 -6
  51. eodag/resources/stac_api.yml +2 -2
  52. eodag/resources/user_conf_template.yml +11 -0
  53. eodag/rest/cache.py +2 -2
  54. eodag/rest/config.py +3 -3
  55. eodag/rest/core.py +24 -24
  56. eodag/rest/errors.py +5 -5
  57. eodag/rest/server.py +3 -11
  58. eodag/rest/stac.py +40 -38
  59. eodag/rest/types/collections_search.py +3 -3
  60. eodag/rest/types/eodag_search.py +23 -23
  61. eodag/rest/types/queryables.py +13 -13
  62. eodag/rest/types/stac_search.py +15 -25
  63. eodag/rest/utils/__init__.py +11 -21
  64. eodag/rest/utils/cql_evaluate.py +6 -6
  65. eodag/rest/utils/rfc3339.py +2 -2
  66. eodag/types/__init__.py +24 -18
  67. eodag/types/bbox.py +2 -2
  68. eodag/types/download_args.py +2 -2
  69. eodag/types/queryables.py +5 -2
  70. eodag/types/search_args.py +4 -4
  71. eodag/types/whoosh.py +1 -3
  72. eodag/utils/__init__.py +81 -40
  73. eodag/utils/exceptions.py +2 -2
  74. eodag/utils/import_system.py +2 -2
  75. eodag/utils/requests.py +2 -2
  76. eodag/utils/rest.py +2 -2
  77. eodag/utils/s3.py +208 -0
  78. eodag/utils/stac_reader.py +10 -10
  79. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/METADATA +5 -4
  80. eodag-3.1.0b2.dist-info/RECORD +113 -0
  81. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/entry_points.txt +1 -0
  82. eodag-3.1.0b1.dist-info/RECORD +0 -108
  83. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/LICENSE +0 -0
  84. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/WHEEL +0 -0
  85. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/top_level.txt +0 -0
eodag/api/core.py CHANGED
@@ -24,7 +24,7 @@ import re
24
24
  import shutil
25
25
  import tempfile
26
26
  from operator import itemgetter
27
- from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Tuple, Union
27
+ from typing import TYPE_CHECKING, Any, Iterator, Optional, Union
28
28
 
29
29
  import geojson
30
30
  import pkg_resources
@@ -185,7 +185,7 @@ class EODataAccessGateway:
185
185
  self._plugins_manager.rebuild(self.providers_config)
186
186
 
187
187
  # store pruned providers configs
188
- self._pruned_providers_config: Dict[str, Any] = {}
188
+ self._pruned_providers_config: dict[str, Any] = {}
189
189
  # filter out providers needing auth that have no credentials set
190
190
  self._prune_providers_list()
191
191
 
@@ -335,7 +335,7 @@ class EODataAccessGateway:
335
335
  new_priority = max_priority + 1
336
336
  self._plugins_manager.set_priority(provider, new_priority)
337
337
 
338
- def get_preferred_provider(self) -> Tuple[str, int]:
338
+ def get_preferred_provider(self) -> tuple[str, int]:
339
339
  """Get the provider currently set as the preferred one for searching
340
340
  products, along with its priority.
341
341
 
@@ -351,7 +351,7 @@ class EODataAccessGateway:
351
351
  def update_providers_config(
352
352
  self,
353
353
  yaml_conf: Optional[str] = None,
354
- dict_conf: Optional[Dict[str, Any]] = None,
354
+ dict_conf: Optional[dict[str, Any]] = None,
355
355
  ) -> None:
356
356
  """Update providers configuration with given input.
357
357
  Can be used to add a provider to existing configuration or update
@@ -397,12 +397,12 @@ class EODataAccessGateway:
397
397
  name: str,
398
398
  url: Optional[str] = None,
399
399
  priority: Optional[int] = None,
400
- search: Dict[str, Any] = {"type": "StacSearch"},
401
- products: Dict[str, Any] = {
400
+ search: dict[str, Any] = {"type": "StacSearch"},
401
+ products: dict[str, Any] = {
402
402
  GENERIC_PRODUCT_TYPE: {"productType": "{productType}"}
403
403
  },
404
- download: Dict[str, Any] = {"type": "HTTPDownload", "auth_error_code": 401},
405
- **kwargs: Dict[str, Any],
404
+ download: dict[str, Any] = {"type": "HTTPDownload", "auth_error_code": 401},
405
+ **kwargs: dict[str, Any],
406
406
  ):
407
407
  """Adds a new provider.
408
408
 
@@ -421,7 +421,7 @@ class EODataAccessGateway:
421
421
  :param download: Download :class:`~eodag.config.PluginConfig` mapping
422
422
  :param kwargs: Additional :class:`~eodag.config.ProviderConfig` mapping
423
423
  """
424
- conf_dict: Dict[str, Any] = {
424
+ conf_dict: dict[str, Any] = {
425
425
  name: {
426
426
  "url": url,
427
427
  "search": {"type": "StacSearch", **search},
@@ -565,7 +565,7 @@ class EODataAccessGateway:
565
565
  main_locations_config = locations_config[main_key]
566
566
 
567
567
  logger.info("Locations configuration loaded from %s" % locations_conf_path)
568
- self.locations_config: List[Dict[str, Any]] = main_locations_config
568
+ self.locations_config: list[dict[str, Any]] = main_locations_config
569
569
  else:
570
570
  logger.info(
571
571
  "Could not load locations configuration from %s" % locations_conf_path
@@ -574,7 +574,7 @@ class EODataAccessGateway:
574
574
 
575
575
  def list_product_types(
576
576
  self, provider: Optional[str] = None, fetch_providers: bool = True
577
- ) -> List[Dict[str, Any]]:
577
+ ) -> list[dict[str, Any]]:
578
578
  """Lists supported product types.
579
579
 
580
580
  :param provider: (optional) The name of a provider that must support the product
@@ -588,7 +588,7 @@ class EODataAccessGateway:
588
588
  # First, update product types list if possible
589
589
  self.fetch_product_types_list(provider=provider)
590
590
 
591
- product_types: List[Dict[str, Any]] = []
591
+ product_types: list[dict[str, Any]] = []
592
592
 
593
593
  providers_configs = (
594
594
  list(self.providers_config.values())
@@ -644,7 +644,7 @@ class EODataAccessGateway:
644
644
  providers_to_fetch = [provider]
645
645
 
646
646
  # providers discovery confs that are fetchable
647
- providers_discovery_configs_fetchable: Dict[str, Any] = {}
647
+ providers_discovery_configs_fetchable: dict[str, Any] = {}
648
648
  # check if any provider has not already been fetched for product types
649
649
  already_fetched = True
650
650
  for provider_to_fetch in providers_to_fetch:
@@ -767,7 +767,7 @@ class EODataAccessGateway:
767
767
 
768
768
  def discover_product_types(
769
769
  self, provider: Optional[str] = None
770
- ) -> Optional[Dict[str, Any]]:
770
+ ) -> Optional[dict[str, Any]]:
771
771
  """Fetch providers for product types
772
772
 
773
773
  :param provider: The name of a provider or provider-group to fetch. Defaults to
@@ -787,7 +787,7 @@ class EODataAccessGateway:
787
787
  raise UnsupportedProvider(
788
788
  f"The requested provider is not (yet) supported: {provider}"
789
789
  )
790
- ext_product_types_conf: Dict[str, Any] = {}
790
+ ext_product_types_conf: dict[str, Any] = {}
791
791
  providers_to_fetch = [
792
792
  p
793
793
  for p in (
@@ -800,7 +800,7 @@ class EODataAccessGateway:
800
800
  else self.available_providers()
801
801
  )
802
802
  ]
803
- kwargs: Dict[str, Any] = {}
803
+ kwargs: dict[str, Any] = {}
804
804
  for provider in providers_to_fetch:
805
805
  if hasattr(self.providers_config[provider], "search"):
806
806
  search_plugin_config = self.providers_config[provider].search
@@ -841,7 +841,7 @@ class EODataAccessGateway:
841
841
  return sort_dict(ext_product_types_conf)
842
842
 
843
843
  def update_product_types_list(
844
- self, ext_product_types_conf: Dict[str, Optional[Dict[str, Dict[str, Any]]]]
844
+ self, ext_product_types_conf: dict[str, Optional[dict[str, dict[str, Any]]]]
845
845
  ) -> None:
846
846
  """Update eodag product types list
847
847
 
@@ -869,7 +869,7 @@ class EODataAccessGateway:
869
869
  provider,
870
870
  )
871
871
  continue
872
- new_product_types: List[str] = []
872
+ new_product_types: list[str] = []
873
873
  for (
874
874
  new_product_type,
875
875
  new_product_type_conf,
@@ -932,7 +932,7 @@ class EODataAccessGateway:
932
932
 
933
933
  def available_providers(
934
934
  self, product_type: Optional[str] = None, by_group: bool = False
935
- ) -> List[str]:
935
+ ) -> list[str]:
936
936
  """Gives the sorted list of the available providers or groups
937
937
 
938
938
  The providers or groups are sorted first by their priority level in descending order,
@@ -959,7 +959,7 @@ class EODataAccessGateway:
959
959
 
960
960
  # If by_group is True, keep only the highest priority for each group
961
961
  if by_group:
962
- group_priority: Dict[str, int] = {}
962
+ group_priority: dict[str, int] = {}
963
963
  for name, priority in providers:
964
964
  if name not in group_priority or priority > group_priority[name]:
965
965
  group_priority[name] = priority
@@ -1026,7 +1026,7 @@ class EODataAccessGateway:
1026
1026
  missionStartDate: Optional[str] = None,
1027
1027
  missionEndDate: Optional[str] = None,
1028
1028
  **kwargs: Any,
1029
- ) -> List[str]:
1029
+ ) -> list[str]:
1030
1030
  """
1031
1031
  Find EODAG product type IDs that best match a set of search parameters.
1032
1032
 
@@ -1084,7 +1084,7 @@ class EODataAccessGateway:
1084
1084
  query = p.parse(text)
1085
1085
  results = searcher.search(query, limit=None)
1086
1086
 
1087
- guesses: List[Dict[str, str]] = [dict(r) for r in results or []]
1087
+ guesses: list[dict[str, str]] = [dict(r) for r in results or []]
1088
1088
 
1089
1089
  # datetime filtering
1090
1090
  if missionStartDate or missionEndDate:
@@ -1125,8 +1125,8 @@ class EODataAccessGateway:
1125
1125
  raise_errors: bool = False,
1126
1126
  start: Optional[str] = None,
1127
1127
  end: Optional[str] = None,
1128
- geom: Optional[Union[str, Dict[str, float], BaseGeometry]] = None,
1129
- locations: Optional[Dict[str, str]] = None,
1128
+ geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
1129
+ locations: Optional[dict[str, str]] = None,
1130
1130
  provider: Optional[str] = None,
1131
1131
  count: bool = False,
1132
1132
  **kwargs: Any,
@@ -1205,7 +1205,7 @@ class EODataAccessGateway:
1205
1205
  items_per_page=items_per_page,
1206
1206
  )
1207
1207
 
1208
- errors: List[Tuple[str, Exception]] = []
1208
+ errors: list[tuple[str, Exception]] = []
1209
1209
  # Loop over available providers and return the first non-empty results
1210
1210
  for i, search_plugin in enumerate(search_plugins):
1211
1211
  search_plugin.clear()
@@ -1234,8 +1234,8 @@ class EODataAccessGateway:
1234
1234
  items_per_page: int = DEFAULT_ITEMS_PER_PAGE,
1235
1235
  start: Optional[str] = None,
1236
1236
  end: Optional[str] = None,
1237
- geom: Optional[Union[str, Dict[str, float], BaseGeometry]] = None,
1238
- locations: Optional[Dict[str, str]] = None,
1237
+ geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
1238
+ locations: Optional[dict[str, str]] = None,
1239
1239
  **kwargs: Any,
1240
1240
  ) -> Iterator[SearchResult]:
1241
1241
  """Iterate over the pages of a products search.
@@ -1411,8 +1411,8 @@ class EODataAccessGateway:
1411
1411
  items_per_page: Optional[int] = None,
1412
1412
  start: Optional[str] = None,
1413
1413
  end: Optional[str] = None,
1414
- geom: Optional[Union[str, Dict[str, float], BaseGeometry]] = None,
1415
- locations: Optional[Dict[str, str]] = None,
1414
+ geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
1415
+ locations: Optional[dict[str, str]] = None,
1416
1416
  **kwargs: Any,
1417
1417
  ) -> SearchResult:
1418
1418
  """Search and return all the products matching the search criteria.
@@ -1633,7 +1633,7 @@ class EODataAccessGateway:
1633
1633
  if not getattr(plugin.config, "discover_product_types", {}).get("fetch_url"):
1634
1634
  return None
1635
1635
 
1636
- kwargs: Dict[str, Any] = {"productType": product_type}
1636
+ kwargs: dict[str, Any] = {"productType": product_type}
1637
1637
 
1638
1638
  # append auth if needed
1639
1639
  if getattr(plugin.config, "need_auth", False):
@@ -1651,11 +1651,11 @@ class EODataAccessGateway:
1651
1651
  self,
1652
1652
  start: Optional[str] = None,
1653
1653
  end: Optional[str] = None,
1654
- geom: Optional[Union[str, Dict[str, float], BaseGeometry]] = None,
1655
- locations: Optional[Dict[str, str]] = None,
1654
+ geom: Optional[Union[str, dict[str, float], BaseGeometry]] = None,
1655
+ locations: Optional[dict[str, str]] = None,
1656
1656
  provider: Optional[str] = None,
1657
1657
  **kwargs: Any,
1658
- ) -> Tuple[List[Union[Search, Api]], Dict[str, Any]]:
1658
+ ) -> tuple[list[Union[Search, Api]], dict[str, Any]]:
1659
1659
  """Internal method to prepare the search kwargs and get the search plugins.
1660
1660
 
1661
1661
  Product query:
@@ -1763,7 +1763,7 @@ class EODataAccessGateway:
1763
1763
 
1764
1764
  preferred_provider = self.get_preferred_provider()[0]
1765
1765
 
1766
- search_plugins: List[Union[Search, Api]] = []
1766
+ search_plugins: list[Union[Search, Api]] = []
1767
1767
  for plugin in self._plugins_manager.get_search_plugins(
1768
1768
  product_type=product_type, provider=provider
1769
1769
  ):
@@ -1833,10 +1833,10 @@ class EODataAccessGateway:
1833
1833
  max_items_per_page,
1834
1834
  )
1835
1835
 
1836
- results: List[EOProduct] = []
1836
+ results: list[EOProduct] = []
1837
1837
  total_results: Optional[int] = 0 if count else None
1838
1838
 
1839
- errors: List[Tuple[str, Exception]] = []
1839
+ errors: list[tuple[str, Exception]] = []
1840
1840
 
1841
1841
  try:
1842
1842
  prep = PreparedSearch(count=count)
@@ -1984,7 +1984,7 @@ class EODataAccessGateway:
1984
1984
  return results
1985
1985
 
1986
1986
  @staticmethod
1987
- def group_by_extent(searches: List[SearchResult]) -> List[SearchResult]:
1987
+ def group_by_extent(searches: list[SearchResult]) -> list[SearchResult]:
1988
1988
  """Combines multiple SearchResults and return a list of SearchResults grouped
1989
1989
  by extent (i.e. bounding box).
1990
1990
 
@@ -1993,7 +1993,7 @@ class EODataAccessGateway:
1993
1993
  """
1994
1994
  # Dict with extents as keys, each extent being defined by a str
1995
1995
  # "{minx}{miny}{maxx}{maxy}" (each float rounded to 2 dec).
1996
- products_grouped_by_extent: Dict[str, Any] = {}
1996
+ products_grouped_by_extent: dict[str, Any] = {}
1997
1997
 
1998
1998
  for search in searches:
1999
1999
  for product in search:
@@ -2015,7 +2015,7 @@ class EODataAccessGateway:
2015
2015
  wait: float = DEFAULT_DOWNLOAD_WAIT,
2016
2016
  timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
2017
2017
  **kwargs: Unpack[DownloadConf],
2018
- ) -> List[str]:
2018
+ ) -> list[str]:
2019
2019
  """Download all products resulting from a search.
2020
2020
 
2021
2021
  :param search_result: A collection of EO products resulting from a search
@@ -2273,7 +2273,7 @@ class EODataAccessGateway:
2273
2273
  properties, associating parameters to their annotated type, and a additional_properties attribute
2274
2274
  """
2275
2275
  # only fetch providers if product type is not found
2276
- available_product_types = [
2276
+ available_product_types: list[str] = [
2277
2277
  pt["ID"]
2278
2278
  for pt in self.list_product_types(provider=provider, fetch_providers=False)
2279
2279
  ]
@@ -2304,13 +2304,13 @@ class EODataAccessGateway:
2304
2304
  **model_fields_to_annotated(CommonQueryables.model_fields),
2305
2305
  )
2306
2306
 
2307
- queryables: QueryablesDict = QueryablesDict(
2308
- additional_properties=True, additional_information="", **{}
2309
- )
2307
+ additional_properties = False
2308
+ additional_information = []
2309
+ queryable_properties: dict[str, Any] = {}
2310
2310
 
2311
2311
  for plugin in self._plugins_manager.get_search_plugins(product_type, provider):
2312
2312
  # attach product type config
2313
- product_type_configs = {}
2313
+ product_type_configs: dict[str, Any] = {}
2314
2314
  if product_type:
2315
2315
  self._attach_product_type_config(plugin, product_type)
2316
2316
  product_type_configs[product_type] = plugin.config.product_type_config
@@ -2330,6 +2330,7 @@ class EODataAccessGateway:
2330
2330
  "queryables from provider %s could not be fetched due to an authentication error",
2331
2331
  plugin.provider,
2332
2332
  )
2333
+
2333
2334
  plugin_queryables = plugin.list_queryables(
2334
2335
  kwargs,
2335
2336
  available_product_types,
@@ -2337,17 +2338,23 @@ class EODataAccessGateway:
2337
2338
  product_type,
2338
2339
  pt_alias,
2339
2340
  )
2340
- queryables.update(plugin_queryables)
2341
- if not plugin_queryables.additional_properties:
2342
- queryables.additional_properties = False
2341
+
2343
2342
  if plugin_queryables.additional_information:
2344
- queryables.additional_information += (
2345
- f"{provider}: {plugin_queryables.additional_information}"
2343
+ additional_information.append(
2344
+ f"{plugin.provider}: {plugin_queryables.additional_information}"
2346
2345
  )
2346
+ queryable_properties = {**plugin_queryables, **queryable_properties}
2347
+ additional_properties = (
2348
+ additional_properties or plugin_queryables.additional_properties
2349
+ )
2347
2350
 
2348
- return queryables
2351
+ return QueryablesDict(
2352
+ additional_properties=additional_properties,
2353
+ additional_information=" | ".join(additional_information),
2354
+ **queryable_properties,
2355
+ )
2349
2356
 
2350
- def available_sortables(self) -> Dict[str, Optional[ProviderSortables]]:
2357
+ def available_sortables(self) -> dict[str, Optional[ProviderSortables]]:
2351
2358
  """For each provider, gives its available sortable parameter(s) and its maximum
2352
2359
  number of them if it supports the sorting feature, otherwise gives None.
2353
2360
 
@@ -2355,7 +2362,7 @@ class EODataAccessGateway:
2355
2362
  its (their) maximum number as value(s).
2356
2363
  :raises: :class:`~eodag.utils.exceptions.UnsupportedProvider`
2357
2364
  """
2358
- sortables: Dict[str, Optional[ProviderSortables]] = {}
2365
+ sortables: dict[str, Optional[ProviderSortables]] = {}
2359
2366
  provider_search_plugins = self._plugins_manager.get_search_plugins()
2360
2367
  for provider_search_plugin in provider_search_plugins:
2361
2368
  provider = provider_search_plugin.provider
@@ -19,7 +19,7 @@ from __future__ import annotations
19
19
 
20
20
  import re
21
21
  from collections import UserDict
22
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
22
+ from typing import TYPE_CHECKING, Any, Optional
23
23
 
24
24
  from eodag.utils.exceptions import NotAvailableError
25
25
  from eodag.utils.repr import dict_to_html_table
@@ -45,10 +45,10 @@ class AssetsDict(UserDict):
45
45
  self.product = product
46
46
  super(AssetsDict, self).__init__(*args, **kwargs)
47
47
 
48
- def __setitem__(self, key: str, value: Dict[str, Any]) -> None:
48
+ def __setitem__(self, key: str, value: dict[str, Any]) -> None:
49
49
  super().__setitem__(key, Asset(self.product, key, value))
50
50
 
51
- def as_dict(self) -> Dict[str, Any]:
51
+ def as_dict(self) -> dict[str, Any]:
52
52
  """Builds a representation of AssetsDict to enable its serialization
53
53
 
54
54
  :returns: The representation of a :class:`~eodag.api.product._assets.AssetsDict`
@@ -56,7 +56,7 @@ class AssetsDict(UserDict):
56
56
  """
57
57
  return {k: v.as_dict() for k, v in self.data.items()}
58
58
 
59
- def get_values(self, asset_filter: str = "") -> List[Asset]:
59
+ def get_values(self, asset_filter: str = "") -> list[Asset]:
60
60
  """
61
61
  retrieves the assets matching the given filter
62
62
 
@@ -138,7 +138,7 @@ class Asset(UserDict):
138
138
  self.key = key
139
139
  super(Asset, self).__init__(*args, **kwargs)
140
140
 
141
- def as_dict(self) -> Dict[str, Any]:
141
+ def as_dict(self) -> dict[str, Any]:
142
142
  """Builds a representation of Asset to enable its serialization
143
143
 
144
144
  :returns: The representation of a :class:`~eodag.api.product._assets.Asset` as a
@@ -22,7 +22,7 @@ import logging
22
22
  import os
23
23
  import re
24
24
  import tempfile
25
- from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
25
+ from typing import TYPE_CHECKING, Any, Optional, Union
26
26
 
27
27
  import requests
28
28
  from requests import RequestException
@@ -38,7 +38,7 @@ try:
38
38
  except ImportError:
39
39
  from eodag.api.product._assets import AssetsDict
40
40
 
41
- from eodag.api.product.drivers import DRIVERS, NoDriver
41
+ from eodag.api.product.drivers import DRIVERS, LEGACY_DRIVERS, NoDriver
42
42
  from eodag.api.product.metadata_mapping import (
43
43
  DEFAULT_GEOMETRY,
44
44
  NOT_AVAILABLE,
@@ -113,7 +113,7 @@ class EOProduct:
113
113
  """
114
114
 
115
115
  provider: str
116
- properties: Dict[str, Any]
116
+ properties: dict[str, Any]
117
117
  product_type: Optional[str]
118
118
  location: str
119
119
  filename: str
@@ -122,9 +122,11 @@ class EOProduct:
122
122
  geometry: BaseGeometry
123
123
  search_intersection: Optional[BaseGeometry]
124
124
  assets: AssetsDict
125
+ #: Driver enables additional methods to be called on the EOProduct
126
+ driver: DatasetDriver
125
127
 
126
128
  def __init__(
127
- self, provider: str, properties: Dict[str, Any], **kwargs: Any
129
+ self, provider: str, properties: dict[str, Any], **kwargs: Any
128
130
  ) -> None:
129
131
  self.provider = provider
130
132
  self.product_type = kwargs.get("productType")
@@ -175,7 +177,7 @@ class EOProduct:
175
177
  self.downloader: Optional[Union[Api, Download]] = None
176
178
  self.downloader_auth: Optional[Authentication] = None
177
179
 
178
- def as_dict(self) -> Dict[str, Any]:
180
+ def as_dict(self) -> dict[str, Any]:
179
181
  """Builds a representation of EOProduct as a dictionary to enable its geojson
180
182
  serialization
181
183
 
@@ -186,7 +188,7 @@ class EOProduct:
186
188
  if self.search_intersection is not None:
187
189
  search_intersection = geometry.mapping(self.search_intersection)
188
190
 
189
- geojson_repr: Dict[str, Any] = {
191
+ geojson_repr: dict[str, Any] = {
190
192
  "type": "Feature",
191
193
  "geometry": geometry.mapping(self.geometry),
192
194
  "id": self.properties["id"],
@@ -206,7 +208,7 @@ class EOProduct:
206
208
  return geojson_repr
207
209
 
208
210
  @classmethod
209
- def from_geojson(cls, feature: Dict[str, Any]) -> EOProduct:
211
+ def from_geojson(cls, feature: dict[str, Any]) -> EOProduct:
210
212
  """Builds an :class:`~eodag.api.product._product.EOProduct` object from its
211
213
  representation as geojson
212
214
 
@@ -356,7 +358,7 @@ class EOProduct:
356
358
 
357
359
  def _init_progress_bar(
358
360
  self, progress_callback: Optional[ProgressCallback]
359
- ) -> Tuple[ProgressCallback, bool]:
361
+ ) -> tuple[ProgressCallback, bool]:
360
362
  # progress bar init
361
363
  if progress_callback is None:
362
364
  progress_callback = ProgressCallback(position=1)
@@ -463,12 +465,20 @@ class EOProduct:
463
465
  )
464
466
  if not isinstance(auth, AuthBase):
465
467
  auth = None
468
+ # Read the ssl_verify parameter used on the provider config
469
+ # to ensure the same behavior for get_quicklook as other download functions
470
+ ssl_verify = (
471
+ getattr(self.downloader.config, "ssl_verify", True)
472
+ if self.downloader
473
+ else True
474
+ )
466
475
  with requests.get(
467
476
  self.properties["quicklook"],
468
477
  stream=True,
469
478
  auth=auth,
470
479
  headers=USER_AGENT,
471
480
  timeout=DEFAULT_STREAM_REQUESTS_TIMEOUT,
481
+ verify=ssl_verify,
472
482
  ) as stream:
473
483
  try:
474
484
  stream.raise_for_status()
@@ -498,11 +508,16 @@ class EOProduct:
498
508
  try:
499
509
  for driver_conf in DRIVERS:
500
510
  if all([criteria(self) for criteria in driver_conf["criteria"]]):
501
- return driver_conf["driver"]
511
+ driver = driver_conf["driver"]
512
+ break
513
+ # use legacy driver for deprecated get_data method usage
514
+ for lecacy_conf in LEGACY_DRIVERS:
515
+ if all([criteria(self) for criteria in lecacy_conf["criteria"]]):
516
+ driver.legacy = lecacy_conf["driver"]
517
+ break
518
+ return driver
502
519
  except TypeError:
503
- logger.warning(
504
- "Drivers definition seems out-of-date, please update eodag-cube"
505
- )
520
+ logger.info("No driver matching")
506
521
  pass
507
522
  return NoDriver()
508
523
 
@@ -16,14 +16,91 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
  """EODAG drivers package"""
19
+ from __future__ import annotations
20
+
21
+ from typing import Callable, TypedDict
22
+
19
23
  from eodag.api.product.drivers.base import DatasetDriver, NoDriver
24
+ from eodag.api.product.drivers.generic import GenericDriver
25
+ from eodag.api.product.drivers.sentinel1 import Sentinel1Driver
26
+ from eodag.api.product.drivers.sentinel2 import Sentinel2Driver
20
27
 
21
28
  try:
22
- from eodag_cube.api.product.drivers import ( # pyright: ignore[reportMissingImports]
23
- DRIVERS,
29
+ # import from eodag-cube if installed
30
+ from eodag_cube.api.product.drivers.generic import ( # pyright: ignore[reportMissingImports]; isort: skip
31
+ GenericDriver as GenericDriver_cube,
32
+ )
33
+ from eodag_cube.api.product.drivers.sentinel2_l1c import ( # pyright: ignore[reportMissingImports]; isort: skip
34
+ Sentinel2L1C as Sentinel2L1C_cube,
35
+ )
36
+ from eodag_cube.api.product.drivers.stac_assets import ( # pyright: ignore[reportMissingImports]; isort: skip
37
+ StacAssets as StacAssets_cube,
24
38
  )
25
39
  except ImportError:
26
- DRIVERS = []
40
+ GenericDriver_cube = NoDriver
41
+ Sentinel2L1C_cube = NoDriver
42
+ StacAssets_cube = NoDriver
43
+
44
+
45
+ class DriverCriteria(TypedDict):
46
+ """Driver criteria definition"""
47
+
48
+ #: Function that returns True if the driver is suitable for the given :class:`~eodag.api.product._product.EOProduct`
49
+ criteria: list[Callable[..., bool]]
50
+ #: driver to use
51
+ driver: DatasetDriver
52
+
53
+
54
+ #: list of drivers and their criteria
55
+ DRIVERS: list[DriverCriteria] = [
56
+ {
57
+ "criteria": [
58
+ lambda prod: True
59
+ if (prod.product_type or "").startswith("S2_MSI_")
60
+ else False
61
+ ],
62
+ "driver": Sentinel2Driver(),
63
+ },
64
+ {
65
+ "criteria": [
66
+ lambda prod: True
67
+ if (prod.product_type or "").startswith("S1_SAR_")
68
+ else False
69
+ ],
70
+ "driver": Sentinel1Driver(),
71
+ },
72
+ {
73
+ "criteria": [lambda prod: True],
74
+ "driver": GenericDriver(),
75
+ },
76
+ ]
77
+
78
+
79
+ #: list of legacy drivers and their criteria
80
+ LEGACY_DRIVERS: list[DriverCriteria] = [
81
+ {
82
+ "criteria": [
83
+ lambda prod: True if len(getattr(prod, "assets", {})) > 0 else False
84
+ ],
85
+ "driver": StacAssets_cube(),
86
+ },
87
+ {
88
+ "criteria": [lambda prod: True if "assets" in prod.properties else False],
89
+ "driver": StacAssets_cube(),
90
+ },
91
+ {
92
+ "criteria": [
93
+ lambda prod: True
94
+ if getattr(prod, "product_type") == "S2_MSI_L1C"
95
+ else False
96
+ ],
97
+ "driver": Sentinel2L1C_cube(),
98
+ },
99
+ {
100
+ "criteria": [lambda prod: True],
101
+ "driver": GenericDriver_cube(),
102
+ },
103
+ ]
27
104
 
28
105
  # exportable content
29
- __all__ = ["DRIVERS", "DatasetDriver", "NoDriver"]
106
+ __all__ = ["DRIVERS", "DatasetDriver", "GenericDriver", "NoDriver", "Sentinel2Driver"]