eodag 2.12.0__py3-none-any.whl → 3.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.
Files changed (77) hide show
  1. eodag/api/core.py +434 -319
  2. eodag/api/product/__init__.py +5 -1
  3. eodag/api/product/_assets.py +7 -2
  4. eodag/api/product/_product.py +46 -68
  5. eodag/api/product/metadata_mapping.py +181 -66
  6. eodag/api/search_result.py +21 -1
  7. eodag/cli.py +20 -6
  8. eodag/config.py +95 -6
  9. eodag/plugins/apis/base.py +8 -162
  10. eodag/plugins/apis/ecmwf.py +36 -24
  11. eodag/plugins/apis/usgs.py +40 -24
  12. eodag/plugins/authentication/aws_auth.py +2 -2
  13. eodag/plugins/authentication/header.py +31 -6
  14. eodag/plugins/authentication/keycloak.py +13 -84
  15. eodag/plugins/authentication/oauth.py +3 -3
  16. eodag/plugins/authentication/openid_connect.py +256 -46
  17. eodag/plugins/authentication/qsauth.py +3 -0
  18. eodag/plugins/authentication/sas_auth.py +8 -1
  19. eodag/plugins/authentication/token.py +92 -46
  20. eodag/plugins/authentication/token_exchange.py +120 -0
  21. eodag/plugins/download/aws.py +86 -91
  22. eodag/plugins/download/base.py +72 -40
  23. eodag/plugins/download/http.py +607 -264
  24. eodag/plugins/download/s3rest.py +28 -15
  25. eodag/plugins/manager.py +73 -57
  26. eodag/plugins/search/__init__.py +36 -0
  27. eodag/plugins/search/base.py +225 -18
  28. eodag/plugins/search/build_search_result.py +389 -32
  29. eodag/plugins/search/cop_marine.py +378 -0
  30. eodag/plugins/search/creodias_s3.py +15 -14
  31. eodag/plugins/search/csw.py +5 -7
  32. eodag/plugins/search/data_request_search.py +44 -20
  33. eodag/plugins/search/qssearch.py +508 -203
  34. eodag/plugins/search/static_stac_search.py +99 -36
  35. eodag/resources/constraints/climate-dt.json +13 -0
  36. eodag/resources/constraints/extremes-dt.json +8 -0
  37. eodag/resources/ext_product_types.json +1 -1
  38. eodag/resources/product_types.yml +1897 -34
  39. eodag/resources/providers.yml +3539 -3277
  40. eodag/resources/stac.yml +48 -54
  41. eodag/resources/stac_api.yml +71 -25
  42. eodag/resources/stac_provider.yml +5 -0
  43. eodag/resources/user_conf_template.yml +51 -3
  44. eodag/rest/__init__.py +6 -0
  45. eodag/rest/cache.py +70 -0
  46. eodag/rest/config.py +68 -0
  47. eodag/rest/constants.py +27 -0
  48. eodag/rest/core.py +757 -0
  49. eodag/rest/server.py +397 -258
  50. eodag/rest/stac.py +438 -307
  51. eodag/rest/types/collections_search.py +44 -0
  52. eodag/rest/types/eodag_search.py +232 -43
  53. eodag/rest/types/{stac_queryables.py → queryables.py} +81 -43
  54. eodag/rest/types/stac_search.py +277 -0
  55. eodag/rest/utils/__init__.py +216 -0
  56. eodag/rest/utils/cql_evaluate.py +119 -0
  57. eodag/rest/utils/rfc3339.py +65 -0
  58. eodag/types/__init__.py +99 -9
  59. eodag/types/bbox.py +15 -14
  60. eodag/types/download_args.py +31 -0
  61. eodag/types/search_args.py +58 -7
  62. eodag/types/whoosh.py +81 -0
  63. eodag/utils/__init__.py +72 -9
  64. eodag/utils/constraints.py +37 -37
  65. eodag/utils/exceptions.py +23 -17
  66. eodag/utils/requests.py +138 -0
  67. eodag/utils/rest.py +104 -0
  68. eodag/utils/stac_reader.py +100 -16
  69. {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/METADATA +64 -44
  70. eodag-3.0.0b1.dist-info/RECORD +109 -0
  71. {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/WHEEL +1 -1
  72. {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/entry_points.txt +6 -5
  73. eodag/plugins/apis/cds.py +0 -540
  74. eodag/rest/utils.py +0 -1133
  75. eodag-2.12.0.dist-info/RECORD +0 -94
  76. {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/LICENSE +0 -0
  77. {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/top_level.txt +0 -0
@@ -18,22 +18,20 @@
18
18
  from __future__ import annotations
19
19
 
20
20
  import logging
21
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
21
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, cast
22
+ from unittest import mock
22
23
 
23
24
  import geojson
24
25
 
26
+ from eodag.api.product.metadata_mapping import get_metadata_path_value
25
27
  from eodag.api.search_result import SearchResult
26
28
  from eodag.plugins.crunch.filter_date import FilterDate
27
29
  from eodag.plugins.crunch.filter_overlap import FilterOverlap
28
30
  from eodag.plugins.crunch.filter_property import FilterProperty
31
+ from eodag.plugins.search import PreparedSearch
29
32
  from eodag.plugins.search.qssearch import StacSearch
30
- from eodag.utils import (
31
- DEFAULT_ITEMS_PER_PAGE,
32
- DEFAULT_PAGE,
33
- HTTP_REQ_TIMEOUT,
34
- MockResponse,
35
- )
36
- from eodag.utils.stac_reader import fetch_stac_items
33
+ from eodag.utils import HTTP_REQ_TIMEOUT, MockResponse
34
+ from eodag.utils.stac_reader import fetch_stac_collections, fetch_stac_items
37
35
 
38
36
  if TYPE_CHECKING:
39
37
  from eodag.api.product import EOProduct
@@ -68,49 +66,112 @@ class StaticStacSearch(StacSearch):
68
66
  """
69
67
 
70
68
  def __init__(self, provider: str, config: PluginConfig) -> None:
69
+ # prevent search parameters from being queried when they are known in the configuration or not
70
+ for param, mapping in config.metadata_mapping.items():
71
+ # only keep one queryable to allow the mock search request
72
+ if param != "productType":
73
+ config.metadata_mapping[param] = get_metadata_path_value(mapping)
74
+ config.discover_metadata["auto_discovery"] = False
75
+ # there is no endpoint for fetching queryables with a static search
76
+ config.discover_queryables["fetch_url"] = None
77
+ config.discover_queryables["product_type_fetch_url"] = None
78
+
71
79
  super(StaticStacSearch, self).__init__(provider, config)
72
80
  self.config.__dict__.setdefault("max_connections", 100)
73
81
  self.config.__dict__.setdefault("timeout", HTTP_REQ_TIMEOUT)
82
+ self.config.__dict__.setdefault("ssl_verify", True)
83
+ self.config.__dict__.setdefault("pagination", {})
84
+ self.config.__dict__["pagination"].setdefault(
85
+ "total_items_nb_key_path", "$.null"
86
+ )
87
+ self.config.__dict__["pagination"].setdefault("max_items_per_page", -1)
74
88
 
75
- def discover_product_types(self) -> Dict[str, Any]:
76
- """Fetch product types is disabled for `StaticStacSearch`
89
+ def discover_product_types(self, **kwargs: Any) -> Optional[Dict[str, Any]]:
90
+ """Fetch product types list from a static STAC Catalog provider using `discover_product_types` conf
77
91
 
78
- :returns: empty dict
79
- :rtype: dict
92
+ :returns: configuration dict containing fetched product types information
93
+ :rtype: Optional[Dict[str, Any]]
80
94
  """
81
- return {}
95
+ fetch_url = cast(
96
+ str,
97
+ self.config.discover_product_types["fetch_url"].format(
98
+ **self.config.__dict__
99
+ ),
100
+ )
101
+ collections = fetch_stac_collections(
102
+ fetch_url,
103
+ collection=kwargs.get("q"),
104
+ max_connections=self.config.max_connections,
105
+ timeout=int(self.config.timeout),
106
+ ssl_verify=self.config.ssl_verify,
107
+ )
108
+ if "q" in kwargs:
109
+ collections = [c for c in collections if c["id"] == kwargs["q"]]
110
+ collections_mock_response = {"collections": collections}
111
+
112
+ # discover_product_types on mocked QueryStringSearch._request
113
+ with mock.patch(
114
+ "eodag.plugins.search.qssearch.QueryStringSearch._request",
115
+ autospec=True,
116
+ return_value=MockResponse(collections_mock_response, 200),
117
+ ):
118
+ conf_update_dict = super(StaticStacSearch, self).discover_product_types(
119
+ **kwargs
120
+ )
121
+
122
+ return conf_update_dict
82
123
 
83
124
  def query(
84
125
  self,
85
- product_type: Optional[str] = None,
86
- items_per_page: int = DEFAULT_ITEMS_PER_PAGE,
87
- page: int = DEFAULT_PAGE,
88
- count: bool = True,
126
+ prep: PreparedSearch = PreparedSearch(),
89
127
  **kwargs: Any,
90
128
  ) -> Tuple[List[EOProduct], Optional[int]]:
91
129
  """Perform a search on a static STAC Catalog"""
92
130
 
131
+ # only return 1 page if pagination is disabled
132
+ if (
133
+ prep.page
134
+ and prep.page > 1
135
+ and prep.items_per_page is not None
136
+ and prep.items_per_page <= 0
137
+ ):
138
+ return ([], 0) if prep.count else ([], None)
139
+
140
+ product_type = kwargs.get("productType", prep.product_type)
141
+ # provider product type specific conf
142
+ self.product_type_def_params = (
143
+ self.get_product_type_def_params(product_type, **kwargs)
144
+ if product_type is not None
145
+ else {}
146
+ )
147
+
148
+ for collection in self.get_collections(prep, **kwargs):
149
+ # skip empty collection if one is required in api_endpoint
150
+ if "{collection}" in self.config.api_endpoint and not collection:
151
+ continue
152
+ search_endpoint = self.config.api_endpoint.rstrip("/").format(
153
+ collection=collection
154
+ )
155
+
93
156
  features = fetch_stac_items(
94
- self.config.api_endpoint,
157
+ search_endpoint,
95
158
  recursive=True,
96
159
  max_connections=self.config.max_connections,
97
- timeout=self.config.timeout,
160
+ timeout=int(self.config.timeout),
161
+ ssl_verify=self.config.ssl_verify,
98
162
  )
99
163
  nb_features = len(features)
100
164
  feature_collection = geojson.FeatureCollection(features)
101
165
 
102
- # save StaticStacSearch._request and mock it to make return loaded static results
103
- stacapi_request = self._request
104
- self._request = (
105
- lambda url, info_message=None, exception_message=None: MockResponse(
106
- feature_collection, 200
166
+ # query on mocked StacSearch._request
167
+ with mock.patch(
168
+ "eodag.plugins.search.qssearch.StacSearch._request",
169
+ autospec=True,
170
+ return_value=MockResponse(feature_collection, 200),
171
+ ):
172
+ eo_products, _ = super(StaticStacSearch, self).query(
173
+ PreparedSearch(items_per_page=nb_features, page=1, count=True), **kwargs
107
174
  )
108
- )
109
-
110
- # query on mocked StacSearch
111
- eo_products, _ = super(StaticStacSearch, self).query(
112
- items_per_page=nb_features, page=1, count=True, **kwargs
113
- )
114
175
  # filter using query params
115
176
  search_result = SearchResult(eo_products)
116
177
  # Filter by date
@@ -124,9 +185,10 @@ class StaticStacSearch(StacSearch):
124
185
  )
125
186
 
126
187
  # Filter by geometry
127
- if "geometry" in kwargs.keys():
188
+ geometry = kwargs.pop("geometry", None)
189
+ if geometry:
128
190
  search_result = search_result.crunch(
129
- FilterOverlap({"intersects": True}), geometry=kwargs.pop("geometry")
191
+ FilterOverlap({"intersects": True}), geometry=geometry
130
192
  )
131
193
  # Filter by cloudCover
132
194
  if "cloudCover" in kwargs.keys():
@@ -151,7 +213,8 @@ class StaticStacSearch(StacSearch):
151
213
  FilterProperty({property_key: property_value, "operator": "eq"})
152
214
  )
153
215
 
154
- # restore plugin._request
155
- self._request = stacapi_request
156
-
157
- return search_result.data, len(search_result)
216
+ return (
217
+ (search_result.data, len(search_result))
218
+ if prep.count
219
+ else (search_result.data, None)
220
+ )