eodag 3.0.0b3__py3-none-any.whl → 3.1.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.
- eodag/api/core.py +347 -247
- eodag/api/product/_assets.py +44 -15
- eodag/api/product/_product.py +58 -47
- eodag/api/product/drivers/__init__.py +81 -4
- eodag/api/product/drivers/base.py +65 -4
- eodag/api/product/drivers/generic.py +65 -0
- eodag/api/product/drivers/sentinel1.py +97 -0
- eodag/api/product/drivers/sentinel2.py +95 -0
- eodag/api/product/metadata_mapping.py +129 -93
- eodag/api/search_result.py +28 -12
- eodag/cli.py +61 -24
- eodag/config.py +457 -167
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +53 -23
- eodag/plugins/apis/usgs.py +41 -17
- eodag/plugins/authentication/aws_auth.py +30 -18
- eodag/plugins/authentication/base.py +14 -3
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +14 -6
- eodag/plugins/authentication/keycloak.py +44 -25
- eodag/plugins/authentication/oauth.py +18 -4
- eodag/plugins/authentication/openid_connect.py +192 -171
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +22 -5
- eodag/plugins/authentication/token.py +95 -17
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/base.py +4 -4
- eodag/plugins/crunch/base.py +8 -5
- eodag/plugins/crunch/filter_date.py +9 -6
- eodag/plugins/crunch/filter_latest_intersect.py +9 -8
- eodag/plugins/crunch/filter_latest_tpl_name.py +8 -8
- eodag/plugins/crunch/filter_overlap.py +9 -11
- eodag/plugins/crunch/filter_property.py +10 -10
- eodag/plugins/download/aws.py +181 -105
- eodag/plugins/download/base.py +49 -67
- eodag/plugins/download/creodias_s3.py +40 -2
- eodag/plugins/download/http.py +247 -223
- eodag/plugins/download/s3rest.py +29 -28
- eodag/plugins/manager.py +176 -41
- eodag/plugins/search/__init__.py +6 -5
- eodag/plugins/search/base.py +123 -60
- eodag/plugins/search/build_search_result.py +1046 -355
- eodag/plugins/search/cop_marine.py +132 -39
- eodag/plugins/search/creodias_s3.py +19 -68
- eodag/plugins/search/csw.py +48 -8
- eodag/plugins/search/data_request_search.py +124 -23
- eodag/plugins/search/qssearch.py +531 -310
- eodag/plugins/search/stac_list_assets.py +85 -0
- eodag/plugins/search/static_stac_search.py +23 -24
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +1295 -355
- eodag/resources/providers.yml +1819 -3010
- eodag/resources/stac.yml +3 -163
- eodag/resources/stac_api.yml +2 -2
- eodag/resources/user_conf_template.yml +115 -99
- eodag/rest/cache.py +2 -2
- eodag/rest/config.py +3 -4
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +157 -117
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +57 -339
- eodag/rest/stac.py +133 -581
- eodag/rest/types/collections_search.py +3 -3
- eodag/rest/types/eodag_search.py +41 -30
- eodag/rest/types/queryables.py +42 -32
- eodag/rest/types/stac_search.py +15 -16
- eodag/rest/utils/__init__.py +14 -21
- eodag/rest/utils/cql_evaluate.py +6 -6
- eodag/rest/utils/rfc3339.py +2 -2
- eodag/types/__init__.py +153 -32
- eodag/types/bbox.py +2 -2
- eodag/types/download_args.py +4 -4
- eodag/types/queryables.py +183 -73
- eodag/types/search_args.py +6 -6
- eodag/types/whoosh.py +127 -3
- eodag/utils/__init__.py +228 -106
- eodag/utils/exceptions.py +47 -26
- eodag/utils/import_system.py +2 -2
- eodag/utils/logging.py +37 -77
- eodag/utils/repr.py +65 -6
- eodag/utils/requests.py +13 -15
- eodag/utils/rest.py +2 -2
- eodag/utils/s3.py +231 -0
- eodag/utils/stac_reader.py +11 -11
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/METADATA +81 -81
- eodag-3.1.0.dist-info/RECORD +113 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/entry_points.txt +5 -2
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag/utils/constraints.py +0 -244
- eodag-3.0.0b3.dist-info/RECORD +0 -110
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/top_level.txt +0 -0
eodag/rest/core.py
CHANGED
|
@@ -50,13 +50,10 @@ from eodag.rest.constants import (
|
|
|
50
50
|
CACHE_KEY_COLLECTIONS,
|
|
51
51
|
CACHE_KEY_QUERYABLES,
|
|
52
52
|
)
|
|
53
|
+
from eodag.rest.errors import ResponseSearchError
|
|
53
54
|
from eodag.rest.stac import StacCatalog, StacCollection, StacCommon, StacItem
|
|
54
55
|
from eodag.rest.types.eodag_search import EODAGSearch
|
|
55
|
-
from eodag.rest.types.queryables import
|
|
56
|
-
QueryablesGetParams,
|
|
57
|
-
StacQueryableProperty,
|
|
58
|
-
StacQueryables,
|
|
59
|
-
)
|
|
56
|
+
from eodag.rest.types.queryables import QueryablesGetParams, StacQueryables
|
|
60
57
|
from eodag.rest.types.stac_search import SearchPostRequest
|
|
61
58
|
from eodag.rest.utils import (
|
|
62
59
|
Cruncher,
|
|
@@ -80,7 +77,7 @@ from eodag.utils.exceptions import (
|
|
|
80
77
|
)
|
|
81
78
|
|
|
82
79
|
if TYPE_CHECKING:
|
|
83
|
-
from typing import Any,
|
|
80
|
+
from typing import Any, Optional, Union
|
|
84
81
|
|
|
85
82
|
from fastapi import Request
|
|
86
83
|
from requests.auth import AuthBase
|
|
@@ -119,12 +116,12 @@ def get_home_page_content(base_url: str, ipp: Optional[int] = None) -> str:
|
|
|
119
116
|
reason="Function internally used by get_home_page_content, also deprecated",
|
|
120
117
|
version="2.6.1",
|
|
121
118
|
)
|
|
122
|
-
def format_product_types(product_types:
|
|
119
|
+
def format_product_types(product_types: list[dict[str, Any]]) -> str:
|
|
123
120
|
"""Format product_types
|
|
124
121
|
|
|
125
122
|
:param product_types: A list of EODAG product types as returned by the core api
|
|
126
123
|
"""
|
|
127
|
-
result:
|
|
124
|
+
result: list[str] = []
|
|
128
125
|
for pt in product_types:
|
|
129
126
|
result.append(f'* *__{pt["ID"]}__*: {pt["abstract"]}')
|
|
130
127
|
return "\n".join(sorted(result))
|
|
@@ -133,17 +130,15 @@ def format_product_types(product_types: List[Dict[str, Any]]) -> str:
|
|
|
133
130
|
def search_stac_items(
|
|
134
131
|
request: Request,
|
|
135
132
|
search_request: SearchPostRequest,
|
|
136
|
-
|
|
137
|
-
) -> Dict[str, Any]:
|
|
133
|
+
) -> dict[str, Any]:
|
|
138
134
|
"""
|
|
139
|
-
Search and retrieve STAC items
|
|
135
|
+
Search and retrieve STAC items based on the given search request.
|
|
140
136
|
|
|
141
|
-
This function takes a search request
|
|
137
|
+
This function takes a search request, performs a search using EODAG API, and returns a
|
|
142
138
|
dictionary of STAC items.
|
|
143
139
|
|
|
144
140
|
:param request: The incoming HTTP request with state information.
|
|
145
|
-
:param search_request: The search criteria for STAC items
|
|
146
|
-
:param catalogs: (optional) A list of catalogs to search within. Defaults to None.
|
|
141
|
+
:param search_request: The search criteria for STAC items
|
|
147
142
|
:returns: A dictionary containing the STAC items and related metadata.
|
|
148
143
|
|
|
149
144
|
The function handles the conversion of search criteria into STAC and EODAG compatible formats, validates the input
|
|
@@ -165,60 +160,54 @@ def search_stac_items(
|
|
|
165
160
|
if search_request.spatial_filter:
|
|
166
161
|
stac_args["geometry"] = search_request.spatial_filter
|
|
167
162
|
try:
|
|
168
|
-
eodag_args = EODAGSearch.model_validate(
|
|
169
|
-
stac_args, context={"isCatalog": bool(catalogs)}
|
|
170
|
-
)
|
|
163
|
+
eodag_args = EODAGSearch.model_validate(stac_args)
|
|
171
164
|
except pydanticValidationError as e:
|
|
172
165
|
raise ValidationError(format_pydantic_error(e)) from e
|
|
173
166
|
|
|
174
167
|
catalog_url = re.sub("/items.*", "", request.state.url)
|
|
175
|
-
|
|
176
168
|
catalog = StacCatalog(
|
|
177
|
-
url=(
|
|
178
|
-
catalog_url
|
|
179
|
-
if catalogs
|
|
180
|
-
else catalog_url.replace(
|
|
181
|
-
"/search", f"/collections/{eodag_args.productType}"
|
|
182
|
-
)
|
|
183
|
-
),
|
|
169
|
+
url=catalog_url.replace("/search", f"/collections/{eodag_args.productType}"),
|
|
184
170
|
stac_config=stac_config,
|
|
185
171
|
root=request.state.url_root,
|
|
186
172
|
provider=eodag_args.provider,
|
|
187
173
|
eodag_api=eodag_api,
|
|
188
|
-
|
|
174
|
+
collection=eodag_args.productType, # type: ignore
|
|
189
175
|
)
|
|
190
176
|
|
|
191
177
|
# get products by ids
|
|
192
178
|
if eodag_args.ids:
|
|
193
|
-
|
|
179
|
+
results = SearchResult([])
|
|
194
180
|
for item_id in eodag_args.ids:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
181
|
+
results.extend(
|
|
182
|
+
eodag_api.search(
|
|
183
|
+
id=item_id,
|
|
184
|
+
productType=eodag_args.productType,
|
|
185
|
+
provider=eodag_args.provider,
|
|
186
|
+
)
|
|
199
187
|
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
total = len(search_results)
|
|
203
|
-
|
|
204
|
-
elif time_interval_overlap(eodag_args, catalog):
|
|
205
|
-
criteria = {
|
|
206
|
-
**catalog.search_args,
|
|
207
|
-
**eodag_args.model_dump(exclude_none=True),
|
|
208
|
-
}
|
|
188
|
+
results.number_matched = len(results)
|
|
189
|
+
total = len(results)
|
|
209
190
|
|
|
210
|
-
search_results = eodag_api.search(count=True, **criteria)
|
|
211
|
-
total = search_results.number_matched or 0
|
|
212
|
-
if search_request.crunch:
|
|
213
|
-
search_results = crunch_products(
|
|
214
|
-
search_results, search_request.crunch, **criteria
|
|
215
|
-
)
|
|
216
191
|
else:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
192
|
+
criteria = eodag_args.model_dump(exclude_none=True)
|
|
193
|
+
# remove provider prefixes
|
|
194
|
+
# quickfix for ecmwf fake extension to not impact items creation
|
|
195
|
+
stac_extensions = list(stac_config["extensions"].keys()) + ["ecmwf"]
|
|
196
|
+
for key in list(criteria):
|
|
197
|
+
if ":" in key and key.split(":")[0] not in stac_extensions:
|
|
198
|
+
new_key = key.split(":")[1]
|
|
199
|
+
criteria[new_key] = criteria.pop(key)
|
|
200
|
+
|
|
201
|
+
results = eodag_api.search(count=True, **criteria)
|
|
202
|
+
total = results.number_matched or 0
|
|
203
|
+
|
|
204
|
+
if len(results) == 0 and results.errors:
|
|
205
|
+
raise ResponseSearchError(results.errors)
|
|
206
|
+
|
|
207
|
+
if search_request.crunch:
|
|
208
|
+
results = crunch_products(results, search_request.crunch, **criteria)
|
|
220
209
|
|
|
221
|
-
for record in
|
|
210
|
+
for record in results:
|
|
222
211
|
record.product_type = eodag_api.get_alias_from_product_type(record.product_type)
|
|
223
212
|
|
|
224
213
|
items = StacItem(
|
|
@@ -228,7 +217,7 @@ def search_stac_items(
|
|
|
228
217
|
eodag_api=eodag_api,
|
|
229
218
|
root=request.state.url_root,
|
|
230
219
|
).get_stac_items(
|
|
231
|
-
search_results=
|
|
220
|
+
search_results=results,
|
|
232
221
|
total=total,
|
|
233
222
|
next_link=get_next_link(
|
|
234
223
|
request, search_request, total, eodag_args.items_per_page
|
|
@@ -243,7 +232,7 @@ def search_stac_items(
|
|
|
243
232
|
|
|
244
233
|
def download_stac_item(
|
|
245
234
|
request: Request,
|
|
246
|
-
|
|
235
|
+
collection_id: str,
|
|
247
236
|
item_id: str,
|
|
248
237
|
provider: Optional[str] = None,
|
|
249
238
|
asset: Optional[str] = None,
|
|
@@ -251,13 +240,13 @@ def download_stac_item(
|
|
|
251
240
|
) -> Response:
|
|
252
241
|
"""Download item
|
|
253
242
|
|
|
254
|
-
:param
|
|
243
|
+
:param collection_id: id of the product type
|
|
255
244
|
:param item_id: Product ID
|
|
256
245
|
:param provider: (optional) Chosen provider
|
|
257
246
|
:param kwargs: additional download parameters
|
|
258
247
|
:returns: a stream of the downloaded data (zip file)
|
|
259
248
|
"""
|
|
260
|
-
product_type =
|
|
249
|
+
product_type = collection_id
|
|
261
250
|
|
|
262
251
|
search_results = eodag_api.search(
|
|
263
252
|
id=item_id, productType=product_type, provider=provider, **kwargs
|
|
@@ -320,8 +309,8 @@ def download_stac_item(
|
|
|
320
309
|
|
|
321
310
|
def _order_and_update(
|
|
322
311
|
product: EOProduct,
|
|
323
|
-
auth: Union[AuthBase,
|
|
324
|
-
query_args:
|
|
312
|
+
auth: Union[AuthBase, dict[str, str], None],
|
|
313
|
+
query_args: dict[str, Any],
|
|
325
314
|
) -> None:
|
|
326
315
|
"""Order product if needed and update given kwargs with order-status-dict"""
|
|
327
316
|
if product.properties.get("storageStatus") != ONLINE_STATUS and hasattr(
|
|
@@ -338,13 +327,11 @@ def _order_and_update(
|
|
|
338
327
|
if (
|
|
339
328
|
product.properties.get("storageStatus") != ONLINE_STATUS
|
|
340
329
|
and NOT_AVAILABLE in product.properties.get("orderStatusLink", "")
|
|
341
|
-
and hasattr(product.downloader, "
|
|
330
|
+
and hasattr(product.downloader, "_order")
|
|
342
331
|
):
|
|
343
332
|
# first order
|
|
344
333
|
logger.debug("Order product")
|
|
345
|
-
order_status_dict = product.downloader.
|
|
346
|
-
product=product, auth=auth
|
|
347
|
-
)
|
|
334
|
+
order_status_dict = product.downloader._order(product=product, auth=auth)
|
|
348
335
|
query_args.update(order_status_dict or {})
|
|
349
336
|
|
|
350
337
|
if (
|
|
@@ -355,18 +342,18 @@ def _order_and_update(
|
|
|
355
342
|
product.properties["storageStatus"] = STAGING_STATUS
|
|
356
343
|
|
|
357
344
|
if product.properties.get("storageStatus") == STAGING_STATUS and hasattr(
|
|
358
|
-
product.downloader, "
|
|
345
|
+
product.downloader, "_order_status"
|
|
359
346
|
):
|
|
360
347
|
# check order status if needed
|
|
361
348
|
logger.debug("Checking product order status")
|
|
362
|
-
product.downloader.
|
|
349
|
+
product.downloader._order_status(product=product, auth=auth)
|
|
363
350
|
|
|
364
351
|
if product.properties.get("storageStatus") != ONLINE_STATUS:
|
|
365
352
|
raise NotAvailableError("Product is not available yet")
|
|
366
353
|
|
|
367
354
|
|
|
368
355
|
@lru_cache(maxsize=1)
|
|
369
|
-
def get_detailled_collections_list() ->
|
|
356
|
+
def get_detailled_collections_list() -> list[dict[str, Any]]:
|
|
370
357
|
"""Returns detailled collections / product_types list as a list of
|
|
371
358
|
config dicts
|
|
372
359
|
|
|
@@ -383,17 +370,17 @@ async def all_collections(
|
|
|
383
370
|
instrument: Optional[str] = None,
|
|
384
371
|
constellation: Optional[str] = None,
|
|
385
372
|
datetime: Optional[str] = None,
|
|
386
|
-
) ->
|
|
373
|
+
) -> dict[str, Any]:
|
|
387
374
|
"""Build STAC collections
|
|
388
375
|
|
|
389
376
|
:param url: Requested URL
|
|
390
377
|
:param root: The API root
|
|
391
378
|
:param filters: Search collections filters
|
|
392
379
|
:param provider: (optional) Chosen provider
|
|
393
|
-
:returns: Collections
|
|
380
|
+
:returns: Collections dictionary
|
|
394
381
|
"""
|
|
395
382
|
|
|
396
|
-
async def _fetch() ->
|
|
383
|
+
async def _fetch() -> dict[str, Any]:
|
|
397
384
|
stac_collection = StacCollection(
|
|
398
385
|
url=request.state.url,
|
|
399
386
|
stac_config=stac_config,
|
|
@@ -413,7 +400,10 @@ async def all_collections(
|
|
|
413
400
|
# # parse f-strings
|
|
414
401
|
format_args = deepcopy(stac_config)
|
|
415
402
|
format_args["collections"].update(
|
|
416
|
-
{
|
|
403
|
+
{
|
|
404
|
+
"url": stac_collection.url,
|
|
405
|
+
"root": stac_collection.root,
|
|
406
|
+
}
|
|
417
407
|
)
|
|
418
408
|
|
|
419
409
|
collections["links"] = [
|
|
@@ -423,14 +413,16 @@ async def all_collections(
|
|
|
423
413
|
collections = format_dict_items(collections, **format_args)
|
|
424
414
|
return collections
|
|
425
415
|
|
|
426
|
-
hashed_collections = hash(
|
|
416
|
+
hashed_collections = hash(
|
|
417
|
+
f"{provider}:{q}:{platform}:{instrument}:{constellation}:{datetime}"
|
|
418
|
+
)
|
|
427
419
|
cache_key = f"{CACHE_KEY_COLLECTIONS}:{hashed_collections}"
|
|
428
420
|
return await cached(_fetch, cache_key, request)
|
|
429
421
|
|
|
430
422
|
|
|
431
423
|
async def get_collection(
|
|
432
424
|
request: Request, collection_id: str, provider: Optional[str] = None
|
|
433
|
-
) ->
|
|
425
|
+
) -> dict[str, Any]:
|
|
434
426
|
"""Build STAC collection by id
|
|
435
427
|
|
|
436
428
|
:param url: Requested URL
|
|
@@ -440,7 +432,7 @@ async def get_collection(
|
|
|
440
432
|
:returns: Collection dictionary
|
|
441
433
|
"""
|
|
442
434
|
|
|
443
|
-
async def _fetch() ->
|
|
435
|
+
async def _fetch() -> dict[str, Any]:
|
|
444
436
|
stac_collection = StacCollection(
|
|
445
437
|
url=request.state.url,
|
|
446
438
|
stac_config=stac_config,
|
|
@@ -462,32 +454,26 @@ async def get_collection(
|
|
|
462
454
|
async def get_stac_catalogs(
|
|
463
455
|
request: Request,
|
|
464
456
|
url: str,
|
|
465
|
-
catalogs: Optional[Tuple[str, ...]] = None,
|
|
466
457
|
provider: Optional[str] = None,
|
|
467
|
-
) ->
|
|
458
|
+
) -> dict[str, Any]:
|
|
468
459
|
"""Build STAC catalog
|
|
469
460
|
|
|
470
461
|
:param url: Requested URL
|
|
471
462
|
:param root: (optional) API root
|
|
472
|
-
:param catalogs: (optional) Catalogs list
|
|
473
463
|
:param provider: (optional) Chosen provider
|
|
474
464
|
:returns: Catalog dictionary
|
|
475
465
|
"""
|
|
476
466
|
|
|
477
|
-
async def _fetch() ->
|
|
467
|
+
async def _fetch() -> dict[str, Any]:
|
|
478
468
|
return StacCatalog(
|
|
479
469
|
url=url,
|
|
480
470
|
stac_config=stac_config,
|
|
481
471
|
root=request.state.url_root,
|
|
482
472
|
provider=provider,
|
|
483
473
|
eodag_api=eodag_api,
|
|
484
|
-
catalogs=list(catalogs) if catalogs else None,
|
|
485
474
|
).data
|
|
486
475
|
|
|
487
|
-
|
|
488
|
-
return await cached(
|
|
489
|
-
_fetch, f"{CACHE_KEY_COLLECTION}:{provider}:{hashed_catalogs}", request
|
|
490
|
-
)
|
|
476
|
+
return await cached(_fetch, f"{CACHE_KEY_COLLECTION}:{provider}", request)
|
|
491
477
|
|
|
492
478
|
|
|
493
479
|
def time_interval_overlap(eodag_args: EODAGSearch, catalog: StacCatalog) -> bool:
|
|
@@ -495,7 +481,10 @@ def time_interval_overlap(eodag_args: EODAGSearch, catalog: StacCatalog) -> bool
|
|
|
495
481
|
# check if time filtering appears both in search arguments and catalog
|
|
496
482
|
# (for catalogs built by date: i.e. `year/2020/month/05`)
|
|
497
483
|
if not set(["start", "end"]) <= set(eodag_args.model_dump().keys()) or not set(
|
|
498
|
-
[
|
|
484
|
+
[
|
|
485
|
+
"start",
|
|
486
|
+
"end",
|
|
487
|
+
]
|
|
499
488
|
) <= set(catalog.search_args.keys()):
|
|
500
489
|
return True
|
|
501
490
|
|
|
@@ -534,10 +523,10 @@ def time_interval_overlap(eodag_args: EODAGSearch, catalog: StacCatalog) -> bool
|
|
|
534
523
|
|
|
535
524
|
|
|
536
525
|
@lru_cache(maxsize=1)
|
|
537
|
-
def get_stac_conformance() ->
|
|
526
|
+
def get_stac_conformance() -> dict[str, str]:
|
|
538
527
|
"""Build STAC conformance
|
|
539
528
|
|
|
540
|
-
:returns: conformance
|
|
529
|
+
:returns: conformance dictionary
|
|
541
530
|
"""
|
|
542
531
|
return stac_config["conformance"]
|
|
543
532
|
|
|
@@ -551,11 +540,11 @@ def get_stac_api_version() -> str:
|
|
|
551
540
|
|
|
552
541
|
|
|
553
542
|
@lru_cache(maxsize=1)
|
|
554
|
-
def get_stac_extension_oseo(url: str) ->
|
|
543
|
+
def get_stac_extension_oseo(url: str) -> dict[str, str]:
|
|
555
544
|
"""Build STAC OGC / OpenSearch Extension for EO
|
|
556
545
|
|
|
557
546
|
:param url: Requested URL
|
|
558
|
-
:returns: Catalog
|
|
547
|
+
:returns: Catalog dictionary
|
|
559
548
|
"""
|
|
560
549
|
|
|
561
550
|
def apply_method(_: str, x: str) -> str:
|
|
@@ -582,50 +571,96 @@ async def get_queryables(
|
|
|
582
571
|
request: Request,
|
|
583
572
|
params: QueryablesGetParams,
|
|
584
573
|
provider: Optional[str] = None,
|
|
585
|
-
) ->
|
|
574
|
+
) -> dict[str, Any]:
|
|
586
575
|
"""Fetch the queryable properties for a collection.
|
|
587
576
|
|
|
588
577
|
:param collection_id: The ID of the collection.
|
|
589
578
|
:returns: A set containing the STAC standardized queryable properties for a collection.
|
|
590
579
|
"""
|
|
591
580
|
|
|
592
|
-
async def _fetch() ->
|
|
581
|
+
async def _fetch() -> dict[str, Any]:
|
|
593
582
|
python_queryables = eodag_api.list_queryables(
|
|
594
|
-
provider=provider,
|
|
583
|
+
provider=provider,
|
|
584
|
+
fetch_providers=False,
|
|
585
|
+
**params.model_dump(exclude_none=True, by_alias=True),
|
|
595
586
|
)
|
|
596
|
-
python_queryables.pop("start")
|
|
597
|
-
python_queryables.pop("end")
|
|
598
|
-
|
|
599
|
-
# productType and id are already default in stac collection and id
|
|
600
|
-
python_queryables.pop("productType", None)
|
|
601
|
-
python_queryables.pop("id", None)
|
|
602
587
|
|
|
603
|
-
|
|
604
|
-
|
|
588
|
+
python_queryables_json = python_queryables.get_model().model_json_schema(
|
|
589
|
+
by_alias=True
|
|
605
590
|
)
|
|
606
|
-
for param, queryable in python_queryables.items():
|
|
607
|
-
stac_param = EODAGSearch.to_stac(param)
|
|
608
|
-
# only keep "datetime" queryable for dates
|
|
609
|
-
if stac_param in stac_queryables or stac_param in (
|
|
610
|
-
"start_datetime",
|
|
611
|
-
"end_datetime",
|
|
612
|
-
):
|
|
613
|
-
continue
|
|
614
591
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
] = StacQueryableProperty.from_python_field_definition(
|
|
618
|
-
stac_param, queryable
|
|
619
|
-
)
|
|
592
|
+
properties: dict[str, Any] = python_queryables_json["properties"]
|
|
593
|
+
required: list[str] = python_queryables_json.get("required") or []
|
|
620
594
|
|
|
621
|
-
|
|
622
|
-
|
|
595
|
+
# productType is either simply removed or replaced by collection later.
|
|
596
|
+
if "productType" in properties:
|
|
597
|
+
properties.pop("productType")
|
|
598
|
+
if "productType" in required:
|
|
599
|
+
required.remove("productType")
|
|
600
|
+
|
|
601
|
+
stac_properties: dict[str, Any] = {}
|
|
602
|
+
|
|
603
|
+
# get stac default properties to set prefixes
|
|
604
|
+
stac_item_properties = list(stac_config["item"]["properties"].values())
|
|
605
|
+
stac_item_properties.extend(stac_config["metadata_ignore"])
|
|
606
|
+
for param, queryable in properties.items():
|
|
607
|
+
# convert key to STAC format
|
|
608
|
+
if param in OSEO_METADATA_MAPPING.keys() and not any(
|
|
609
|
+
param in str(prop) for prop in stac_item_properties
|
|
610
|
+
):
|
|
611
|
+
param = f"oseo:{param}"
|
|
612
|
+
stac_param = EODAGSearch.to_stac(param, stac_item_properties, provider)
|
|
613
|
+
|
|
614
|
+
queryable["title"] = stac_param.split(":")[-1]
|
|
615
|
+
|
|
616
|
+
# remove null default values
|
|
617
|
+
if not queryable.get("default"):
|
|
618
|
+
queryable.pop("default", None)
|
|
619
|
+
|
|
620
|
+
stac_properties[stac_param] = queryable
|
|
621
|
+
required = list(map(lambda x: x.replace(param, stac_param), required))
|
|
622
|
+
|
|
623
|
+
# due to certain metadata mappings we might only get end_datetime but we can
|
|
624
|
+
# assume that start_datetime is also available
|
|
625
|
+
if (
|
|
626
|
+
"end_datetime" in stac_properties
|
|
627
|
+
and "start_datetime" not in stac_properties
|
|
628
|
+
):
|
|
629
|
+
stac_properties["start_datetime"] = deepcopy(
|
|
630
|
+
stac_properties["end_datetime"]
|
|
631
|
+
)
|
|
632
|
+
stac_properties["start_datetime"]["title"] = "start_datetime"
|
|
633
|
+
# if we can search by start_datetime we can search by datetime
|
|
634
|
+
if "start_datetime" in stac_properties:
|
|
635
|
+
stac_properties["datetime"] = StacQueryables.possible_properties[
|
|
636
|
+
"datetime"
|
|
637
|
+
].model_dump()
|
|
638
|
+
|
|
639
|
+
# format spatial extend properties to STAC format.
|
|
640
|
+
if "geometry" in stac_properties:
|
|
641
|
+
stac_properties["bbox"] = StacQueryables.possible_properties[
|
|
642
|
+
"bbox"
|
|
643
|
+
].model_dump()
|
|
644
|
+
stac_properties["geometry"] = StacQueryables.possible_properties[
|
|
645
|
+
"geometry"
|
|
646
|
+
].model_dump()
|
|
647
|
+
|
|
648
|
+
if not params.collection:
|
|
649
|
+
stac_properties["collection"] = StacQueryables.default_properties[
|
|
650
|
+
"collection"
|
|
651
|
+
].model_dump()
|
|
652
|
+
|
|
653
|
+
additional_properties = python_queryables.additional_properties
|
|
654
|
+
description = "Queryable names for the EODAG STAC API Item Search filter. "
|
|
655
|
+
description += python_queryables.additional_information
|
|
623
656
|
|
|
624
657
|
return StacQueryables(
|
|
625
658
|
q_id=request.state.url,
|
|
626
|
-
additional_properties=
|
|
627
|
-
properties=
|
|
628
|
-
|
|
659
|
+
additional_properties=additional_properties,
|
|
660
|
+
properties=stac_properties,
|
|
661
|
+
required=required or None,
|
|
662
|
+
description=description,
|
|
663
|
+
).model_dump(mode="json", by_alias=True, exclude_none=True)
|
|
629
664
|
|
|
630
665
|
hashed_queryables = hash(params.model_dump_json())
|
|
631
666
|
return await cached(
|
|
@@ -652,7 +687,7 @@ def crunch_products(
|
|
|
652
687
|
f'Unknown crunch name. Use one of: {", ".join(crunchers.keys())}'
|
|
653
688
|
)
|
|
654
689
|
|
|
655
|
-
cruncher_config:
|
|
690
|
+
cruncher_config: dict[str, Any] = {}
|
|
656
691
|
for config_param in cruncher.config_params:
|
|
657
692
|
config_param_value = kwargs.get(config_param)
|
|
658
693
|
if not config_param_value:
|
|
@@ -685,17 +720,22 @@ def eodag_api_init() -> None:
|
|
|
685
720
|
ext_col = StacCollection.ext_stac_collections.get(key)
|
|
686
721
|
if not ext_col:
|
|
687
722
|
continue
|
|
688
|
-
platform: Union[str,
|
|
723
|
+
platform: Union[str, list[str]] = ext_col.get("summaries", {}).get(
|
|
689
724
|
"platform"
|
|
690
725
|
)
|
|
691
|
-
constellation: Union[str,
|
|
726
|
+
constellation: Union[str, list[str]] = ext_col.get("summaries", {}).get(
|
|
692
727
|
"constellation"
|
|
693
728
|
)
|
|
729
|
+
processing_level: Union[str, list[str]] = ext_col.get("summaries", {}).get(
|
|
730
|
+
"processing:level"
|
|
731
|
+
)
|
|
694
732
|
# Check if platform or constellation are lists and join them into a string if they are
|
|
695
733
|
if isinstance(platform, list):
|
|
696
734
|
platform = ",".join(platform)
|
|
697
735
|
if isinstance(constellation, list):
|
|
698
736
|
constellation = ",".join(constellation)
|
|
737
|
+
if isinstance(processing_level, list):
|
|
738
|
+
processing_level = ",".join(processing_level)
|
|
699
739
|
|
|
700
740
|
update_fields = {
|
|
701
741
|
"title": ext_col.get("title"),
|
|
@@ -706,7 +746,7 @@ def eodag_api_init() -> None:
|
|
|
706
746
|
),
|
|
707
747
|
"platform": constellation,
|
|
708
748
|
"platformSerialIdentifier": platform,
|
|
709
|
-
"processingLevel":
|
|
749
|
+
"processingLevel": processing_level,
|
|
710
750
|
"license": ext_col["license"],
|
|
711
751
|
"missionStartDate": ext_col["extent"]["temporal"]["interval"][0][0],
|
|
712
752
|
"missionEndDate": ext_col["extent"]["temporal"]["interval"][-1][1],
|