eodag 3.0.0b3__py3-none-any.whl → 3.0.1__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 +189 -125
- eodag/api/product/metadata_mapping.py +12 -3
- eodag/api/search_result.py +29 -3
- eodag/cli.py +35 -19
- eodag/config.py +412 -116
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +14 -4
- eodag/plugins/apis/usgs.py +25 -2
- eodag/plugins/authentication/aws_auth.py +14 -5
- eodag/plugins/authentication/base.py +10 -1
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +12 -4
- eodag/plugins/authentication/keycloak.py +41 -22
- eodag/plugins/authentication/oauth.py +11 -1
- eodag/plugins/authentication/openid_connect.py +178 -163
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +19 -2
- eodag/plugins/authentication/token.py +57 -10
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/crunch/base.py +4 -1
- eodag/plugins/crunch/filter_date.py +5 -2
- eodag/plugins/crunch/filter_latest_intersect.py +5 -4
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/crunch/filter_overlap.py +5 -7
- eodag/plugins/crunch/filter_property.py +4 -3
- eodag/plugins/download/aws.py +39 -22
- eodag/plugins/download/base.py +11 -11
- eodag/plugins/download/creodias_s3.py +11 -2
- eodag/plugins/download/http.py +86 -52
- eodag/plugins/download/s3rest.py +20 -18
- eodag/plugins/manager.py +168 -23
- eodag/plugins/search/base.py +33 -14
- eodag/plugins/search/build_search_result.py +55 -51
- eodag/plugins/search/cop_marine.py +112 -29
- eodag/plugins/search/creodias_s3.py +20 -5
- eodag/plugins/search/csw.py +41 -1
- eodag/plugins/search/data_request_search.py +109 -9
- eodag/plugins/search/qssearch.py +532 -152
- eodag/plugins/search/static_stac_search.py +20 -21
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +187 -56
- eodag/resources/providers.yml +1610 -1701
- eodag/resources/stac.yml +3 -163
- eodag/resources/user_conf_template.yml +112 -97
- eodag/rest/config.py +1 -2
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +61 -51
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +24 -325
- eodag/rest/stac.py +93 -544
- eodag/rest/types/eodag_search.py +13 -8
- eodag/rest/types/queryables.py +1 -2
- eodag/rest/types/stac_search.py +11 -2
- eodag/types/__init__.py +15 -3
- eodag/types/download_args.py +1 -1
- eodag/types/queryables.py +1 -2
- eodag/types/search_args.py +3 -3
- eodag/utils/__init__.py +77 -57
- eodag/utils/exceptions.py +23 -9
- eodag/utils/logging.py +37 -77
- eodag/utils/requests.py +1 -3
- eodag/utils/stac_reader.py +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/METADATA +11 -12
- eodag-3.0.1.dist-info/RECORD +109 -0
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/entry_points.txt +1 -0
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag-3.0.0b3.dist-info/RECORD +0 -110
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.0.1.dist-info}/top_level.txt +0 -0
eodag/rest/core.py
CHANGED
|
@@ -33,6 +33,7 @@ from requests.models import Response as RequestsResponse
|
|
|
33
33
|
import eodag
|
|
34
34
|
from eodag import EOProduct
|
|
35
35
|
from eodag.api.product.metadata_mapping import (
|
|
36
|
+
DEFAULT_METADATA_MAPPING,
|
|
36
37
|
NOT_AVAILABLE,
|
|
37
38
|
OFFLINE_STATUS,
|
|
38
39
|
ONLINE_STATUS,
|
|
@@ -50,6 +51,7 @@ from eodag.rest.constants import (
|
|
|
50
51
|
CACHE_KEY_COLLECTIONS,
|
|
51
52
|
CACHE_KEY_QUERYABLES,
|
|
52
53
|
)
|
|
54
|
+
from eodag.rest.errors import ResponseSearchError
|
|
53
55
|
from eodag.rest.stac import StacCatalog, StacCollection, StacCommon, StacItem
|
|
54
56
|
from eodag.rest.types.eodag_search import EODAGSearch
|
|
55
57
|
from eodag.rest.types.queryables import (
|
|
@@ -80,7 +82,7 @@ from eodag.utils.exceptions import (
|
|
|
80
82
|
)
|
|
81
83
|
|
|
82
84
|
if TYPE_CHECKING:
|
|
83
|
-
from typing import Any, Dict, List, Optional,
|
|
85
|
+
from typing import Any, Dict, List, Optional, Union
|
|
84
86
|
|
|
85
87
|
from fastapi import Request
|
|
86
88
|
from requests.auth import AuthBase
|
|
@@ -133,17 +135,15 @@ def format_product_types(product_types: List[Dict[str, Any]]) -> str:
|
|
|
133
135
|
def search_stac_items(
|
|
134
136
|
request: Request,
|
|
135
137
|
search_request: SearchPostRequest,
|
|
136
|
-
catalogs: Optional[List[str]] = None,
|
|
137
138
|
) -> Dict[str, Any]:
|
|
138
139
|
"""
|
|
139
|
-
Search and retrieve STAC items
|
|
140
|
+
Search and retrieve STAC items based on the given search request.
|
|
140
141
|
|
|
141
|
-
This function takes a search request
|
|
142
|
+
This function takes a search request, performs a search using EODAG API, and returns a
|
|
142
143
|
dictionary of STAC items.
|
|
143
144
|
|
|
144
145
|
: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.
|
|
146
|
+
:param search_request: The search criteria for STAC items
|
|
147
147
|
:returns: A dictionary containing the STAC items and related metadata.
|
|
148
148
|
|
|
149
149
|
The function handles the conversion of search criteria into STAC and EODAG compatible formats, validates the input
|
|
@@ -165,60 +165,64 @@ def search_stac_items(
|
|
|
165
165
|
if search_request.spatial_filter:
|
|
166
166
|
stac_args["geometry"] = search_request.spatial_filter
|
|
167
167
|
try:
|
|
168
|
-
eodag_args = EODAGSearch.model_validate(
|
|
169
|
-
stac_args, context={"isCatalog": bool(catalogs)}
|
|
170
|
-
)
|
|
168
|
+
eodag_args = EODAGSearch.model_validate(stac_args)
|
|
171
169
|
except pydanticValidationError as e:
|
|
172
170
|
raise ValidationError(format_pydantic_error(e)) from e
|
|
173
171
|
|
|
174
172
|
catalog_url = re.sub("/items.*", "", request.state.url)
|
|
175
|
-
|
|
176
173
|
catalog = StacCatalog(
|
|
177
|
-
url=(
|
|
178
|
-
catalog_url
|
|
179
|
-
if catalogs
|
|
180
|
-
else catalog_url.replace(
|
|
181
|
-
"/search", f"/collections/{eodag_args.productType}"
|
|
182
|
-
)
|
|
183
|
-
),
|
|
174
|
+
url=catalog_url.replace("/search", f"/collections/{eodag_args.productType}"),
|
|
184
175
|
stac_config=stac_config,
|
|
185
176
|
root=request.state.url_root,
|
|
186
177
|
provider=eodag_args.provider,
|
|
187
178
|
eodag_api=eodag_api,
|
|
188
|
-
|
|
179
|
+
collection=eodag_args.productType, # type: ignore
|
|
189
180
|
)
|
|
190
181
|
|
|
191
182
|
# get products by ids
|
|
192
183
|
if eodag_args.ids:
|
|
193
|
-
|
|
184
|
+
results = SearchResult([])
|
|
194
185
|
for item_id in eodag_args.ids:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
186
|
+
results.extend(
|
|
187
|
+
eodag_api.search(
|
|
188
|
+
id=item_id,
|
|
189
|
+
productType=eodag_args.productType,
|
|
190
|
+
provider=eodag_args.provider,
|
|
191
|
+
)
|
|
199
192
|
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
total = len(search_results)
|
|
193
|
+
results.number_matched = len(results)
|
|
194
|
+
total = len(results)
|
|
203
195
|
|
|
204
196
|
elif time_interval_overlap(eodag_args, catalog):
|
|
205
197
|
criteria = {
|
|
206
198
|
**catalog.search_args,
|
|
207
199
|
**eodag_args.model_dump(exclude_none=True),
|
|
208
200
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
201
|
+
# remove provider prefixes
|
|
202
|
+
stac_extensions = stac_config["extensions"]
|
|
203
|
+
keys_to_update = {}
|
|
204
|
+
for key in criteria:
|
|
205
|
+
if ":" in key and key.split(":")[0] not in stac_extensions:
|
|
206
|
+
new_key = key.split(":")[1]
|
|
207
|
+
keys_to_update[key] = new_key
|
|
208
|
+
for key, new_key in keys_to_update.items():
|
|
209
|
+
criteria[new_key] = criteria[key]
|
|
210
|
+
criteria.pop(key)
|
|
211
|
+
|
|
212
|
+
results = eodag_api.search(count=True, **criteria)
|
|
213
|
+
total = results.number_matched or 0
|
|
216
214
|
else:
|
|
217
215
|
# return empty results
|
|
218
|
-
|
|
216
|
+
results = SearchResult([], 0)
|
|
219
217
|
total = 0
|
|
220
218
|
|
|
221
|
-
|
|
219
|
+
if len(results) == 0 and results.errors:
|
|
220
|
+
raise ResponseSearchError(results.errors)
|
|
221
|
+
|
|
222
|
+
if search_request.crunch:
|
|
223
|
+
results = crunch_products(results, search_request.crunch, **criteria)
|
|
224
|
+
|
|
225
|
+
for record in results:
|
|
222
226
|
record.product_type = eodag_api.get_alias_from_product_type(record.product_type)
|
|
223
227
|
|
|
224
228
|
items = StacItem(
|
|
@@ -228,7 +232,7 @@ def search_stac_items(
|
|
|
228
232
|
eodag_api=eodag_api,
|
|
229
233
|
root=request.state.url_root,
|
|
230
234
|
).get_stac_items(
|
|
231
|
-
search_results=
|
|
235
|
+
search_results=results,
|
|
232
236
|
total=total,
|
|
233
237
|
next_link=get_next_link(
|
|
234
238
|
request, search_request, total, eodag_args.items_per_page
|
|
@@ -243,7 +247,7 @@ def search_stac_items(
|
|
|
243
247
|
|
|
244
248
|
def download_stac_item(
|
|
245
249
|
request: Request,
|
|
246
|
-
|
|
250
|
+
collection_id: str,
|
|
247
251
|
item_id: str,
|
|
248
252
|
provider: Optional[str] = None,
|
|
249
253
|
asset: Optional[str] = None,
|
|
@@ -251,13 +255,13 @@ def download_stac_item(
|
|
|
251
255
|
) -> Response:
|
|
252
256
|
"""Download item
|
|
253
257
|
|
|
254
|
-
:param
|
|
258
|
+
:param collection_id: id of the product type
|
|
255
259
|
:param item_id: Product ID
|
|
256
260
|
:param provider: (optional) Chosen provider
|
|
257
261
|
:param kwargs: additional download parameters
|
|
258
262
|
:returns: a stream of the downloaded data (zip file)
|
|
259
263
|
"""
|
|
260
|
-
product_type =
|
|
264
|
+
product_type = collection_id
|
|
261
265
|
|
|
262
266
|
search_results = eodag_api.search(
|
|
263
267
|
id=item_id, productType=product_type, provider=provider, **kwargs
|
|
@@ -390,7 +394,7 @@ async def all_collections(
|
|
|
390
394
|
:param root: The API root
|
|
391
395
|
:param filters: Search collections filters
|
|
392
396
|
:param provider: (optional) Chosen provider
|
|
393
|
-
:returns: Collections
|
|
397
|
+
:returns: Collections dictionary
|
|
394
398
|
"""
|
|
395
399
|
|
|
396
400
|
async def _fetch() -> Dict[str, Any]:
|
|
@@ -423,7 +427,9 @@ async def all_collections(
|
|
|
423
427
|
collections = format_dict_items(collections, **format_args)
|
|
424
428
|
return collections
|
|
425
429
|
|
|
426
|
-
hashed_collections = hash(
|
|
430
|
+
hashed_collections = hash(
|
|
431
|
+
f"{provider}:{q}:{platform}:{instrument}:{constellation}:{datetime}"
|
|
432
|
+
)
|
|
427
433
|
cache_key = f"{CACHE_KEY_COLLECTIONS}:{hashed_collections}"
|
|
428
434
|
return await cached(_fetch, cache_key, request)
|
|
429
435
|
|
|
@@ -462,14 +468,12 @@ async def get_collection(
|
|
|
462
468
|
async def get_stac_catalogs(
|
|
463
469
|
request: Request,
|
|
464
470
|
url: str,
|
|
465
|
-
catalogs: Optional[Tuple[str, ...]] = None,
|
|
466
471
|
provider: Optional[str] = None,
|
|
467
472
|
) -> Dict[str, Any]:
|
|
468
473
|
"""Build STAC catalog
|
|
469
474
|
|
|
470
475
|
:param url: Requested URL
|
|
471
476
|
:param root: (optional) API root
|
|
472
|
-
:param catalogs: (optional) Catalogs list
|
|
473
477
|
:param provider: (optional) Chosen provider
|
|
474
478
|
:returns: Catalog dictionary
|
|
475
479
|
"""
|
|
@@ -481,13 +485,9 @@ async def get_stac_catalogs(
|
|
|
481
485
|
root=request.state.url_root,
|
|
482
486
|
provider=provider,
|
|
483
487
|
eodag_api=eodag_api,
|
|
484
|
-
catalogs=list(catalogs) if catalogs else None,
|
|
485
488
|
).data
|
|
486
489
|
|
|
487
|
-
|
|
488
|
-
return await cached(
|
|
489
|
-
_fetch, f"{CACHE_KEY_COLLECTION}:{provider}:{hashed_catalogs}", request
|
|
490
|
-
)
|
|
490
|
+
return await cached(_fetch, f"{CACHE_KEY_COLLECTION}:{provider}", request)
|
|
491
491
|
|
|
492
492
|
|
|
493
493
|
def time_interval_overlap(eodag_args: EODAGSearch, catalog: StacCatalog) -> bool:
|
|
@@ -537,7 +537,7 @@ def time_interval_overlap(eodag_args: EODAGSearch, catalog: StacCatalog) -> bool
|
|
|
537
537
|
def get_stac_conformance() -> Dict[str, str]:
|
|
538
538
|
"""Build STAC conformance
|
|
539
539
|
|
|
540
|
-
:returns: conformance
|
|
540
|
+
:returns: conformance dictionary
|
|
541
541
|
"""
|
|
542
542
|
return stac_config["conformance"]
|
|
543
543
|
|
|
@@ -555,7 +555,7 @@ def get_stac_extension_oseo(url: str) -> Dict[str, str]:
|
|
|
555
555
|
"""Build STAC OGC / OpenSearch Extension for EO
|
|
556
556
|
|
|
557
557
|
:param url: Requested URL
|
|
558
|
-
:returns: Catalog
|
|
558
|
+
:returns: Catalog dictionary
|
|
559
559
|
"""
|
|
560
560
|
|
|
561
561
|
def apply_method(_: str, x: str) -> str:
|
|
@@ -603,8 +603,18 @@ async def get_queryables(
|
|
|
603
603
|
stac_queryables: Dict[str, StacQueryableProperty] = deepcopy(
|
|
604
604
|
StacQueryables.default_properties
|
|
605
605
|
)
|
|
606
|
+
# get stac default properties to set prefixes
|
|
607
|
+
stac_item_properties = list(stac_config["item"]["properties"].values())
|
|
608
|
+
stac_item_properties.extend(list(stac_queryables.keys()))
|
|
609
|
+
ignore = stac_config["metadata_ignore"]
|
|
610
|
+
stac_item_properties.extend(ignore)
|
|
611
|
+
default_mapping = DEFAULT_METADATA_MAPPING.keys()
|
|
606
612
|
for param, queryable in python_queryables.items():
|
|
607
|
-
|
|
613
|
+
if param in default_mapping and not any(
|
|
614
|
+
param in str(prop) for prop in stac_item_properties
|
|
615
|
+
):
|
|
616
|
+
param = f"oseo:{param}"
|
|
617
|
+
stac_param = EODAGSearch.to_stac(param, stac_item_properties, provider)
|
|
608
618
|
# only keep "datetime" queryable for dates
|
|
609
619
|
if stac_param in stac_queryables or stac_param in (
|
|
610
620
|
"start_datetime",
|
eodag/rest/errors.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright 2024, CS GROUP - France, https://www.csgroup.eu/
|
|
3
|
+
#
|
|
4
|
+
# This file is part of EODAG project
|
|
5
|
+
# https://www.github.com/CS-SI/EODAG
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
import logging
|
|
19
|
+
from typing import Dict, List, Tuple, Union
|
|
20
|
+
|
|
21
|
+
from fastapi import FastAPI, Request
|
|
22
|
+
from fastapi.responses import ORJSONResponse
|
|
23
|
+
from starlette import status
|
|
24
|
+
from starlette.exceptions import HTTPException as StarletteHTTPException
|
|
25
|
+
|
|
26
|
+
from eodag.rest.types.eodag_search import EODAGSearch
|
|
27
|
+
from eodag.utils.exceptions import (
|
|
28
|
+
AuthenticationError,
|
|
29
|
+
DownloadError,
|
|
30
|
+
EodagError,
|
|
31
|
+
MisconfiguredError,
|
|
32
|
+
NoMatchingProductType,
|
|
33
|
+
NotAvailableError,
|
|
34
|
+
RequestError,
|
|
35
|
+
TimeOutError,
|
|
36
|
+
UnsupportedProductType,
|
|
37
|
+
UnsupportedProvider,
|
|
38
|
+
ValidationError,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
EODAG_DEFAULT_STATUS_CODES = {
|
|
42
|
+
AuthenticationError: status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
43
|
+
DownloadError: status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
44
|
+
MisconfiguredError: status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
45
|
+
NotAvailableError: status.HTTP_404_NOT_FOUND,
|
|
46
|
+
NoMatchingProductType: status.HTTP_404_NOT_FOUND,
|
|
47
|
+
TimeOutError: status.HTTP_504_GATEWAY_TIMEOUT,
|
|
48
|
+
UnsupportedProductType: status.HTTP_404_NOT_FOUND,
|
|
49
|
+
UnsupportedProvider: status.HTTP_404_NOT_FOUND,
|
|
50
|
+
ValidationError: status.HTTP_400_BAD_REQUEST,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
logger = logging.getLogger("eodag.rest.server")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ResponseSearchError(Exception):
|
|
57
|
+
"""Represent a EODAG search error response"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, errors: List[Tuple[str, Exception]]) -> None:
|
|
60
|
+
self._errors = errors
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def errors(self) -> List[Dict[str, Union[str, int]]]:
|
|
64
|
+
"""return errors as a list of dict"""
|
|
65
|
+
error_list: List[Dict[str, Union[str, int]]] = []
|
|
66
|
+
for name, exception in self._errors:
|
|
67
|
+
|
|
68
|
+
error_dict: Dict[str, Union[str, int]] = {
|
|
69
|
+
"provider": name,
|
|
70
|
+
"error": exception.__class__.__name__,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if exception.args:
|
|
74
|
+
error_dict["message"] = exception.args[0]
|
|
75
|
+
|
|
76
|
+
if len(exception.args) > 1:
|
|
77
|
+
error_dict["detail"] = " ".join([str(i) for i in exception.args[1:]])
|
|
78
|
+
|
|
79
|
+
error_dict["status_code"] = EODAG_DEFAULT_STATUS_CODES.get(
|
|
80
|
+
type(exception), getattr(exception, "status_code", 500)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if type(exception) in (MisconfiguredError, AuthenticationError):
|
|
84
|
+
logger.error("%s: %s", type(exception).__name__, str(exception))
|
|
85
|
+
error_dict[
|
|
86
|
+
"message"
|
|
87
|
+
] = "Internal server error: please contact the administrator"
|
|
88
|
+
error_dict.pop("detail", None)
|
|
89
|
+
|
|
90
|
+
if type(exception) is ValidationError:
|
|
91
|
+
for error_param in exception.parameters:
|
|
92
|
+
stac_param = EODAGSearch.to_stac(error_param)
|
|
93
|
+
exception.message = exception.message.replace(
|
|
94
|
+
error_param, stac_param
|
|
95
|
+
)
|
|
96
|
+
error_dict["message"] = exception.message
|
|
97
|
+
|
|
98
|
+
error_list.append(error_dict)
|
|
99
|
+
|
|
100
|
+
return error_list
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def status_code(self) -> int:
|
|
104
|
+
"""get global errors status code"""
|
|
105
|
+
if len(self._errors) == 1 and type(self.errors[0]["status_code"]) is int:
|
|
106
|
+
return self.errors[0]["status_code"]
|
|
107
|
+
|
|
108
|
+
return 400
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
async def response_search_error_handler(
|
|
112
|
+
request: Request, exc: Exception
|
|
113
|
+
) -> ORJSONResponse:
|
|
114
|
+
"""Handle ResponseSearchError exceptions"""
|
|
115
|
+
if not isinstance(exc, ResponseSearchError):
|
|
116
|
+
return starlette_exception_handler(request, exc)
|
|
117
|
+
|
|
118
|
+
return ORJSONResponse(
|
|
119
|
+
status_code=exc.status_code,
|
|
120
|
+
content={"errors": exc.errors},
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
async def eodag_errors_handler(request: Request, exc: Exception) -> ORJSONResponse:
|
|
125
|
+
"""Handler for EODAG errors"""
|
|
126
|
+
if not isinstance(exc, EodagError):
|
|
127
|
+
return starlette_exception_handler(request, exc)
|
|
128
|
+
|
|
129
|
+
exception_status_code = getattr(exc, "status_code", None)
|
|
130
|
+
default_status_code = exception_status_code or 500
|
|
131
|
+
code = EODAG_DEFAULT_STATUS_CODES.get(type(exc), default_status_code)
|
|
132
|
+
|
|
133
|
+
detail = f"{type(exc).__name__}: {str(exc)}"
|
|
134
|
+
|
|
135
|
+
if type(exc) in (MisconfiguredError, AuthenticationError, TimeOutError):
|
|
136
|
+
logger.error("%s: %s", type(exc).__name__, str(exc))
|
|
137
|
+
|
|
138
|
+
if type(exc) in (MisconfiguredError, AuthenticationError):
|
|
139
|
+
detail = "Internal server error: please contact the administrator"
|
|
140
|
+
|
|
141
|
+
if type(exc) is ValidationError:
|
|
142
|
+
for error_param in exc.parameters:
|
|
143
|
+
stac_param = EODAGSearch.to_stac(error_param)
|
|
144
|
+
exc.message = exc.message.replace(error_param, stac_param)
|
|
145
|
+
detail = exc.message
|
|
146
|
+
|
|
147
|
+
return ORJSONResponse(
|
|
148
|
+
status_code=code,
|
|
149
|
+
content={"description": detail},
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def starlette_exception_handler(request: Request, error: Exception) -> ORJSONResponse:
|
|
154
|
+
"""Default errors handle"""
|
|
155
|
+
description = (
|
|
156
|
+
getattr(error, "description", None)
|
|
157
|
+
or getattr(error, "detail", None)
|
|
158
|
+
or str(error)
|
|
159
|
+
)
|
|
160
|
+
return ORJSONResponse(
|
|
161
|
+
status_code=getattr(error, "status_code", 500),
|
|
162
|
+
content={"description": description},
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def add_exception_handlers(app: FastAPI) -> None:
|
|
167
|
+
"""Add exception handlers to the FastAPI application.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
app: the FastAPI application.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
None
|
|
174
|
+
"""
|
|
175
|
+
app.add_exception_handler(StarletteHTTPException, starlette_exception_handler)
|
|
176
|
+
|
|
177
|
+
app.add_exception_handler(RequestError, eodag_errors_handler)
|
|
178
|
+
for exc in EODAG_DEFAULT_STATUS_CODES:
|
|
179
|
+
app.add_exception_handler(exc, eodag_errors_handler)
|
|
180
|
+
|
|
181
|
+
app.add_exception_handler(ResponseSearchError, response_search_error_handler)
|