eodag 3.5.1__py3-none-any.whl → 3.7.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 +29 -14
- eodag/api/product/__init__.py +30 -0
- eodag/api/product/metadata_mapping.py +20 -3
- eodag/api/search_result.py +155 -1
- eodag/cli.py +60 -44
- eodag/config.py +7 -6
- eodag/plugins/authentication/openid_connect.py +1 -2
- eodag/plugins/download/aws.py +145 -178
- eodag/plugins/download/base.py +18 -5
- eodag/plugins/download/creodias_s3.py +10 -5
- eodag/plugins/download/http.py +14 -6
- eodag/plugins/download/s3rest.py +1 -2
- eodag/plugins/manager.py +1 -1
- eodag/plugins/search/base.py +34 -4
- eodag/plugins/search/build_search_result.py +11 -6
- eodag/plugins/search/cop_marine.py +2 -0
- eodag/plugins/search/qssearch.py +48 -26
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +100 -153
- eodag/resources/providers.yml +58 -325
- eodag/resources/stac.yml +1 -2
- eodag/resources/user_conf_template.yml +0 -11
- eodag/rest/core.py +5 -9
- eodag/rest/server.py +9 -7
- eodag/utils/__init__.py +48 -27
- eodag/utils/exceptions.py +4 -0
- eodag/utils/s3.py +605 -65
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/METADATA +10 -10
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/RECORD +33 -33
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/WHEEL +0 -0
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/entry_points.txt +0 -0
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/licenses/LICENSE +0 -0
- {eodag-3.5.1.dist-info → eodag-3.7.0.dist-info}/top_level.txt +0 -0
eodag/rest/server.py
CHANGED
|
@@ -383,24 +383,26 @@ async def list_collection_queryables(
|
|
|
383
383
|
:returns: A json object containing the list of available queryable properties for the specified collection.
|
|
384
384
|
"""
|
|
385
385
|
logger.info(f"{request.method} {request.state.url}")
|
|
386
|
-
# split by `,` to handle list of parameters
|
|
387
|
-
additional_params = {k: v.split(",") for k, v in dict(request.query_params).items()}
|
|
388
|
-
provider = additional_params.pop("provider", None)
|
|
389
386
|
|
|
390
|
-
|
|
387
|
+
params: dict[str, list[Any]] = {}
|
|
388
|
+
for k, v in request.query_params.multi_items():
|
|
389
|
+
params.setdefault(k, []).append(v)
|
|
390
|
+
|
|
391
|
+
provider = params.pop("provider", [None])[0]
|
|
392
|
+
datetime = params.pop("datetime", [None])[0]
|
|
391
393
|
|
|
392
394
|
queryables = await get_queryables(
|
|
393
395
|
request,
|
|
394
396
|
QueryablesGetParams.model_validate(
|
|
395
397
|
{
|
|
396
|
-
**
|
|
398
|
+
**params,
|
|
397
399
|
**{
|
|
398
400
|
"collection": collection_id,
|
|
399
|
-
"datetime": datetime
|
|
401
|
+
"datetime": datetime,
|
|
400
402
|
},
|
|
401
403
|
}
|
|
402
404
|
),
|
|
403
|
-
provider=provider
|
|
405
|
+
provider=provider,
|
|
404
406
|
)
|
|
405
407
|
|
|
406
408
|
return ORJSONResponse(queryables)
|
eodag/utils/__init__.py
CHANGED
|
@@ -36,6 +36,7 @@ import re
|
|
|
36
36
|
import shutil
|
|
37
37
|
import ssl
|
|
38
38
|
import string
|
|
39
|
+
import struct
|
|
39
40
|
import sys
|
|
40
41
|
import types
|
|
41
42
|
import unicodedata
|
|
@@ -61,18 +62,7 @@ from typing import (
|
|
|
61
62
|
Union,
|
|
62
63
|
cast,
|
|
63
64
|
)
|
|
64
|
-
|
|
65
|
-
# All modules using these should import them from utils package
|
|
66
|
-
from urllib.parse import ( # noqa; noqa
|
|
67
|
-
parse_qs,
|
|
68
|
-
parse_qsl,
|
|
69
|
-
quote,
|
|
70
|
-
unquote,
|
|
71
|
-
urlencode,
|
|
72
|
-
urljoin,
|
|
73
|
-
urlparse,
|
|
74
|
-
urlsplit,
|
|
75
|
-
)
|
|
65
|
+
from urllib.parse import urlparse, urlsplit
|
|
76
66
|
from urllib.request import url2pathname
|
|
77
67
|
|
|
78
68
|
if sys.version_info >= (3, 12):
|
|
@@ -80,7 +70,6 @@ if sys.version_info >= (3, 12):
|
|
|
80
70
|
else:
|
|
81
71
|
from typing_extensions import Unpack # noqa
|
|
82
72
|
|
|
83
|
-
|
|
84
73
|
import click
|
|
85
74
|
import orjson
|
|
86
75
|
import shapefile
|
|
@@ -110,6 +99,13 @@ logger = py_logging.getLogger("eodag.utils")
|
|
|
110
99
|
DEFAULT_PROJ = "EPSG:4326"
|
|
111
100
|
|
|
112
101
|
GENERIC_PRODUCT_TYPE = "GENERIC_PRODUCT_TYPE"
|
|
102
|
+
GENERIC_STAC_PROVIDER = "generic_stac_provider"
|
|
103
|
+
|
|
104
|
+
STAC_SEARCH_PLUGINS = [
|
|
105
|
+
"StacSearch",
|
|
106
|
+
"StacListAssets",
|
|
107
|
+
"StaticStacSearch",
|
|
108
|
+
]
|
|
113
109
|
|
|
114
110
|
eodag_version = metadata("eodag")["Version"]
|
|
115
111
|
USER_AGENT = {"User-Agent": f"eodag/{eodag_version}"}
|
|
@@ -217,14 +213,13 @@ class FloatRange(click.types.FloatParamType):
|
|
|
217
213
|
):
|
|
218
214
|
if self.min is None:
|
|
219
215
|
self.fail(
|
|
220
|
-
"%s is bigger than the maximum valid value
|
|
216
|
+
"%s is bigger than the maximum valid value %s." % (rv, self.max),
|
|
221
217
|
param,
|
|
222
218
|
ctx,
|
|
223
219
|
)
|
|
224
220
|
elif self.max is None:
|
|
225
221
|
self.fail(
|
|
226
|
-
"%s is smaller than the minimum valid value "
|
|
227
|
-
"%s." % (rv, self.min),
|
|
222
|
+
"%s is smaller than the minimum valid value %s." % (rv, self.min),
|
|
228
223
|
param,
|
|
229
224
|
ctx,
|
|
230
225
|
)
|
|
@@ -380,27 +375,29 @@ def merge_mappings(mapping1: dict[Any, Any], mapping2: dict[Any, Any]) -> None:
|
|
|
380
375
|
# `m1_keys_lowercase.get(key, key)`
|
|
381
376
|
current_value = mapping1.get(m1_keys_lowercase.get(key, key))
|
|
382
377
|
if current_value is not None:
|
|
383
|
-
current_value_type = type(current_value)
|
|
384
|
-
new_value_type = type(value)
|
|
385
378
|
try:
|
|
386
379
|
# If current or new value is a list (search queryable parameter), simply replace current with new
|
|
387
380
|
if (
|
|
388
|
-
|
|
389
|
-
and
|
|
390
|
-
or
|
|
391
|
-
and
|
|
381
|
+
isinstance(value, list)
|
|
382
|
+
and not isinstance(current_value, list)
|
|
383
|
+
or not isinstance(value, list)
|
|
384
|
+
and isinstance(current_value, list)
|
|
392
385
|
):
|
|
393
386
|
mapping1[m1_keys_lowercase.get(key, key)] = value
|
|
394
387
|
else:
|
|
395
388
|
mapping1[m1_keys_lowercase.get(key, key)] = cast_scalar_value(
|
|
396
|
-
value,
|
|
389
|
+
value, type(current_value)
|
|
397
390
|
)
|
|
398
391
|
except (TypeError, ValueError):
|
|
399
392
|
# Ignore any override value that does not have the same type
|
|
400
393
|
# as the default value
|
|
401
394
|
logger.debug(
|
|
402
|
-
|
|
403
|
-
|
|
395
|
+
"Ignored '%s' setting override from '%s' to '%s', (could not cast %s to %s)",
|
|
396
|
+
key,
|
|
397
|
+
current_value,
|
|
398
|
+
value,
|
|
399
|
+
type(value),
|
|
400
|
+
type(current_value),
|
|
404
401
|
)
|
|
405
402
|
pass
|
|
406
403
|
else:
|
|
@@ -1444,8 +1441,7 @@ def cast_scalar_value(value: Any, new_type: Any) -> Any:
|
|
|
1444
1441
|
# case
|
|
1445
1442
|
if value.capitalize() not in ("True", "False"):
|
|
1446
1443
|
raise ValueError(
|
|
1447
|
-
"Only true or false strings (case insensitive) are "
|
|
1448
|
-
"allowed for booleans"
|
|
1444
|
+
"Only true or false strings (case insensitive) are allowed for booleans"
|
|
1449
1445
|
)
|
|
1450
1446
|
# Get the real Python value of the boolean. e.g: value='tRuE'
|
|
1451
1447
|
# => eval(value.capitalize())=True.
|
|
@@ -1498,6 +1494,7 @@ def guess_extension(type: str) -> Optional[str]:
|
|
|
1498
1494
|
return mimetypes.guess_extension(type, strict=False)
|
|
1499
1495
|
|
|
1500
1496
|
|
|
1497
|
+
@functools.lru_cache(maxsize=2)
|
|
1501
1498
|
def get_ssl_context(ssl_verify: bool) -> ssl.SSLContext:
|
|
1502
1499
|
"""
|
|
1503
1500
|
Returns an SSL context based on ``ssl_verify`` argument.
|
|
@@ -1565,3 +1562,27 @@ def remove_str_array_quotes(input_str: str) -> str:
|
|
|
1565
1562
|
continue
|
|
1566
1563
|
output_str += input_str[i]
|
|
1567
1564
|
return output_str
|
|
1565
|
+
|
|
1566
|
+
|
|
1567
|
+
def parse_le_uint32(data: bytes) -> int:
|
|
1568
|
+
"""
|
|
1569
|
+
Parse little-endian unsigned 4-byte integer.
|
|
1570
|
+
|
|
1571
|
+
>>> parse_le_uint32(b'\\x01\\x00\\x00\\x00')
|
|
1572
|
+
1
|
|
1573
|
+
>>> parse_le_uint32(b'\\xff\\xff\\xff\\xff')
|
|
1574
|
+
4294967295
|
|
1575
|
+
"""
|
|
1576
|
+
return struct.unpack("<I", data)[0]
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
def parse_le_uint16(data: bytes) -> int:
|
|
1580
|
+
"""
|
|
1581
|
+
Parse little-endian unsigned 2-byte integer.
|
|
1582
|
+
|
|
1583
|
+
>>> parse_le_uint16(b'\\x01\\x00')
|
|
1584
|
+
1
|
|
1585
|
+
>>> parse_le_uint16(b'\\xff\\xff')
|
|
1586
|
+
65535
|
|
1587
|
+
"""
|
|
1588
|
+
return struct.unpack("<H", data)[0]
|
eodag/utils/exceptions.py
CHANGED
|
@@ -79,6 +79,10 @@ class STACOpenerError(EodagError):
|
|
|
79
79
|
"""An error indicating that a STAC file could not be opened"""
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
class InvalidDataError(EodagError):
|
|
83
|
+
"""Raised when data is invalid, malformed, or corrupt and cannot be processed as expected."""
|
|
84
|
+
|
|
85
|
+
|
|
82
86
|
class RequestError(EodagError):
|
|
83
87
|
"""An error indicating that a request has failed. Usually eodag functions
|
|
84
88
|
and methods should catch and skip this"""
|