eodag 3.10.1__py3-none-any.whl → 4.0.0a2__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 (75) hide show
  1. eodag/__init__.py +6 -1
  2. eodag/api/collection.py +353 -0
  3. eodag/api/core.py +606 -641
  4. eodag/api/product/__init__.py +3 -3
  5. eodag/api/product/_product.py +74 -56
  6. eodag/api/product/drivers/__init__.py +4 -46
  7. eodag/api/product/drivers/base.py +0 -28
  8. eodag/api/product/metadata_mapping.py +178 -216
  9. eodag/api/search_result.py +156 -15
  10. eodag/cli.py +83 -403
  11. eodag/config.py +81 -51
  12. eodag/plugins/apis/base.py +2 -2
  13. eodag/plugins/apis/ecmwf.py +36 -25
  14. eodag/plugins/apis/usgs.py +55 -40
  15. eodag/plugins/authentication/base.py +1 -3
  16. eodag/plugins/crunch/filter_date.py +3 -3
  17. eodag/plugins/crunch/filter_latest_intersect.py +2 -2
  18. eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
  19. eodag/plugins/download/aws.py +46 -42
  20. eodag/plugins/download/base.py +13 -14
  21. eodag/plugins/download/http.py +65 -65
  22. eodag/plugins/manager.py +28 -29
  23. eodag/plugins/search/__init__.py +6 -4
  24. eodag/plugins/search/base.py +131 -80
  25. eodag/plugins/search/build_search_result.py +245 -173
  26. eodag/plugins/search/cop_marine.py +87 -56
  27. eodag/plugins/search/csw.py +47 -37
  28. eodag/plugins/search/qssearch.py +653 -429
  29. eodag/plugins/search/stac_list_assets.py +1 -1
  30. eodag/plugins/search/static_stac_search.py +43 -44
  31. eodag/resources/{product_types.yml → collections.yml} +2594 -2453
  32. eodag/resources/ext_collections.json +1 -1
  33. eodag/resources/ext_product_types.json +1 -1
  34. eodag/resources/providers.yml +2706 -2733
  35. eodag/resources/stac_provider.yml +50 -92
  36. eodag/resources/user_conf_template.yml +9 -0
  37. eodag/types/__init__.py +2 -0
  38. eodag/types/queryables.py +70 -91
  39. eodag/types/search_args.py +1 -1
  40. eodag/utils/__init__.py +97 -21
  41. eodag/utils/dates.py +0 -12
  42. eodag/utils/exceptions.py +6 -6
  43. eodag/utils/free_text_search.py +3 -3
  44. eodag/utils/repr.py +2 -0
  45. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/METADATA +13 -99
  46. eodag-4.0.0a2.dist-info/RECORD +93 -0
  47. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/entry_points.txt +0 -4
  48. eodag/plugins/authentication/oauth.py +0 -60
  49. eodag/plugins/download/creodias_s3.py +0 -71
  50. eodag/plugins/download/s3rest.py +0 -351
  51. eodag/plugins/search/data_request_search.py +0 -565
  52. eodag/resources/stac.yml +0 -294
  53. eodag/resources/stac_api.yml +0 -2105
  54. eodag/rest/__init__.py +0 -24
  55. eodag/rest/cache.py +0 -70
  56. eodag/rest/config.py +0 -67
  57. eodag/rest/constants.py +0 -26
  58. eodag/rest/core.py +0 -764
  59. eodag/rest/errors.py +0 -210
  60. eodag/rest/server.py +0 -604
  61. eodag/rest/server.wsgi +0 -6
  62. eodag/rest/stac.py +0 -1032
  63. eodag/rest/templates/README +0 -1
  64. eodag/rest/types/__init__.py +0 -18
  65. eodag/rest/types/collections_search.py +0 -44
  66. eodag/rest/types/eodag_search.py +0 -386
  67. eodag/rest/types/queryables.py +0 -174
  68. eodag/rest/types/stac_search.py +0 -272
  69. eodag/rest/utils/__init__.py +0 -207
  70. eodag/rest/utils/cql_evaluate.py +0 -119
  71. eodag/rest/utils/rfc3339.py +0 -64
  72. eodag-3.10.1.dist-info/RECORD +0 -116
  73. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/WHEEL +0 -0
  74. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/licenses/LICENSE +0 -0
  75. {eodag-3.10.1.dist-info → eodag-4.0.0a2.dist-info}/top_level.txt +0 -0
@@ -34,11 +34,12 @@ from dateutil.utils import today
34
34
 
35
35
  from eodag import EOProduct
36
36
  from eodag.api.product import AssetsDict
37
+ from eodag.api.search_result import SearchResult
37
38
  from eodag.config import PluginConfig
38
39
  from eodag.plugins.search import PreparedSearch
39
40
  from eodag.plugins.search.static_stac_search import StaticStacSearch
40
41
  from eodag.utils import get_bucket_name_and_prefix, get_geometry_from_various
41
- from eodag.utils.exceptions import RequestError, UnsupportedProductType, ValidationError
42
+ from eodag.utils.exceptions import RequestError, UnsupportedCollection, ValidationError
42
43
 
43
44
  if TYPE_CHECKING:
44
45
  from mypy_boto3_s3 import S3Client
@@ -112,7 +113,7 @@ def _check_int_values_properties(properties: dict[str, Any]):
112
113
  class CopMarineSearch(StaticStacSearch):
113
114
  """class that implements search for the Copernicus Marine provider
114
115
 
115
- It calls :meth:`~eodag.plugins.search.static_stac_search.StaticStacSearch.discover_product_types`
116
+ It calls :meth:`~eodag.plugins.search.static_stac_search.StaticStacSearch.discover_collections`
116
117
  inherited from :class:`~eodag.plugins.search.static_stac_search.StaticStacSearch`
117
118
  but for the actual search a special method which fetches the urls of the available products from an S3 storage and
118
119
  filters them has been written.
@@ -132,40 +133,40 @@ class CopMarineSearch(StaticStacSearch):
132
133
  # reset to original metadata mapping from config (changed in super class init)
133
134
  self.config.metadata_mapping = original_metadata_mapping
134
135
 
135
- def _get_product_type_info(
136
- self, product_type: str
136
+ def _get_collection_info(
137
+ self, collection: str
137
138
  ) -> tuple[dict[str, Any], list[dict[str, Any]]]:
138
- """Fetch product type and associated datasets info"""
139
+ """Fetch collection and associated datasets info"""
139
140
 
140
- fetch_url = cast(str, self.config.discover_product_types["fetch_url"]).format(
141
+ fetch_url = cast(str, self.config.discover_collections["fetch_url"]).format(
141
142
  **self.config.__dict__
142
143
  )
143
144
 
144
- logger.debug("fetch data for collection %s", product_type)
145
- provider_product_type = self.config.products.get(product_type, {}).get(
146
- "productType", None
145
+ logger.debug("fetch data for collection %s", collection)
146
+ provider_collection = self.config.products.get(collection, {}).get(
147
+ "_collection", None
147
148
  )
148
- if not provider_product_type:
149
- provider_product_type = product_type
149
+ if not provider_collection:
150
+ provider_collection = collection
150
151
  collection_url = (
151
- fetch_url.replace("catalog.stac.json", provider_product_type)
152
+ fetch_url.replace("catalog.stac.json", provider_collection)
152
153
  + "/product.stac.json"
153
154
  )
154
155
  try:
155
156
  collection_data = requests.get(collection_url).json()
156
157
  except requests.RequestException as exc:
157
158
  if exc.errno == 404:
158
- logger.error("product %s not found", product_type)
159
- raise UnsupportedProductType(product_type)
160
- logger.error("data for product %s could not be fetched", product_type)
159
+ logger.error("product %s not found", collection)
160
+ raise UnsupportedCollection(collection)
161
+ logger.error("data for product %s could not be fetched", collection)
161
162
  raise RequestError.from_error(
162
- exc, f"data for product {product_type} could not be fetched"
163
+ exc, f"data for product {collection} could not be fetched"
163
164
  ) from exc
164
165
 
165
166
  datasets = []
166
167
  for link in [li for li in collection_data["links"] if li["rel"] == "item"]:
167
168
  dataset_url = (
168
- fetch_url.replace("catalog.stac.json", provider_product_type)
169
+ fetch_url.replace("catalog.stac.json", provider_collection)
169
170
  + "/"
170
171
  + link["href"]
171
172
  )
@@ -182,7 +183,7 @@ class CopMarineSearch(StaticStacSearch):
182
183
  collection_objects: ListObjectsOutputTypeDef,
183
184
  product_id: str,
184
185
  s3_url: str,
185
- product_type: str,
186
+ collection: str,
186
187
  dataset_item: dict[str, Any],
187
188
  collection_dict: dict[str, Any],
188
189
  ):
@@ -194,7 +195,7 @@ class CopMarineSearch(StaticStacSearch):
194
195
  for obj in collection_objects["Contents"]:
195
196
  if product_id in obj["Key"]:
196
197
  return self._create_product(
197
- product_type,
198
+ collection,
198
199
  obj["Key"],
199
200
  s3_url,
200
201
  dataset_item,
@@ -205,7 +206,7 @@ class CopMarineSearch(StaticStacSearch):
205
206
 
206
207
  def _create_product(
207
208
  self,
208
- product_type: str,
209
+ collection: str,
209
210
  item_key: str,
210
211
  s3_url: str,
211
212
  dataset_item: dict[str, Any],
@@ -220,21 +221,21 @@ class CopMarineSearch(StaticStacSearch):
220
221
  download_url = s3_url + "/" + item_key
221
222
  geometry = (
222
223
  get_geometry_from_various(**dataset_item)
223
- or self.config.metadata_mapping["defaultGeometry"]
224
+ or self.config.metadata_mapping["eodag:default_geometry"]
224
225
  )
225
226
  properties = {
226
227
  "id": item_id,
227
228
  "title": item_id,
228
229
  "geometry": geometry,
229
- "downloadLink": download_url,
230
+ "eodag:download_link": download_url,
230
231
  "dataset": dataset_item["id"],
231
232
  }
232
233
  if use_dataset_dates:
233
234
  dates = _get_dates_from_dataset_data(dataset_item)
234
235
  if not dates:
235
236
  return None
236
- properties["startTimeFromAscendingNode"] = dates["start"]
237
- properties["completionTimeFromAscendingNode"] = dates["end"]
237
+ properties["start_datetime"] = dates["start"]
238
+ properties["end_datetime"] = dates["end"]
238
239
  else:
239
240
  item_dates = re.findall(r"(\d{4})(0[1-9]|1[0-2])([0-3]\d)", item_id)
240
241
  if not item_dates:
@@ -247,12 +248,10 @@ class CopMarineSearch(StaticStacSearch):
247
248
  item_end = _get_date_from_yyyymmdd(item_dates[1], item_key)
248
249
  else: # only date and created_at timestamps
249
250
  item_end = item_start
250
- properties["startTimeFromAscendingNode"] = item_start.strftime(
251
+ properties["start_datetime"] = item_start.strftime("%Y-%m-%dT%H:%M:%SZ")
252
+ properties["end_datetime"] = (item_end or item_start).strftime(
251
253
  "%Y-%m-%dT%H:%M:%SZ"
252
254
  )
253
- properties["completionTimeFromAscendingNode"] = (
254
- item_end or item_start
255
- ).strftime("%Y-%m-%dT%H:%M:%SZ")
256
255
 
257
256
  for key, value in collection_dict["properties"].items():
258
257
  if key not in ["id", "title", "start_datetime", "end_datetime", "datetime"]:
@@ -261,7 +260,7 @@ class CopMarineSearch(StaticStacSearch):
261
260
  if key not in ["id", "title", "start_datetime", "end_datetime", "datetime"]:
262
261
  properties[key] = value
263
262
 
264
- code_mapping = self.config.products.get(product_type, {}).get(
263
+ code_mapping = self.config.products.get(collection, {}).get(
265
264
  "code_mapping", None
266
265
  )
267
266
  if code_mapping:
@@ -277,9 +276,11 @@ class CopMarineSearch(StaticStacSearch):
277
276
 
278
277
  _check_int_values_properties(properties)
279
278
 
280
- properties["thumbnail"] = collection_dict["assets"]["thumbnail"]["href"]
279
+ properties["eodag:thumbnail"] = collection_dict["assets"]["thumbnail"]["href"]
281
280
  if "omiFigure" in collection_dict["assets"]:
282
- properties["quicklook"] = collection_dict["assets"]["omiFigure"]["href"]
281
+ properties["eodag:quicklook"] = collection_dict["assets"]["omiFigure"][
282
+ "href"
283
+ ]
283
284
  assets = {
284
285
  "native": {
285
286
  "title": "native",
@@ -289,10 +290,7 @@ class CopMarineSearch(StaticStacSearch):
289
290
  }
290
291
  additional_assets = self.get_assets_from_mapping(dataset_item)
291
292
  assets.update(additional_assets)
292
- product = EOProduct(self.provider, properties, productType=product_type)
293
- # use product_type_config as default properties
294
- product_type_config = getattr(self.config, "product_type_config", {})
295
- product.properties = dict(product_type_config, **product.properties)
293
+ product = EOProduct(self.provider, properties, collection=collection)
296
294
  product.assets = AssetsDict(product, assets)
297
295
  return product
298
296
 
@@ -300,29 +298,39 @@ class CopMarineSearch(StaticStacSearch):
300
298
  self,
301
299
  prep: PreparedSearch = PreparedSearch(),
302
300
  **kwargs: Any,
303
- ) -> tuple[list[EOProduct], Optional[int]]:
301
+ ) -> SearchResult:
304
302
  """
305
303
  Implementation of search for the Copernicus Marine provider
306
304
  :param prep: object containing search parameterds
307
305
  :param kwargs: additional search arguments
308
306
  :returns: list of products and total number of products
309
307
  """
310
- page = prep.page
311
308
  items_per_page = prep.items_per_page
309
+ token_value = getattr(prep, "next_page_token") or prep.page
312
310
 
313
311
  # only return 1 page if pagination is disabled
314
- if page is None or items_per_page is None or page > 1 and items_per_page <= 0:
315
- return ([], 0) if prep.count else ([], None)
316
-
317
- product_type = kwargs.get("productType", prep.product_type)
318
- if not product_type:
312
+ if (
313
+ token_value is None
314
+ or items_per_page is None
315
+ or int(token_value) > 1
316
+ and items_per_page <= 0
317
+ ):
318
+ result = SearchResult([])
319
+ if prep.count:
320
+ result.number_matched = 0
321
+ return result
322
+
323
+ token = int(token_value)
324
+
325
+ collection = kwargs.get("collection", prep.collection)
326
+ if not collection:
319
327
  raise ValidationError(
320
- "parameter product type is required for search with cop_marine provider"
328
+ "parameter collection is required for search with cop_marine provider"
321
329
  )
322
- collection_dict, datasets_items_list = self._get_product_type_info(product_type)
330
+ collection_dict, datasets_items_list = self._get_collection_info(collection)
323
331
  geometry = kwargs.pop("geometry", None)
324
332
  products: list[EOProduct] = []
325
- start_index = items_per_page * (page - 1) + 1
333
+ start_index = items_per_page * (token - 1) + 1
326
334
  num_total = 0
327
335
  for i, dataset_item in enumerate(datasets_items_list):
328
336
  # Filter by geometry
@@ -334,16 +342,16 @@ class CopMarineSearch(StaticStacSearch):
334
342
  logger.debug("searching data for dataset %s", dataset_item["id"])
335
343
 
336
344
  # date bounds
337
- if "startTimeFromAscendingNode" in kwargs:
338
- start_date = isoparse(kwargs["startTimeFromAscendingNode"])
345
+ if "start_datetime" in kwargs:
346
+ start_date = isoparse(kwargs["start_datetime"])
339
347
  elif "start_datetime" in dataset_item["properties"]:
340
348
  start_date = isoparse(dataset_item["properties"]["start_datetime"])
341
349
  else:
342
350
  start_date = isoparse(dataset_item["properties"]["datetime"])
343
351
  if not start_date.tzinfo:
344
352
  start_date = start_date.replace(tzinfo=tzutc())
345
- if "completionTimeFromAscendingNode" in kwargs:
346
- end_date = isoparse(kwargs["completionTimeFromAscendingNode"])
353
+ if "end_datetime" in kwargs:
354
+ end_date = isoparse(kwargs["end_datetime"])
347
355
  elif "end_datetime" in dataset_item["properties"]:
348
356
  end_date = isoparse(dataset_item["properties"]["end_datetime"])
349
357
  else:
@@ -355,7 +363,7 @@ class CopMarineSearch(StaticStacSearch):
355
363
  s3_url = dataset_item["assets"]["native"]["href"]
356
364
  except KeyError as e:
357
365
  logger.warning(
358
- f"Unable to extract info from {product_type} item #{i}: {str(e)}"
366
+ f"Unable to extract info from {collection} item #{i}: {str(e)}"
359
367
  )
360
368
  continue
361
369
 
@@ -374,7 +382,7 @@ class CopMarineSearch(StaticStacSearch):
374
382
  continue
375
383
  if len(products) < items_per_page or items_per_page < 0:
376
384
  product = self._create_product(
377
- product_type,
385
+ collection,
378
386
  collection_path,
379
387
  endpoint_url + "/" + bucket,
380
388
  dataset_item,
@@ -403,7 +411,10 @@ class CopMarineSearch(StaticStacSearch):
403
411
  )
404
412
  if "Contents" not in s3_objects:
405
413
  if len(products) == 0 and i == len(datasets_items_list) - 1:
406
- return ([], 0) if prep.count else ([], None)
414
+ result = SearchResult([])
415
+ if prep.count:
416
+ result.number_matched = 0
417
+ return result
407
418
  else:
408
419
  break
409
420
 
@@ -412,12 +423,16 @@ class CopMarineSearch(StaticStacSearch):
412
423
  s3_objects,
413
424
  kwargs["id"],
414
425
  endpoint_url + "/" + bucket,
415
- product_type,
426
+ collection,
416
427
  dataset_item,
417
428
  collection_dict,
418
429
  )
419
430
  if product:
420
- return [product], 1
431
+ formated_result = SearchResult(
432
+ [product],
433
+ 1,
434
+ )
435
+ return formated_result
421
436
  current_object = s3_objects["Contents"][-1]["Key"]
422
437
  continue
423
438
 
@@ -476,7 +491,7 @@ class CopMarineSearch(StaticStacSearch):
476
491
  continue
477
492
  if len(products) < items_per_page or items_per_page < 0:
478
493
  product = self._create_product(
479
- product_type,
494
+ collection,
480
495
  item_key,
481
496
  endpoint_url + "/" + bucket,
482
497
  dataset_item,
@@ -487,4 +502,20 @@ class CopMarineSearch(StaticStacSearch):
487
502
  products.append(product)
488
503
  current_object = item_key
489
504
 
490
- return products, num_total
505
+ search_params = (
506
+ kwargs
507
+ | {"items_per_page": prep.items_per_page}
508
+ | {"collection": collection}
509
+ | {"provider": self.provider}
510
+ | {"geometry": geometry}
511
+ if geometry
512
+ else {}
513
+ )
514
+
515
+ formated_result = SearchResult(
516
+ products,
517
+ num_total,
518
+ search_params=search_params,
519
+ next_page_token=str(start_index + 1),
520
+ )
521
+ return formated_result
@@ -35,6 +35,7 @@ from shapely import geometry, wkt
35
35
 
36
36
  from eodag.api.product import EOProduct
37
37
  from eodag.api.product.metadata_mapping import properties_from_xml
38
+ from eodag.api.search_result import SearchResult
38
39
  from eodag.plugins.search import PreparedSearch
39
40
  from eodag.plugins.search.base import Search
40
41
  from eodag.utils import DEFAULT_PROJ
@@ -62,7 +63,7 @@ class CSWSearch(Search):
62
63
  * :attr:`~eodag.config.PluginConfig.version` (``str``): OGC Catalogue Service version; default: ``2.0.2``
63
64
  * :attr:`~eodag.config.PluginConfig.search_definition` (``dict[str, Any]``) (**mandatory**):
64
65
 
65
- * **product_type_tags** (``list[dict[str, Any]``): dict of product type tags
66
+ * **collection_tags** (``list[dict[str, Any]``): dict of collection tags
66
67
  * **resource_location_filter** (``str``): regex string
67
68
  * **date_tags** (``dict[str, Any]``): tags for start and end
68
69
 
@@ -74,15 +75,15 @@ class CSWSearch(Search):
74
75
  specification of Python string formatting, with a special behaviour added to it. For example,
75
76
  an entry in the metadata mapping of this kind::
76
77
 
77
- completionTimeFromAscendingNode:
78
- - 'f=acquisition.endViewingDate:lte:{completionTimeFromAscendingNode#timestamp}'
78
+ end_datetime:
79
+ - 'f=acquisition.endViewingDate:lte:{end_datetime#timestamp}'
79
80
  - '$.properties.acquisition.endViewingDate'
80
81
 
81
82
  means that the search url will have a query string parameter named ``f`` with a value of
82
83
  ``acquisition.endViewingDate:lte:1543922280.0`` if the search was done with the value
83
- of ``completionTimeFromAscendingNode`` being ``2018-12-04T12:18:00``. What happened is that
84
- ``{completionTimeFromAscendingNode#timestamp}`` was replaced with the timestamp of the value
85
- of ``completionTimeFromAscendingNode``. This example shows all there is to know about the
84
+ of ``end_datetime`` being ``2018-12-04T12:18:00``. What happened is that
85
+ ``{end_datetime#timestamp}`` was replaced with the timestamp of the value
86
+ of ``end_datetime``. This example shows all there is to know about the
86
87
  semantics of the query string formatting introduced by this plugin: any eodag search parameter
87
88
  can be referenced in the query string with an additional optional conversion function that
88
89
  is separated from it by a ``#`` (see :func:`~eodag.api.product.metadata_mapping.format_metadata` for further
@@ -107,11 +108,14 @@ class CSWSearch(Search):
107
108
  self,
108
109
  prep: PreparedSearch = PreparedSearch(),
109
110
  **kwargs: Any,
110
- ) -> tuple[list[EOProduct], Optional[int]]:
111
+ ) -> SearchResult:
111
112
  """Perform a search on a OGC/CSW-like interface"""
112
- product_type = kwargs.get("productType")
113
- if product_type is None:
114
- return ([], 0) if prep.count else ([], None)
113
+ collection = kwargs.get("collection")
114
+ if collection is None:
115
+ result = SearchResult([])
116
+ if prep.count:
117
+ result.number_matched = 0
118
+ return result
115
119
  auth = kwargs.get("auth")
116
120
  if auth:
117
121
  self.__init_catalog(**getattr(auth.config, "credentials", {}))
@@ -119,16 +123,16 @@ class CSWSearch(Search):
119
123
  self.__init_catalog()
120
124
  results: list[EOProduct] = []
121
125
  if self.catalog:
122
- provider_product_type = self.config.products[product_type]["productType"]
123
- for product_type_def in self.config.search_definition["product_type_tags"]:
124
- product_type_search_tag = product_type_def["name"]
126
+ provider_collection = self.config.products[collection]["collection"]
127
+ for collection_def in self.config.search_definition["collection_tags"]:
128
+ collection_search_tag = collection_def["name"]
125
129
  logger.debug(
126
- "Querying <%s> tag for product type %s",
127
- product_type_search_tag,
128
- provider_product_type,
130
+ "Querying <%s> tag for collection %s",
131
+ collection_search_tag,
132
+ provider_collection,
129
133
  )
130
134
  constraints = self.__convert_query_params(
131
- product_type_def, provider_product_type, kwargs
135
+ collection_def, provider_collection, kwargs
132
136
  )
133
137
  with patch_owslib_requests(verify=True):
134
138
  try:
@@ -139,25 +143,31 @@ class CSWSearch(Search):
139
143
  import traceback as tb
140
144
 
141
145
  logger.warning(
142
- "Failed to query %s for product type %s : %s",
143
- product_type_search_tag,
144
- product_type,
146
+ "Failed to query %s for collection %s : %s",
147
+ collection_search_tag,
148
+ collection,
145
149
  tb.format_exc(),
146
150
  )
147
151
  continue
148
152
  partial_results = [
149
- self.__build_product(record, product_type, **kwargs)
153
+ self.__build_product(record, collection, **kwargs)
150
154
  for record in self.catalog.records.values()
151
155
  ]
152
156
  logger.info(
153
157
  "Found %s results querying %s",
154
158
  len(partial_results),
155
- product_type_search_tag,
159
+ collection_search_tag,
156
160
  )
157
161
  results.extend(partial_results)
158
162
  logger.info("Found %s overall results", len(results))
159
163
  total_results = len(results) if prep.count else None
160
- return results, total_results
164
+ if not prep.count and "number_matched" in kwargs:
165
+ total_results = kwargs["number_matched"]
166
+ formated_result = SearchResult(
167
+ results,
168
+ total_results,
169
+ )
170
+ return formated_result
161
171
 
162
172
  def __init_catalog(
163
173
  self, username: Optional[str] = None, password: Optional[str] = None
@@ -182,7 +192,7 @@ class CSWSearch(Search):
182
192
  e,
183
193
  )
184
194
 
185
- def __build_product(self, rec: Any, product_type: str, **kwargs: Any) -> EOProduct:
195
+ def __build_product(self, rec: Any, collection: str, **kwargs: Any) -> EOProduct:
186
196
  """Enable search results to be handled by http download plugin"""
187
197
  download_url = ""
188
198
  resource_filter = re.compile(
@@ -217,11 +227,11 @@ class CSWSearch(Search):
217
227
  else:
218
228
  properties["geometry"] = wkt.loads(properties["geometry"])
219
229
  return EOProduct(
220
- product_type,
230
+ collection,
221
231
  self.provider,
222
232
  # TODO: EOProduct has no more *args in its __init__ (search_args attribute removed)
223
233
  # Not sure why download_url was here in the first place, needs to be updated,
224
- # possibly by having instead 'downloadLink' in the properties
234
+ # possibly by having instead 'eodag:download_link' in the properties
225
235
  # download_url,
226
236
  properties,
227
237
  searched_bbox=kwargs.get("footprints"),
@@ -229,26 +239,26 @@ class CSWSearch(Search):
229
239
 
230
240
  def __convert_query_params(
231
241
  self,
232
- product_type_def: dict[str, Any],
233
- product_type: str,
242
+ collection_def: dict[str, Any],
243
+ collection: str,
234
244
  params: dict[str, Any],
235
245
  ) -> Union[list[OgcExpression], list[list[OgcExpression]]]:
236
246
  """Translates eodag search to CSW constraints using owslib constraint classes"""
237
247
  constraints: list[OgcExpression] = []
238
248
  # How the match should be performed (fuzzy, prefix, postfix or exact).
239
249
  # defaults to fuzzy
240
- pt_tag, matching = (
241
- product_type_def["name"],
242
- product_type_def.get("matching", "fuzzy"),
250
+ col_tag, matching = (
251
+ collection_def["name"],
252
+ collection_def.get("matching", "fuzzy"),
243
253
  )
244
254
  if matching == "prefix":
245
- constraints.append(PropertyIsLike(pt_tag, "{}%".format(product_type)))
255
+ constraints.append(PropertyIsLike(col_tag, "{}%".format(collection)))
246
256
  elif matching == "postfix":
247
- constraints.append(PropertyIsLike(pt_tag, "%{}".format(product_type)))
257
+ constraints.append(PropertyIsLike(col_tag, "%{}".format(collection)))
248
258
  elif matching == "exact":
249
- constraints.append(PropertyIsEqualTo(pt_tag, product_type))
259
+ constraints.append(PropertyIsEqualTo(col_tag, collection))
250
260
  else: # unknown matching is considered to be equal to 'fuzzy'
251
- constraints.append(PropertyIsLike(pt_tag, "%{}%".format(product_type)))
261
+ constraints.append(PropertyIsLike(col_tag, "%{}%".format(collection)))
252
262
 
253
263
  # `footprint`
254
264
  fp = params.get("geometry")
@@ -259,8 +269,8 @@ class CSWSearch(Search):
259
269
 
260
270
  # dates
261
271
  start, end = (
262
- params.get("startTimeFromAscendingNode"),
263
- params.get("completionTimeFromAscendingNode"),
272
+ params.get("start_datetime"),
273
+ params.get("end_datetime"),
264
274
  )
265
275
  if start and "date_tags" in self.config.search_definition:
266
276
  constraints.append(