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