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.
Files changed (94) hide show
  1. eodag/api/core.py +347 -247
  2. eodag/api/product/_assets.py +44 -15
  3. eodag/api/product/_product.py +58 -47
  4. eodag/api/product/drivers/__init__.py +81 -4
  5. eodag/api/product/drivers/base.py +65 -4
  6. eodag/api/product/drivers/generic.py +65 -0
  7. eodag/api/product/drivers/sentinel1.py +97 -0
  8. eodag/api/product/drivers/sentinel2.py +95 -0
  9. eodag/api/product/metadata_mapping.py +129 -93
  10. eodag/api/search_result.py +28 -12
  11. eodag/cli.py +61 -24
  12. eodag/config.py +457 -167
  13. eodag/plugins/apis/base.py +10 -4
  14. eodag/plugins/apis/ecmwf.py +53 -23
  15. eodag/plugins/apis/usgs.py +41 -17
  16. eodag/plugins/authentication/aws_auth.py +30 -18
  17. eodag/plugins/authentication/base.py +14 -3
  18. eodag/plugins/authentication/generic.py +14 -3
  19. eodag/plugins/authentication/header.py +14 -6
  20. eodag/plugins/authentication/keycloak.py +44 -25
  21. eodag/plugins/authentication/oauth.py +18 -4
  22. eodag/plugins/authentication/openid_connect.py +192 -171
  23. eodag/plugins/authentication/qsauth.py +12 -4
  24. eodag/plugins/authentication/sas_auth.py +22 -5
  25. eodag/plugins/authentication/token.py +95 -17
  26. eodag/plugins/authentication/token_exchange.py +19 -19
  27. eodag/plugins/base.py +4 -4
  28. eodag/plugins/crunch/base.py +8 -5
  29. eodag/plugins/crunch/filter_date.py +9 -6
  30. eodag/plugins/crunch/filter_latest_intersect.py +9 -8
  31. eodag/plugins/crunch/filter_latest_tpl_name.py +8 -8
  32. eodag/plugins/crunch/filter_overlap.py +9 -11
  33. eodag/plugins/crunch/filter_property.py +10 -10
  34. eodag/plugins/download/aws.py +181 -105
  35. eodag/plugins/download/base.py +49 -67
  36. eodag/plugins/download/creodias_s3.py +40 -2
  37. eodag/plugins/download/http.py +247 -223
  38. eodag/plugins/download/s3rest.py +29 -28
  39. eodag/plugins/manager.py +176 -41
  40. eodag/plugins/search/__init__.py +6 -5
  41. eodag/plugins/search/base.py +123 -60
  42. eodag/plugins/search/build_search_result.py +1046 -355
  43. eodag/plugins/search/cop_marine.py +132 -39
  44. eodag/plugins/search/creodias_s3.py +19 -68
  45. eodag/plugins/search/csw.py +48 -8
  46. eodag/plugins/search/data_request_search.py +124 -23
  47. eodag/plugins/search/qssearch.py +531 -310
  48. eodag/plugins/search/stac_list_assets.py +85 -0
  49. eodag/plugins/search/static_stac_search.py +23 -24
  50. eodag/resources/ext_product_types.json +1 -1
  51. eodag/resources/product_types.yml +1295 -355
  52. eodag/resources/providers.yml +1819 -3010
  53. eodag/resources/stac.yml +3 -163
  54. eodag/resources/stac_api.yml +2 -2
  55. eodag/resources/user_conf_template.yml +115 -99
  56. eodag/rest/cache.py +2 -2
  57. eodag/rest/config.py +3 -4
  58. eodag/rest/constants.py +0 -1
  59. eodag/rest/core.py +157 -117
  60. eodag/rest/errors.py +181 -0
  61. eodag/rest/server.py +57 -339
  62. eodag/rest/stac.py +133 -581
  63. eodag/rest/types/collections_search.py +3 -3
  64. eodag/rest/types/eodag_search.py +41 -30
  65. eodag/rest/types/queryables.py +42 -32
  66. eodag/rest/types/stac_search.py +15 -16
  67. eodag/rest/utils/__init__.py +14 -21
  68. eodag/rest/utils/cql_evaluate.py +6 -6
  69. eodag/rest/utils/rfc3339.py +2 -2
  70. eodag/types/__init__.py +153 -32
  71. eodag/types/bbox.py +2 -2
  72. eodag/types/download_args.py +4 -4
  73. eodag/types/queryables.py +183 -73
  74. eodag/types/search_args.py +6 -6
  75. eodag/types/whoosh.py +127 -3
  76. eodag/utils/__init__.py +228 -106
  77. eodag/utils/exceptions.py +47 -26
  78. eodag/utils/import_system.py +2 -2
  79. eodag/utils/logging.py +37 -77
  80. eodag/utils/repr.py +65 -6
  81. eodag/utils/requests.py +13 -15
  82. eodag/utils/rest.py +2 -2
  83. eodag/utils/s3.py +231 -0
  84. eodag/utils/stac_reader.py +11 -11
  85. {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/METADATA +81 -81
  86. eodag-3.1.0.dist-info/RECORD +113 -0
  87. {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/WHEEL +1 -1
  88. {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/entry_points.txt +5 -2
  89. eodag/resources/constraints/climate-dt.json +0 -13
  90. eodag/resources/constraints/extremes-dt.json +0 -8
  91. eodag/utils/constraints.py +0 -244
  92. eodag-3.0.0b3.dist-info/RECORD +0 -110
  93. {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/LICENSE +0 -0
  94. {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/top_level.txt +0 -0
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 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)