eodag 3.0.0b3__py3-none-any.whl → 3.1.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 +292 -198
- eodag/api/product/_assets.py +6 -6
- eodag/api/product/_product.py +18 -18
- eodag/api/product/metadata_mapping.py +51 -14
- eodag/api/search_result.py +29 -3
- eodag/cli.py +57 -20
- eodag/config.py +413 -117
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +49 -16
- eodag/plugins/apis/usgs.py +30 -7
- 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 +93 -15
- 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 +6 -6
- eodag/plugins/download/aws.py +50 -34
- eodag/plugins/download/base.py +41 -50
- eodag/plugins/download/creodias_s3.py +40 -2
- eodag/plugins/download/http.py +221 -195
- eodag/plugins/download/s3rest.py +25 -25
- eodag/plugins/manager.py +168 -23
- eodag/plugins/search/base.py +106 -39
- eodag/plugins/search/build_search_result.py +1065 -324
- eodag/plugins/search/cop_marine.py +112 -29
- eodag/plugins/search/creodias_s3.py +45 -24
- eodag/plugins/search/csw.py +41 -1
- eodag/plugins/search/data_request_search.py +109 -9
- eodag/plugins/search/qssearch.py +549 -257
- eodag/plugins/search/static_stac_search.py +20 -21
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +577 -87
- eodag/resources/providers.yml +1619 -2776
- 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 +138 -98
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +55 -329
- eodag/rest/stac.py +93 -544
- eodag/rest/types/eodag_search.py +19 -8
- eodag/rest/types/queryables.py +6 -8
- eodag/rest/types/stac_search.py +11 -2
- eodag/rest/utils/__init__.py +3 -0
- eodag/types/__init__.py +71 -18
- eodag/types/download_args.py +3 -3
- eodag/types/queryables.py +180 -73
- eodag/types/search_args.py +3 -3
- eodag/types/whoosh.py +126 -0
- eodag/utils/__init__.py +147 -66
- eodag/utils/exceptions.py +47 -26
- eodag/utils/logging.py +37 -77
- eodag/utils/repr.py +65 -6
- eodag/utils/requests.py +11 -13
- eodag/utils/stac_reader.py +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/METADATA +80 -81
- eodag-3.1.0b1.dist-info/RECORD +108 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/entry_points.txt +4 -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.0b1.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0b1.dist-info}/top_level.txt +0 -0
eodag/api/product/_assets.py
CHANGED
|
@@ -98,12 +98,12 @@ class AssetsDict(UserDict):
|
|
|
98
98
|
<details><summary style='color: grey;'>
|
|
99
99
|
<span style='color: black'>'{k}'</span>: 
|
|
100
100
|
{{
|
|
101
|
-
{"'roles': '<span style='color: black'>"+str(v['roles'])+"</span>', "
|
|
102
|
-
|
|
103
|
-
{"'type': '"+str(v['type'])+"', "
|
|
104
|
-
|
|
105
|
-
{"'title': '<span style='color: black'>"+str(v['title'])+"</span>', "
|
|
106
|
-
|
|
101
|
+
{"'roles': '<span style='color: black'>" + str(v['roles']) + "</span>', "
|
|
102
|
+
if v.get("roles") else ""}
|
|
103
|
+
{"'type': '" + str(v['type']) + "', "
|
|
104
|
+
if v.get("type") else ""}
|
|
105
|
+
{"'title': '<span style='color: black'>" + str(v['title']) + "</span>', "
|
|
106
|
+
if v.get("title") else ""}
|
|
107
107
|
...
|
|
108
108
|
}}
|
|
109
109
|
</summary>
|
eodag/api/product/_product.py
CHANGED
|
@@ -116,6 +116,7 @@ class EOProduct:
|
|
|
116
116
|
properties: Dict[str, Any]
|
|
117
117
|
product_type: Optional[str]
|
|
118
118
|
location: str
|
|
119
|
+
filename: str
|
|
119
120
|
remote_location: str
|
|
120
121
|
search_kwargs: Any
|
|
121
122
|
geometry: BaseGeometry
|
|
@@ -281,8 +282,8 @@ class EOProduct:
|
|
|
281
282
|
def download(
|
|
282
283
|
self,
|
|
283
284
|
progress_callback: Optional[ProgressCallback] = None,
|
|
284
|
-
wait:
|
|
285
|
-
timeout:
|
|
285
|
+
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
286
|
+
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
286
287
|
**kwargs: Unpack[DownloadConf],
|
|
287
288
|
) -> str:
|
|
288
289
|
"""Download the EO product using the provided download plugin and the
|
|
@@ -525,22 +526,21 @@ class EOProduct:
|
|
|
525
526
|
<tr style='background-color: transparent;'>
|
|
526
527
|
<td style='text-align: left; vertical-align: top;'>
|
|
527
528
|
{dict_to_html_table({
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
<details><summary style='color: grey; margin-top: 10px;'>properties: ({
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
<details><summary style='color: grey; margin-top: 10px;'>assets: ({
|
|
542
|
-
|
|
543
|
-
})</summary>{self.assets._repr_html_(embeded=True)}</details>
|
|
529
|
+
"provider": self.provider,
|
|
530
|
+
"product_type": self.product_type,
|
|
531
|
+
"properties["id"]": self.properties.get('id', None),
|
|
532
|
+
"properties["startTimeFromAscendingNode"]": self.properties.get(
|
|
533
|
+
'startTimeFromAscendingNode', None
|
|
534
|
+
),
|
|
535
|
+
"properties["completionTimeFromAscendingNode"]": self.properties.get(
|
|
536
|
+
'completionTimeFromAscendingNode', None
|
|
537
|
+
),
|
|
538
|
+
}, brackets=False)}
|
|
539
|
+
<details><summary style='color: grey; margin-top: 10px;'>properties: ({len(
|
|
540
|
+
self.properties)})</summary>{
|
|
541
|
+
dict_to_html_table(self.properties, depth=1)}</details>
|
|
542
|
+
<details><summary style='color: grey; margin-top: 10px;'>assets: ({len(
|
|
543
|
+
self.assets)})</summary>{self.assets._repr_html_(embeded=True)}</details>
|
|
544
544
|
</td>
|
|
545
545
|
<td {geom_style} title='geometry'>geometry<br />{self.geometry._repr_svg_()}</td>
|
|
546
546
|
<td {thumbnail_style} title='properties["thumbnail"]'>{thumbnail_html}</td>
|
|
@@ -40,7 +40,9 @@ from typing import (
|
|
|
40
40
|
import geojson
|
|
41
41
|
import orjson
|
|
42
42
|
import pyproj
|
|
43
|
+
import shapely
|
|
43
44
|
from dateutil.parser import isoparse
|
|
45
|
+
from dateutil.relativedelta import relativedelta
|
|
44
46
|
from dateutil.tz import UTC, tzutc
|
|
45
47
|
from jsonpath_ng.jsonpath import Child, JSONPath
|
|
46
48
|
from lxml import etree
|
|
@@ -152,7 +154,7 @@ def get_search_param(map_value: List[str]) -> str:
|
|
|
152
154
|
|
|
153
155
|
|
|
154
156
|
def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
155
|
-
"""Format a string of form {<field_name>#<conversion_function>}
|
|
157
|
+
"""Format a string of form ``{<field_name>#<conversion_function>}``
|
|
156
158
|
|
|
157
159
|
The currently understood converters are:
|
|
158
160
|
- ``datetime_to_timestamp_milliseconds``: converts a utc date string to a timestamp in
|
|
@@ -178,6 +180,8 @@ def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
|
178
180
|
- ``recursive_sub_str``: recursively substitue in the structure (e.g. dict)
|
|
179
181
|
values matching a regex
|
|
180
182
|
- ``slice_str``: slice a string (equivalent to s[start, end, step])
|
|
183
|
+
- ``to_lower``: Convert a string to lowercase
|
|
184
|
+
- ``to_upper``: Convert a string to uppercase
|
|
181
185
|
- ``fake_l2a_title_from_l1c``: used to generate SAFE format metadata for data from AWS
|
|
182
186
|
- ``s2msil2a_title_to_aws_productinfo``: used to generate SAFE format metadata for data from AWS
|
|
183
187
|
- ``split_cop_dem_id``: get the bbox by splitting the product id
|
|
@@ -362,6 +366,8 @@ def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
|
362
366
|
|
|
363
367
|
@staticmethod
|
|
364
368
|
def convert_to_nwse_bounds(input_geom: BaseGeometry) -> List[float]:
|
|
369
|
+
if isinstance(input_geom, str):
|
|
370
|
+
input_geom = shapely.wkt.loads(input_geom)
|
|
365
371
|
return list(input_geom.bounds[-1:] + input_geom.bounds[:-1])
|
|
366
372
|
|
|
367
373
|
@staticmethod
|
|
@@ -557,6 +563,16 @@ def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
|
557
563
|
]
|
|
558
564
|
return string[cmin:cmax:cstep]
|
|
559
565
|
|
|
566
|
+
@staticmethod
|
|
567
|
+
def convert_to_lower(string: str) -> str:
|
|
568
|
+
"""Convert a string to lowercase."""
|
|
569
|
+
return string.lower()
|
|
570
|
+
|
|
571
|
+
@staticmethod
|
|
572
|
+
def convert_to_upper(string: str) -> str:
|
|
573
|
+
"""Convert a string to uppercase."""
|
|
574
|
+
return string.upper()
|
|
575
|
+
|
|
560
576
|
@staticmethod
|
|
561
577
|
def convert_fake_l2a_title_from_l1c(string: str) -> str:
|
|
562
578
|
id_regex = re.compile(
|
|
@@ -831,9 +847,9 @@ def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
|
831
847
|
def convert_get_hydrological_year(date: str):
|
|
832
848
|
utc_date = MetadataFormatter.convert_to_iso_utc_datetime(date)
|
|
833
849
|
date_object = datetime.strptime(utc_date, "%Y-%m-%dT%H:%M:%S.%fZ")
|
|
834
|
-
date_object_second_year = date_object +
|
|
850
|
+
date_object_second_year = date_object + relativedelta(years=1)
|
|
835
851
|
return [
|
|
836
|
-
f
|
|
852
|
+
f"{date_object.strftime('%Y')}_{date_object_second_year.strftime('%y')}"
|
|
837
853
|
]
|
|
838
854
|
|
|
839
855
|
@staticmethod
|
|
@@ -901,10 +917,8 @@ def format_metadata(search_param: str, *args: Any, **kwargs: Any) -> str:
|
|
|
901
917
|
return assets_dict
|
|
902
918
|
|
|
903
919
|
# if stac extension colon separator `:` is in search params, parse it to prevent issues with vformat
|
|
904
|
-
if re.search(r"{[
|
|
905
|
-
search_param = re.sub(
|
|
906
|
-
r"{([a-zA-Z0-9_-]*):([a-zA-Z0-9_-]*)}", r"{\1_COLON_\2}", search_param
|
|
907
|
-
)
|
|
920
|
+
if re.search(r"{[\w-]*:[\w#-]*}", search_param):
|
|
921
|
+
search_param = re.sub(r"{([\w-]*):([\w#-]*)}", r"{\1_COLON_\2}", search_param)
|
|
908
922
|
kwargs = {k.replace(":", "_COLON_"): v for k, v in kwargs.items()}
|
|
909
923
|
|
|
910
924
|
return MetadataFormatter().vformat(search_param, args, kwargs)
|
|
@@ -974,10 +988,24 @@ def properties_from_json(
|
|
|
974
988
|
if re.search(r"({[^{}:]+})+", conversion_or_none):
|
|
975
989
|
conversion_or_none = conversion_or_none.format(**properties)
|
|
976
990
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
991
|
+
if extracted_value == NOT_AVAILABLE:
|
|
992
|
+
# try if value can be formatted even if it is not available
|
|
993
|
+
try:
|
|
994
|
+
properties[metadata] = format_metadata(
|
|
995
|
+
"{%s%s%s}" % (metadata, SEP, conversion_or_none),
|
|
996
|
+
**{metadata: extracted_value},
|
|
997
|
+
)
|
|
998
|
+
except ValueError:
|
|
999
|
+
logger.debug(
|
|
1000
|
+
f"{metadata}: {extracted_value} could not be formatted with {conversion_or_none}"
|
|
1001
|
+
)
|
|
1002
|
+
continue
|
|
1003
|
+
else:
|
|
1004
|
+
# in this case formatting should work, otherwise something is wrong in the mapping
|
|
1005
|
+
properties[metadata] = format_metadata(
|
|
1006
|
+
"{%s%s%s}" % (metadata, SEP, conversion_or_none),
|
|
1007
|
+
**{metadata: extracted_value},
|
|
1008
|
+
)
|
|
981
1009
|
# properties as python objects when possible (format_metadata returns only strings)
|
|
982
1010
|
try:
|
|
983
1011
|
properties[metadata] = ast.literal_eval(properties[metadata])
|
|
@@ -1208,7 +1236,7 @@ def mtd_cfg_as_conversion_and_querypath(
|
|
|
1208
1236
|
dest_dict: Dict[str, Any] = {},
|
|
1209
1237
|
result_type: str = "json",
|
|
1210
1238
|
) -> Dict[str, Any]:
|
|
1211
|
-
"""Metadata configuration dictionary to querypath with conversion
|
|
1239
|
+
"""Metadata configuration dictionary to querypath with conversion dictionary
|
|
1212
1240
|
Transform every src_dict value from jsonpath_str to tuple `(conversion, jsonpath_object)`
|
|
1213
1241
|
or from xpath_str to tuple `(conversion, xpath_str)`
|
|
1214
1242
|
|
|
@@ -1461,7 +1489,15 @@ def get_queryable_from_provider(
|
|
|
1461
1489
|
:param metadata_mapping: metadata-mapping configuration
|
|
1462
1490
|
:returns: EODAG configured queryable parameter or None
|
|
1463
1491
|
"""
|
|
1464
|
-
pattern = rf"\
|
|
1492
|
+
pattern = rf"\"{provider_queryable}\""
|
|
1493
|
+
# if 1:1 mapping exists privilege this one instead of other mapping
|
|
1494
|
+
# e.g. provider queryable = year -> use year and not date in which year also appears
|
|
1495
|
+
mapping_values = [
|
|
1496
|
+
v[0] if isinstance(v, list) else "" for v in metadata_mapping.values()
|
|
1497
|
+
]
|
|
1498
|
+
if provider_queryable in mapping_values:
|
|
1499
|
+
ind = mapping_values.index(provider_queryable)
|
|
1500
|
+
return Queryables.get_queryable_from_alias(list(metadata_mapping.keys())[ind])
|
|
1465
1501
|
for param, param_conf in metadata_mapping.items():
|
|
1466
1502
|
if isinstance(param_conf, list) and re.search(pattern, param_conf[0]):
|
|
1467
1503
|
return Queryables.get_queryable_from_alias(param)
|
|
@@ -1489,7 +1525,8 @@ def get_provider_queryable_key(
|
|
|
1489
1525
|
provider_queryables: Dict[str, Any],
|
|
1490
1526
|
metadata_mapping: Dict[str, Union[List[Any], str]],
|
|
1491
1527
|
) -> str:
|
|
1492
|
-
"""
|
|
1528
|
+
"""Finds the provider queryable corresponding to the given eodag key based on the metadata mapping
|
|
1529
|
+
|
|
1493
1530
|
:param eodag_key: key in eodag
|
|
1494
1531
|
:param provider_queryables: queryables returned from the provider
|
|
1495
1532
|
:param metadata_mapping: metadata mapping from which the keys are retrieved
|
eodag/api/search_result.py
CHANGED
|
@@ -18,9 +18,20 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
from collections import UserList
|
|
21
|
-
from typing import
|
|
21
|
+
from typing import (
|
|
22
|
+
TYPE_CHECKING,
|
|
23
|
+
Annotated,
|
|
24
|
+
Any,
|
|
25
|
+
Dict,
|
|
26
|
+
Iterable,
|
|
27
|
+
List,
|
|
28
|
+
Optional,
|
|
29
|
+
Tuple,
|
|
30
|
+
Union,
|
|
31
|
+
)
|
|
22
32
|
|
|
23
33
|
from shapely.geometry import GeometryCollection, shape
|
|
34
|
+
from typing_extensions import Doc
|
|
24
35
|
|
|
25
36
|
from eodag.api.product import EOProduct
|
|
26
37
|
from eodag.plugins.crunch.filter_date import FilterDate
|
|
@@ -47,11 +58,19 @@ class SearchResult(UserList):
|
|
|
47
58
|
|
|
48
59
|
data: List[EOProduct]
|
|
49
60
|
|
|
61
|
+
errors: Annotated[
|
|
62
|
+
List[Tuple[str, Exception]], Doc("Tuple of provider name, exception")
|
|
63
|
+
]
|
|
64
|
+
|
|
50
65
|
def __init__(
|
|
51
|
-
self,
|
|
66
|
+
self,
|
|
67
|
+
products: List[EOProduct],
|
|
68
|
+
number_matched: Optional[int] = None,
|
|
69
|
+
errors: List[Tuple[str, Exception]] = [],
|
|
52
70
|
) -> None:
|
|
53
|
-
super(
|
|
71
|
+
super().__init__(products)
|
|
54
72
|
self.number_matched = number_matched
|
|
73
|
+
self.errors = errors
|
|
55
74
|
|
|
56
75
|
def crunch(self, cruncher: Crunch, **search_params: Any) -> SearchResult:
|
|
57
76
|
"""Do some crunching with the underlying EO products.
|
|
@@ -197,6 +216,13 @@ class SearchResult(UserList):
|
|
|
197
216
|
+ "</table>"
|
|
198
217
|
)
|
|
199
218
|
|
|
219
|
+
def extend(self, other: Iterable) -> None:
|
|
220
|
+
"""override extend method to include errors"""
|
|
221
|
+
if isinstance(other, SearchResult):
|
|
222
|
+
self.errors.extend(other.errors)
|
|
223
|
+
|
|
224
|
+
return super().extend(other)
|
|
225
|
+
|
|
200
226
|
|
|
201
227
|
class RawSearchResult(UserList):
|
|
202
228
|
"""An object representing a collection of raw/unparsed search results obtained from a provider.
|
eodag/cli.py
CHANGED
|
@@ -39,6 +39,7 @@ Commands:
|
|
|
39
39
|
|
|
40
40
|
noqa: D103
|
|
41
41
|
"""
|
|
42
|
+
|
|
42
43
|
from __future__ import annotations
|
|
43
44
|
|
|
44
45
|
import json
|
|
@@ -56,6 +57,11 @@ from eodag.utils import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE, parse_qs
|
|
|
56
57
|
from eodag.utils.exceptions import NoMatchingProductType, UnsupportedProvider
|
|
57
58
|
from eodag.utils.logging import setup_logging
|
|
58
59
|
|
|
60
|
+
try:
|
|
61
|
+
from eodag.rest.utils import LIVENESS_PROBE_PATH
|
|
62
|
+
except ImportError:
|
|
63
|
+
pass
|
|
64
|
+
|
|
59
65
|
if TYPE_CHECKING:
|
|
60
66
|
from click import Context
|
|
61
67
|
|
|
@@ -69,6 +75,18 @@ CRUNCHERS = [
|
|
|
69
75
|
]
|
|
70
76
|
|
|
71
77
|
|
|
78
|
+
class LivenessFilter:
|
|
79
|
+
"""
|
|
80
|
+
Filter out requests to the liveness probe endpoint
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
def filter(self, record):
|
|
84
|
+
"""
|
|
85
|
+
Filter method required by the Python logging API.
|
|
86
|
+
"""
|
|
87
|
+
return LIVENESS_PROBE_PATH not in record.getMessage()
|
|
88
|
+
|
|
89
|
+
|
|
72
90
|
class MutuallyExclusiveOption(click.Option):
|
|
73
91
|
"""Mutually Exclusive Options for Click
|
|
74
92
|
from https://gist.github.com/jacobtolar/fb80d5552a9a9dfc32b12a829fa21c0c
|
|
@@ -553,12 +571,13 @@ def download(ctx: Context, **kwargs: Any) -> None:
|
|
|
553
571
|
|
|
554
572
|
for idx, product in enumerate(search_results):
|
|
555
573
|
if product.downloader is None:
|
|
574
|
+
downloader = satim_api._plugins_manager.get_download_plugin(product)
|
|
556
575
|
auth = product.downloader_auth
|
|
557
576
|
if auth is None:
|
|
558
|
-
auth = satim_api._plugins_manager.get_auth_plugin(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
)
|
|
577
|
+
auth = satim_api._plugins_manager.get_auth_plugin(
|
|
578
|
+
downloader, product
|
|
579
|
+
)
|
|
580
|
+
search_results[idx].register_downloader(downloader, auth)
|
|
562
581
|
|
|
563
582
|
downloaded_file = product.get_quicklook()
|
|
564
583
|
if not downloaded_file:
|
|
@@ -573,12 +592,13 @@ def download(ctx: Context, **kwargs: Any) -> None:
|
|
|
573
592
|
# register downloader
|
|
574
593
|
for idx, product in enumerate(search_results):
|
|
575
594
|
if product.downloader is None:
|
|
595
|
+
downloader = satim_api._plugins_manager.get_download_plugin(product)
|
|
576
596
|
auth = product.downloader_auth
|
|
577
597
|
if auth is None:
|
|
578
|
-
auth = satim_api._plugins_manager.get_auth_plugin(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
)
|
|
598
|
+
auth = satim_api._plugins_manager.get_auth_plugin(
|
|
599
|
+
downloader, product
|
|
600
|
+
)
|
|
601
|
+
search_results[idx].register_downloader(downloader, auth)
|
|
582
602
|
|
|
583
603
|
downloaded_files = satim_api.download_all(search_results)
|
|
584
604
|
if downloaded_files and len(downloaded_files) > 0:
|
|
@@ -676,7 +696,9 @@ def serve_rest(
|
|
|
676
696
|
try:
|
|
677
697
|
pid = os.fork()
|
|
678
698
|
except OSError as e:
|
|
679
|
-
raise Exception(
|
|
699
|
+
raise Exception(
|
|
700
|
+
"%s [%d]" % (e.strerror, e.errno) if e.errno is not None else e.strerror
|
|
701
|
+
)
|
|
680
702
|
|
|
681
703
|
if pid == 0:
|
|
682
704
|
os.setsid()
|
|
@@ -684,19 +706,34 @@ def serve_rest(
|
|
|
684
706
|
else:
|
|
685
707
|
sys.exit(0)
|
|
686
708
|
else:
|
|
709
|
+
import logging
|
|
710
|
+
|
|
687
711
|
logging_config = uvicorn.config.LOGGING_CONFIG
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
712
|
+
uvicorn_fmt = "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s"
|
|
713
|
+
logging_config["filters"] = {"liveness": {"()": LivenessFilter}}
|
|
714
|
+
logging_config["formatters"]["access"]["fmt"] = uvicorn_fmt
|
|
715
|
+
logging_config["formatters"]["default"]["fmt"] = uvicorn_fmt
|
|
716
|
+
logging_config["loggers"]["uvicorn.access"]["filters"] = ["liveness"]
|
|
717
|
+
|
|
718
|
+
eodag_formatter = logging.Formatter(
|
|
719
|
+
"%(asctime)-15s %(name)-32s [%(levelname)-8s] (tid=%(thread)d) %(message)s"
|
|
720
|
+
)
|
|
721
|
+
logging.getLogger("eodag").handlers[0].setFormatter(eodag_formatter)
|
|
722
|
+
|
|
723
|
+
if ctx.obj["verbosity"] <= 1:
|
|
724
|
+
logging_config["handlers"]["null"] = {
|
|
725
|
+
"level": "DEBUG",
|
|
726
|
+
"class": "logging.NullHandler",
|
|
699
727
|
}
|
|
728
|
+
logging_config["loggers"]["uvicorn"]["handlers"] = ["null"]
|
|
729
|
+
logging_config["loggers"]["uvicorn.error"]["handlers"] = ["null"]
|
|
730
|
+
logging_config["loggers"]["uvicorn.access"]["handlers"] = ["null"]
|
|
731
|
+
else:
|
|
732
|
+
log_level = "INFO" if ctx.obj["verbosity"] == 2 else "DEBUG"
|
|
733
|
+
logging_config["loggers"]["uvicorn"]["level"] = log_level
|
|
734
|
+
logging_config["loggers"]["uvicorn.error"]["level"] = log_level
|
|
735
|
+
logging_config["loggers"]["uvicorn.access"]["level"] = log_level
|
|
736
|
+
|
|
700
737
|
uvicorn.run(
|
|
701
738
|
"eodag.rest.server:app",
|
|
702
739
|
host=bind_host,
|