eodag 2.12.1__py3-none-any.whl → 3.0.0b1__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 +434 -319
- eodag/api/product/__init__.py +5 -1
- eodag/api/product/_assets.py +7 -2
- eodag/api/product/_product.py +46 -68
- eodag/api/product/metadata_mapping.py +181 -66
- eodag/api/search_result.py +21 -1
- eodag/cli.py +20 -6
- eodag/config.py +95 -6
- eodag/plugins/apis/base.py +8 -165
- eodag/plugins/apis/ecmwf.py +36 -24
- eodag/plugins/apis/usgs.py +40 -24
- eodag/plugins/authentication/aws_auth.py +2 -2
- eodag/plugins/authentication/header.py +31 -6
- eodag/plugins/authentication/keycloak.py +13 -84
- eodag/plugins/authentication/oauth.py +3 -3
- eodag/plugins/authentication/openid_connect.py +256 -46
- eodag/plugins/authentication/qsauth.py +3 -0
- eodag/plugins/authentication/sas_auth.py +8 -1
- eodag/plugins/authentication/token.py +92 -46
- eodag/plugins/authentication/token_exchange.py +120 -0
- eodag/plugins/download/aws.py +86 -91
- eodag/plugins/download/base.py +72 -40
- eodag/plugins/download/http.py +607 -264
- eodag/plugins/download/s3rest.py +28 -15
- eodag/plugins/manager.py +73 -57
- eodag/plugins/search/__init__.py +36 -0
- eodag/plugins/search/base.py +225 -18
- eodag/plugins/search/build_search_result.py +389 -32
- eodag/plugins/search/cop_marine.py +378 -0
- eodag/plugins/search/creodias_s3.py +15 -14
- eodag/plugins/search/csw.py +5 -7
- eodag/plugins/search/data_request_search.py +44 -20
- eodag/plugins/search/qssearch.py +508 -203
- eodag/plugins/search/static_stac_search.py +99 -36
- eodag/resources/constraints/climate-dt.json +13 -0
- eodag/resources/constraints/extremes-dt.json +8 -0
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +1897 -34
- eodag/resources/providers.yml +3539 -3277
- eodag/resources/stac.yml +48 -54
- eodag/resources/stac_api.yml +71 -25
- eodag/resources/stac_provider.yml +5 -0
- eodag/resources/user_conf_template.yml +51 -3
- eodag/rest/__init__.py +6 -0
- eodag/rest/cache.py +70 -0
- eodag/rest/config.py +68 -0
- eodag/rest/constants.py +27 -0
- eodag/rest/core.py +757 -0
- eodag/rest/server.py +397 -258
- eodag/rest/stac.py +438 -307
- eodag/rest/types/collections_search.py +44 -0
- eodag/rest/types/eodag_search.py +232 -43
- eodag/rest/types/{stac_queryables.py → queryables.py} +81 -43
- eodag/rest/types/stac_search.py +277 -0
- eodag/rest/utils/__init__.py +216 -0
- eodag/rest/utils/cql_evaluate.py +119 -0
- eodag/rest/utils/rfc3339.py +65 -0
- eodag/types/__init__.py +99 -9
- eodag/types/bbox.py +15 -14
- eodag/types/download_args.py +31 -0
- eodag/types/search_args.py +58 -7
- eodag/types/whoosh.py +81 -0
- eodag/utils/__init__.py +72 -9
- eodag/utils/constraints.py +37 -37
- eodag/utils/exceptions.py +23 -17
- eodag/utils/requests.py +138 -0
- eodag/utils/rest.py +104 -0
- eodag/utils/stac_reader.py +100 -16
- {eodag-2.12.1.dist-info → eodag-3.0.0b1.dist-info}/METADATA +64 -44
- eodag-3.0.0b1.dist-info/RECORD +109 -0
- {eodag-2.12.1.dist-info → eodag-3.0.0b1.dist-info}/WHEEL +1 -1
- {eodag-2.12.1.dist-info → eodag-3.0.0b1.dist-info}/entry_points.txt +6 -5
- eodag/plugins/apis/cds.py +0 -540
- eodag/rest/utils.py +0 -1133
- eodag-2.12.1.dist-info/RECORD +0 -94
- {eodag-2.12.1.dist-info → eodag-3.0.0b1.dist-info}/LICENSE +0 -0
- {eodag-2.12.1.dist-info → eodag-3.0.0b1.dist-info}/top_level.txt +0 -0
eodag/plugins/apis/usgs.py
CHANGED
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
|
+
import os
|
|
21
22
|
import shutil
|
|
22
23
|
import tarfile
|
|
23
24
|
import zipfile
|
|
24
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, cast
|
|
25
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union, cast
|
|
25
26
|
|
|
26
27
|
import requests
|
|
27
28
|
from jsonpath_ng.ext import parse
|
|
@@ -35,7 +36,7 @@ from eodag.api.product.metadata_mapping import (
|
|
|
35
36
|
properties_from_json,
|
|
36
37
|
)
|
|
37
38
|
from eodag.plugins.apis.base import Api
|
|
38
|
-
from eodag.plugins.
|
|
39
|
+
from eodag.plugins.search import PreparedSearch
|
|
39
40
|
from eodag.utils import (
|
|
40
41
|
DEFAULT_DOWNLOAD_TIMEOUT,
|
|
41
42
|
DEFAULT_DOWNLOAD_WAIT,
|
|
@@ -52,17 +53,21 @@ from eodag.utils.exceptions import (
|
|
|
52
53
|
NoMatchingProductType,
|
|
53
54
|
NotAvailableError,
|
|
54
55
|
RequestError,
|
|
56
|
+
ValidationError,
|
|
55
57
|
)
|
|
56
58
|
|
|
57
59
|
if TYPE_CHECKING:
|
|
60
|
+
from requests.auth import AuthBase
|
|
61
|
+
|
|
58
62
|
from eodag.api.search_result import SearchResult
|
|
59
63
|
from eodag.config import PluginConfig
|
|
60
|
-
from eodag.
|
|
64
|
+
from eodag.types.download_args import DownloadConf
|
|
65
|
+
from eodag.utils import DownloadedCallback, Unpack
|
|
61
66
|
|
|
62
67
|
logger = logging.getLogger("eodag.apis.usgs")
|
|
63
68
|
|
|
64
69
|
|
|
65
|
-
class UsgsApi(
|
|
70
|
+
class UsgsApi(Api):
|
|
66
71
|
"""A plugin that enables to query and download data on the USGS catalogues"""
|
|
67
72
|
|
|
68
73
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
@@ -71,7 +76,7 @@ class UsgsApi(Download, Api):
|
|
|
71
76
|
# Same method as in base.py, Search.__init__()
|
|
72
77
|
# Prepare the metadata mapping
|
|
73
78
|
# Do a shallow copy, the structure is flat enough for this to be sufficient
|
|
74
|
-
metas = DEFAULT_METADATA_MAPPING.copy()
|
|
79
|
+
metas: Dict[str, Any] = DEFAULT_METADATA_MAPPING.copy()
|
|
75
80
|
# Update the defaults with the mapping value. This will add any new key
|
|
76
81
|
# added by the provider mapping that is not in the default metadata.
|
|
77
82
|
metas.update(self.config.metadata_mapping)
|
|
@@ -98,25 +103,33 @@ class UsgsApi(Download, Api):
|
|
|
98
103
|
except USGSAuthExpiredError:
|
|
99
104
|
api.logout()
|
|
100
105
|
continue
|
|
101
|
-
except USGSError:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
except USGSError as e:
|
|
107
|
+
if i == 0:
|
|
108
|
+
# `.usgs` API file key might be obsolete
|
|
109
|
+
# Remove it and try again
|
|
110
|
+
os.remove(api.TMPFILE)
|
|
111
|
+
continue
|
|
112
|
+
raise AuthenticationError("Please check your USGS credentials.") from e
|
|
105
113
|
|
|
106
114
|
def query(
|
|
107
115
|
self,
|
|
108
|
-
|
|
109
|
-
items_per_page: int = DEFAULT_ITEMS_PER_PAGE,
|
|
110
|
-
page: int = DEFAULT_PAGE,
|
|
111
|
-
count: bool = True,
|
|
116
|
+
prep: PreparedSearch = PreparedSearch(),
|
|
112
117
|
**kwargs: Any,
|
|
113
118
|
) -> Tuple[List[EOProduct], Optional[int]]:
|
|
114
119
|
"""Search for data on USGS catalogues"""
|
|
120
|
+
page = prep.page if prep.page is not None else DEFAULT_PAGE
|
|
121
|
+
items_per_page = (
|
|
122
|
+
prep.items_per_page
|
|
123
|
+
if prep.items_per_page is not None
|
|
124
|
+
else DEFAULT_ITEMS_PER_PAGE
|
|
125
|
+
)
|
|
115
126
|
product_type = kwargs.get("productType")
|
|
116
127
|
if product_type is None:
|
|
117
128
|
raise NoMatchingProductType(
|
|
118
129
|
"Cannot search on USGS without productType specified"
|
|
119
130
|
)
|
|
131
|
+
if kwargs.get("sortBy"):
|
|
132
|
+
raise ValidationError("USGS does not support sorting feature")
|
|
120
133
|
|
|
121
134
|
self.authenticate()
|
|
122
135
|
|
|
@@ -230,11 +243,11 @@ class UsgsApi(Download, Api):
|
|
|
230
243
|
def download(
|
|
231
244
|
self,
|
|
232
245
|
product: EOProduct,
|
|
233
|
-
auth: Optional[
|
|
246
|
+
auth: Optional[Union[AuthBase, Dict[str, str]]] = None,
|
|
234
247
|
progress_callback: Optional[ProgressCallback] = None,
|
|
235
248
|
wait: int = DEFAULT_DOWNLOAD_WAIT,
|
|
236
249
|
timeout: int = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
237
|
-
**kwargs:
|
|
250
|
+
**kwargs: Unpack[DownloadConf],
|
|
238
251
|
) -> Optional[str]:
|
|
239
252
|
"""Download data from USGS catalogues"""
|
|
240
253
|
|
|
@@ -250,11 +263,11 @@ class UsgsApi(Download, Api):
|
|
|
250
263
|
product.product_type, self.config.products[GENERIC_PRODUCT_TYPE] # type: ignore
|
|
251
264
|
).get("outputs_extension", ".tar.gz"),
|
|
252
265
|
)
|
|
266
|
+
kwargs["outputs_extension"] = kwargs.get("outputs_extension", outputs_extension)
|
|
253
267
|
|
|
254
268
|
fs_path, record_filename = self._prepare_download(
|
|
255
269
|
product,
|
|
256
270
|
progress_callback=progress_callback,
|
|
257
|
-
outputs_extension=outputs_extension,
|
|
258
271
|
**kwargs,
|
|
259
272
|
)
|
|
260
273
|
if not fs_path or not record_filename:
|
|
@@ -308,13 +321,14 @@ class UsgsApi(Download, Api):
|
|
|
308
321
|
req_url = req_urls[0]
|
|
309
322
|
progress_callback.reset()
|
|
310
323
|
logger.debug(f"Downloading {req_url}")
|
|
324
|
+
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
311
325
|
|
|
312
326
|
@self._download_retry(product, wait, timeout)
|
|
313
327
|
def download_request(
|
|
314
328
|
product: EOProduct,
|
|
315
329
|
fs_path: str,
|
|
316
330
|
progress_callback: ProgressCallback,
|
|
317
|
-
**kwargs:
|
|
331
|
+
**kwargs: Unpack[DownloadConf],
|
|
318
332
|
) -> None:
|
|
319
333
|
try:
|
|
320
334
|
with requests.get(
|
|
@@ -322,6 +336,7 @@ class UsgsApi(Download, Api):
|
|
|
322
336
|
stream=True,
|
|
323
337
|
headers=USER_AGENT,
|
|
324
338
|
timeout=wait * 60,
|
|
339
|
+
verify=ssl_verify,
|
|
325
340
|
) as stream:
|
|
326
341
|
try:
|
|
327
342
|
stream.raise_for_status()
|
|
@@ -334,7 +349,9 @@ class UsgsApi(Download, Api):
|
|
|
334
349
|
error_message = str(e)
|
|
335
350
|
raise NotAvailableError(error_message)
|
|
336
351
|
else:
|
|
337
|
-
stream_size =
|
|
352
|
+
stream_size = (
|
|
353
|
+
int(stream.headers.get("content-length", 0)) or None
|
|
354
|
+
)
|
|
338
355
|
progress_callback.reset(total=stream_size)
|
|
339
356
|
with open(fs_path, "wb") as fhandle:
|
|
340
357
|
for chunk in stream.iter_content(chunk_size=64 * 1024):
|
|
@@ -357,13 +374,12 @@ class UsgsApi(Download, Api):
|
|
|
357
374
|
api.logout()
|
|
358
375
|
|
|
359
376
|
# Check downloaded file format
|
|
360
|
-
if (
|
|
361
|
-
outputs_extension == ".
|
|
362
|
-
):
|
|
377
|
+
if (
|
|
378
|
+
kwargs["outputs_extension"] == ".tar.gz" and tarfile.is_tarfile(fs_path)
|
|
379
|
+
) or (kwargs["outputs_extension"] == ".zip" and zipfile.is_zipfile(fs_path)):
|
|
363
380
|
product_path = self._finalize(
|
|
364
381
|
fs_path,
|
|
365
382
|
progress_callback=progress_callback,
|
|
366
|
-
outputs_extension=outputs_extension,
|
|
367
383
|
**kwargs,
|
|
368
384
|
)
|
|
369
385
|
product.location = path_to_uri(product_path)
|
|
@@ -396,12 +412,12 @@ class UsgsApi(Download, Api):
|
|
|
396
412
|
def download_all(
|
|
397
413
|
self,
|
|
398
414
|
products: SearchResult,
|
|
399
|
-
auth: Optional[
|
|
415
|
+
auth: Optional[Union[AuthBase, Dict[str, str]]] = None,
|
|
400
416
|
downloaded_callback: Optional[DownloadedCallback] = None,
|
|
401
417
|
progress_callback: Optional[ProgressCallback] = None,
|
|
402
418
|
wait: int = DEFAULT_DOWNLOAD_WAIT,
|
|
403
419
|
timeout: int = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
404
|
-
**kwargs:
|
|
420
|
+
**kwargs: Unpack[DownloadConf],
|
|
405
421
|
) -> List[str]:
|
|
406
422
|
"""
|
|
407
423
|
Download all using parent (base plugin) method
|
|
@@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Dict
|
|
|
22
22
|
from eodag.plugins.authentication.base import Authentication
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
|
-
from
|
|
25
|
+
from mypy_boto3_s3.client import S3Client
|
|
26
26
|
|
|
27
27
|
from eodag.config import PluginConfig
|
|
28
28
|
|
|
@@ -39,7 +39,7 @@ class AwsAuth(Authentication):
|
|
|
39
39
|
will be skipped if AWS credentials are filled in eodag conf
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
s3_client:
|
|
42
|
+
s3_client: S3Client
|
|
43
43
|
|
|
44
44
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
45
45
|
super(AwsAuth, self).__init__(provider, config)
|
|
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING, Dict
|
|
|
22
22
|
from requests.auth import AuthBase
|
|
23
23
|
|
|
24
24
|
from eodag.plugins.authentication import Authentication
|
|
25
|
+
from eodag.utils.exceptions import MisconfiguredError
|
|
25
26
|
|
|
26
27
|
if TYPE_CHECKING:
|
|
27
28
|
from requests import PreparedRequest
|
|
@@ -58,16 +59,40 @@ class HTTPHeaderAuth(Authentication):
|
|
|
58
59
|
oh-my-another-user-input: YYY
|
|
59
60
|
|
|
60
61
|
Expect an undefined behaviour if you use empty braces in header value strings.
|
|
62
|
+
|
|
63
|
+
The plugin also accepts headers to be passed directly through credentials::
|
|
64
|
+
|
|
65
|
+
provider:
|
|
66
|
+
...
|
|
67
|
+
auth:
|
|
68
|
+
plugin: HTTPHeaderAuth
|
|
69
|
+
credentials:
|
|
70
|
+
Authorization: "Something XXX"
|
|
71
|
+
X-Special-Header: "Fixed value"
|
|
72
|
+
X-Another-Special-Header: "YYY"
|
|
73
|
+
...
|
|
74
|
+
...
|
|
61
75
|
"""
|
|
62
76
|
|
|
63
|
-
def authenticate(self) ->
|
|
77
|
+
def authenticate(self) -> HeaderAuth:
|
|
64
78
|
"""Authenticate"""
|
|
65
79
|
self.validate_config_credentials()
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
try:
|
|
81
|
+
headers = (
|
|
82
|
+
{
|
|
83
|
+
header: value.format(**self.config.credentials)
|
|
84
|
+
for header, value in self.config.headers.items()
|
|
85
|
+
}
|
|
86
|
+
if getattr(self.config, "headers", None)
|
|
87
|
+
else self.config.credentials
|
|
88
|
+
)
|
|
89
|
+
return HeaderAuth(headers)
|
|
90
|
+
except KeyError as e:
|
|
91
|
+
raise MisconfiguredError(
|
|
92
|
+
"The following credentials are missing for provider {}: {}".format(
|
|
93
|
+
self.provider, ", ".join(e.args)
|
|
94
|
+
)
|
|
95
|
+
)
|
|
71
96
|
|
|
72
97
|
|
|
73
98
|
class HeaderAuth(AuthBase):
|
|
@@ -18,15 +18,16 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
|
-
from
|
|
22
|
-
from typing import TYPE_CHECKING, Dict, Union
|
|
21
|
+
from typing import TYPE_CHECKING, Any, Dict
|
|
23
22
|
|
|
24
23
|
import requests
|
|
25
24
|
|
|
26
|
-
from eodag.plugins.authentication import
|
|
27
|
-
|
|
25
|
+
from eodag.plugins.authentication.openid_connect import (
|
|
26
|
+
CodeAuthorizedAuth,
|
|
27
|
+
OIDCRefreshTokenBase,
|
|
28
|
+
)
|
|
28
29
|
from eodag.utils import HTTP_REQ_TIMEOUT, USER_AGENT
|
|
29
|
-
from eodag.utils.exceptions import
|
|
30
|
+
from eodag.utils.exceptions import MisconfiguredError, TimeOutError
|
|
30
31
|
|
|
31
32
|
if TYPE_CHECKING:
|
|
32
33
|
from requests.auth import AuthBase
|
|
@@ -37,7 +38,7 @@ if TYPE_CHECKING:
|
|
|
37
38
|
logger = logging.getLogger("eodag.auth.keycloak")
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
class KeycloakOIDCPasswordAuth(
|
|
41
|
+
class KeycloakOIDCPasswordAuth(OIDCRefreshTokenBase):
|
|
41
42
|
"""Authentication plugin using Keycloak and OpenId Connect.
|
|
42
43
|
|
|
43
44
|
This plugin request a token and use it through a query-string or a header.
|
|
@@ -80,13 +81,9 @@ class KeycloakOIDCPasswordAuth(Authentication):
|
|
|
80
81
|
GRANT_TYPE = "password"
|
|
81
82
|
TOKEN_URL_TEMPLATE = "{auth_base_uri}/realms/{realm}/protocol/openid-connect/token"
|
|
82
83
|
REQUIRED_PARAMS = ["auth_base_uri", "client_id", "client_secret", "token_provision"]
|
|
83
|
-
# already retrieved token store, to be used if authenticate() fails (OTP use-case)
|
|
84
|
-
retrieved_token: str = ""
|
|
85
|
-
token_info: Dict[str, Union[str, datetime]] = {}
|
|
86
84
|
|
|
87
85
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
88
86
|
super(KeycloakOIDCPasswordAuth, self).__init__(provider, config)
|
|
89
|
-
self.session = requests.Session()
|
|
90
87
|
|
|
91
88
|
def validate_config_credentials(self) -> None:
|
|
92
89
|
"""Validate configured credentials"""
|
|
@@ -105,51 +102,14 @@ class KeycloakOIDCPasswordAuth(Authentication):
|
|
|
105
102
|
"""
|
|
106
103
|
self.validate_config_credentials()
|
|
107
104
|
access_token = self._get_access_token()
|
|
108
|
-
self.
|
|
105
|
+
self.token_info["access_token"] = access_token
|
|
109
106
|
return CodeAuthorizedAuth(
|
|
110
|
-
self.
|
|
107
|
+
self.token_info["access_token"],
|
|
111
108
|
self.config.token_provision,
|
|
112
109
|
key=getattr(self.config, "token_qs_key", None),
|
|
113
110
|
)
|
|
114
111
|
|
|
115
|
-
def
|
|
116
|
-
current_time = datetime.now()
|
|
117
|
-
if (
|
|
118
|
-
not self.token_info
|
|
119
|
-
or (
|
|
120
|
-
"refresh_token" in self.token_info
|
|
121
|
-
and (current_time - self.token_info["token_time"]).seconds
|
|
122
|
-
>= self.token_info["refresh_token_expiration"]
|
|
123
|
-
)
|
|
124
|
-
or (
|
|
125
|
-
"refresh_token" not in self.token_info
|
|
126
|
-
and (current_time - self.token_info["token_time"]).seconds
|
|
127
|
-
>= self.token_info["access_token_expiration"]
|
|
128
|
-
)
|
|
129
|
-
):
|
|
130
|
-
# Request new TOKEN on first attempt or if token expired
|
|
131
|
-
res = self._request_new_token()
|
|
132
|
-
self.token_info["token_time"] = current_time
|
|
133
|
-
self.token_info["access_token_expiration"] = res["expires_in"]
|
|
134
|
-
if "refresh_token" in res:
|
|
135
|
-
self.token_info["refresh_time"] = current_time
|
|
136
|
-
self.token_info["refresh_token_expiration"] = res["refresh_expires_in"]
|
|
137
|
-
self.token_info["refresh_token"] = res["refresh_token"]
|
|
138
|
-
return res["access_token"]
|
|
139
|
-
elif (
|
|
140
|
-
"refresh_token" in self.token_info
|
|
141
|
-
and (current_time - self.token_info["refresh_time"]).seconds
|
|
142
|
-
>= self.token_info["access_token_expiration"]
|
|
143
|
-
):
|
|
144
|
-
# Use refresh token
|
|
145
|
-
res = self._get_token_with_refresh_token()
|
|
146
|
-
self.token_info["refresh_token"] = res["refresh_token"]
|
|
147
|
-
self.token_info["refresh_time"] = current_time
|
|
148
|
-
return res["access_token"]
|
|
149
|
-
logger.debug("using already retrieved access token")
|
|
150
|
-
return self.retrieved_token
|
|
151
|
-
|
|
152
|
-
def _request_new_token(self) -> Dict[str, str]:
|
|
112
|
+
def _request_new_token(self) -> Dict[str, Any]:
|
|
153
113
|
logger.debug("fetching new access token")
|
|
154
114
|
req_data = {
|
|
155
115
|
"client_id": self.config.client_id,
|
|
@@ -168,41 +128,10 @@ class KeycloakOIDCPasswordAuth(Authentication):
|
|
|
168
128
|
timeout=HTTP_REQ_TIMEOUT,
|
|
169
129
|
)
|
|
170
130
|
response.raise_for_status()
|
|
131
|
+
except requests.exceptions.Timeout as exc:
|
|
132
|
+
raise TimeOutError(exc, timeout=HTTP_REQ_TIMEOUT) from exc
|
|
171
133
|
except requests.RequestException as e:
|
|
172
|
-
|
|
173
|
-
# try using already retrieved token if authenticate() fails (OTP use-case)
|
|
174
|
-
if "access_token_expiration" in self.token_info:
|
|
175
|
-
return {
|
|
176
|
-
"access_token": self.retrieved_token,
|
|
177
|
-
"expires_in": self.token_info["access_token_expiration"],
|
|
178
|
-
}
|
|
179
|
-
else:
|
|
180
|
-
return {"access_token": self.retrieved_token, "expires_in": 0}
|
|
181
|
-
response_text = getattr(e.response, "text", "").strip()
|
|
182
|
-
# check if error is identified as auth_error in provider conf
|
|
183
|
-
auth_errors = getattr(self.config, "auth_error_code", [None])
|
|
184
|
-
if not isinstance(auth_errors, list):
|
|
185
|
-
auth_errors = [auth_errors]
|
|
186
|
-
if (
|
|
187
|
-
hasattr(e.response, "status_code")
|
|
188
|
-
and e.response.status_code in auth_errors
|
|
189
|
-
):
|
|
190
|
-
raise AuthenticationError(
|
|
191
|
-
"HTTP Error %s returned, %s\nPlease check your credentials for %s"
|
|
192
|
-
% (e.response.status_code, response_text, self.provider)
|
|
193
|
-
)
|
|
194
|
-
# other error
|
|
195
|
-
else:
|
|
196
|
-
import traceback as tb
|
|
197
|
-
|
|
198
|
-
logger.error(
|
|
199
|
-
f"Provider {self.provider} returned {e.response.status_code}: {response_text}"
|
|
200
|
-
)
|
|
201
|
-
raise AuthenticationError(
|
|
202
|
-
"Something went wrong while trying to get access token:\n{}".format(
|
|
203
|
-
tb.format_exc()
|
|
204
|
-
)
|
|
205
|
-
)
|
|
134
|
+
return self._request_new_token_error(e)
|
|
206
135
|
return response.json()
|
|
207
136
|
|
|
208
137
|
def _get_token_with_refresh_token(self) -> Dict[str, str]:
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from typing import TYPE_CHECKING, Dict
|
|
20
|
+
from typing import TYPE_CHECKING, Dict, Optional
|
|
21
21
|
|
|
22
22
|
from eodag.plugins.authentication.base import Authentication
|
|
23
23
|
|
|
@@ -30,8 +30,8 @@ class OAuth(Authentication):
|
|
|
30
30
|
|
|
31
31
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
32
32
|
super(OAuth, self).__init__(provider, config)
|
|
33
|
-
self.access_key = None
|
|
34
|
-
self.secret_key = None
|
|
33
|
+
self.access_key: Optional[str] = None
|
|
34
|
+
self.secret_key: Optional[str] = None
|
|
35
35
|
|
|
36
36
|
def authenticate(self) -> Dict[str, str]:
|
|
37
37
|
"""Authenticate"""
|