eodag 2.12.0__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 -162
- 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.0.dist-info → eodag-3.0.0b1.dist-info}/METADATA +64 -44
- eodag-3.0.0b1.dist-info/RECORD +109 -0
- {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/WHEEL +1 -1
- {eodag-2.12.0.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.0.dist-info/RECORD +0 -94
- {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/LICENSE +0 -0
- {eodag-2.12.0.dist-info → eodag-3.0.0b1.dist-info}/top_level.txt +0 -0
eodag/api/product/__init__.py
CHANGED
|
@@ -15,8 +15,12 @@
|
|
|
15
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
16
|
# See the License for the specific language governing permissions and
|
|
17
17
|
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
# type: ignore
|
|
18
20
|
"""EODAG product package"""
|
|
19
21
|
try:
|
|
20
|
-
from
|
|
22
|
+
# import from eodag-cube if installed
|
|
23
|
+
from eodag_cube.api.product import Asset, AssetsDict, EOProduct # noqa
|
|
21
24
|
except ImportError:
|
|
25
|
+
from ._assets import Asset, AssetsDict # noqa
|
|
22
26
|
from ._product import EOProduct # noqa
|
eodag/api/product/_assets.py
CHANGED
|
@@ -19,12 +19,14 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import re
|
|
21
21
|
from collections import UserDict
|
|
22
|
-
from typing import TYPE_CHECKING, Any, Dict, List
|
|
22
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
23
23
|
|
|
24
24
|
from eodag.utils.exceptions import NotAvailableError
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from eodag.api.product import EOProduct
|
|
28
|
+
from eodag.types.download_args import DownloadConf
|
|
29
|
+
from eodag.utils import Unpack
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class AssetsDict(UserDict):
|
|
@@ -98,6 +100,9 @@ class Asset(UserDict):
|
|
|
98
100
|
"""
|
|
99
101
|
|
|
100
102
|
product: EOProduct
|
|
103
|
+
size: int
|
|
104
|
+
filename: Optional[str]
|
|
105
|
+
rel_path: str
|
|
101
106
|
|
|
102
107
|
def __init__(self, product: EOProduct, key: str, *args: Any, **kwargs: Any) -> None:
|
|
103
108
|
self.product = product
|
|
@@ -113,7 +118,7 @@ class Asset(UserDict):
|
|
|
113
118
|
"""
|
|
114
119
|
return self.data
|
|
115
120
|
|
|
116
|
-
def download(self, **kwargs:
|
|
121
|
+
def download(self, **kwargs: Unpack[DownloadConf]) -> str:
|
|
117
122
|
"""Downloads a single asset
|
|
118
123
|
|
|
119
124
|
:param kwargs: (optional) Additional named-arguments passed to `plugin.download()`
|
eodag/api/product/_product.py
CHANGED
|
@@ -21,17 +21,27 @@ import base64
|
|
|
21
21
|
import logging
|
|
22
22
|
import os
|
|
23
23
|
import re
|
|
24
|
-
import
|
|
24
|
+
import tempfile
|
|
25
25
|
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
|
|
26
26
|
|
|
27
27
|
import requests
|
|
28
28
|
from requests import RequestException
|
|
29
|
-
from
|
|
29
|
+
from requests.auth import AuthBase
|
|
30
|
+
from shapely import geometry
|
|
30
31
|
from shapely.errors import ShapelyError
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
try:
|
|
34
|
+
# import from eodag-cube if installed
|
|
35
|
+
from eodag_cube.api.product import AssetsDict # type: ignore # noqa
|
|
36
|
+
except ImportError:
|
|
37
|
+
from eodag.api.product._assets import AssetsDict # type: ignore # noqa
|
|
38
|
+
|
|
33
39
|
from eodag.api.product.drivers import DRIVERS, NoDriver
|
|
34
|
-
from eodag.api.product.metadata_mapping import
|
|
40
|
+
from eodag.api.product.metadata_mapping import (
|
|
41
|
+
DEFAULT_GEOMETRY,
|
|
42
|
+
NOT_AVAILABLE,
|
|
43
|
+
NOT_MAPPED,
|
|
44
|
+
)
|
|
35
45
|
from eodag.utils import (
|
|
36
46
|
DEFAULT_DOWNLOAD_TIMEOUT,
|
|
37
47
|
DEFAULT_DOWNLOAD_WAIT,
|
|
@@ -49,6 +59,8 @@ if TYPE_CHECKING:
|
|
|
49
59
|
from eodag.plugins.apis.base import Api
|
|
50
60
|
from eodag.plugins.authentication.base import Authentication
|
|
51
61
|
from eodag.plugins.download.base import Download
|
|
62
|
+
from eodag.types.download_args import DownloadConf
|
|
63
|
+
from eodag.utils import Unpack
|
|
52
64
|
|
|
53
65
|
try:
|
|
54
66
|
from shapely.errors import GEOSException
|
|
@@ -133,40 +145,15 @@ class EOProduct:
|
|
|
133
145
|
raise MisconfiguredError(
|
|
134
146
|
f"No geometry available to build EOProduct(id={properties.get('id', None)}, provider={provider})"
|
|
135
147
|
)
|
|
136
|
-
elif properties["geometry"] == NOT_AVAILABLE:
|
|
137
|
-
product_geometry = properties.pop("defaultGeometry")
|
|
148
|
+
elif not properties["geometry"] or properties["geometry"] == NOT_AVAILABLE:
|
|
149
|
+
product_geometry = properties.pop("defaultGeometry", DEFAULT_GEOMETRY)
|
|
138
150
|
else:
|
|
139
151
|
product_geometry = properties["geometry"]
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
found_bbox = bbox_pattern.match(product_geometry)
|
|
146
|
-
if found_bbox:
|
|
147
|
-
coords = found_bbox.groups()
|
|
148
|
-
if len(coords) == 4:
|
|
149
|
-
product_geometry = geometry.box(
|
|
150
|
-
float(coords[1]),
|
|
151
|
-
float(coords[0]),
|
|
152
|
-
float(coords[3]),
|
|
153
|
-
float(coords[2]),
|
|
154
|
-
)
|
|
155
|
-
# Best effort to understand provider specific geometry (the default is to
|
|
156
|
-
# assume an object implementing the Geo Interface: see
|
|
157
|
-
# https://gist.github.com/2217756)
|
|
158
|
-
if isinstance(product_geometry, str):
|
|
159
|
-
try:
|
|
160
|
-
product_geometry = wkt.loads(product_geometry)
|
|
161
|
-
except (ShapelyError, GEOSException):
|
|
162
|
-
try:
|
|
163
|
-
product_geometry = wkb.loads(product_geometry)
|
|
164
|
-
# Also catching TypeError because product_geometry can be a
|
|
165
|
-
# string and not a bytes string
|
|
166
|
-
except (ShapelyError, GEOSException, TypeError):
|
|
167
|
-
# Giv up!
|
|
168
|
-
raise
|
|
169
|
-
self.geometry = self.search_intersection = geometry.shape(product_geometry)
|
|
152
|
+
|
|
153
|
+
self.geometry = self.search_intersection = get_geometry_from_various(
|
|
154
|
+
geometry=product_geometry
|
|
155
|
+
)
|
|
156
|
+
|
|
170
157
|
self.search_kwargs = kwargs
|
|
171
158
|
if self.search_kwargs.get("geometry") is not None:
|
|
172
159
|
searched_geom = get_geometry_from_various(
|
|
@@ -273,31 +260,23 @@ class EOProduct:
|
|
|
273
260
|
# resolve locations and properties if needed with downloader configuration
|
|
274
261
|
location_attrs = ("location", "remote_location")
|
|
275
262
|
for location_attr in location_attrs:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
263
|
+
if "%(" in getattr(self, location_attr):
|
|
264
|
+
try:
|
|
265
|
+
setattr(
|
|
266
|
+
self,
|
|
267
|
+
location_attr,
|
|
268
|
+
getattr(self, location_attr) % vars(self.downloader.config),
|
|
269
|
+
)
|
|
270
|
+
except ValueError as e:
|
|
271
|
+
logger.debug(
|
|
272
|
+
f"Could not resolve product.{location_attr} ({getattr(self, location_attr)})"
|
|
273
|
+
f" in register_downloader: {str(e)}"
|
|
274
|
+
)
|
|
288
275
|
|
|
289
276
|
for k, v in self.properties.items():
|
|
290
|
-
if isinstance(v, str):
|
|
277
|
+
if isinstance(v, str) and "%(" in v:
|
|
291
278
|
try:
|
|
292
|
-
|
|
293
|
-
parsed = urllib.parse.urlparse(v)
|
|
294
|
-
prop = urllib.parse.unquote(parsed.path) % vars(
|
|
295
|
-
self.downloader.config
|
|
296
|
-
)
|
|
297
|
-
parsed = parsed._replace(path=urllib.parse.quote(prop))
|
|
298
|
-
self.properties[k] = urllib.parse.urlunparse(parsed)
|
|
299
|
-
else:
|
|
300
|
-
self.properties[k] = v % vars(self.downloader.config)
|
|
279
|
+
self.properties[k] = v % vars(self.downloader.config)
|
|
301
280
|
except (TypeError, ValueError) as e:
|
|
302
281
|
logger.debug(
|
|
303
282
|
f"Could not resolve {k} property ({v}) in register_downloader: {str(e)}"
|
|
@@ -308,7 +287,7 @@ class EOProduct:
|
|
|
308
287
|
progress_callback: Optional[ProgressCallback] = None,
|
|
309
288
|
wait: int = DEFAULT_DOWNLOAD_WAIT,
|
|
310
289
|
timeout: int = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
311
|
-
**kwargs:
|
|
290
|
+
**kwargs: Unpack[DownloadConf],
|
|
312
291
|
) -> str:
|
|
313
292
|
"""Download the EO product using the provided download plugin and the
|
|
314
293
|
authenticator if necessary.
|
|
@@ -351,13 +330,6 @@ class EOProduct:
|
|
|
351
330
|
else self.downloader_auth
|
|
352
331
|
)
|
|
353
332
|
|
|
354
|
-
# resolve remote location if needed with downloader configuration
|
|
355
|
-
self.remote_location = urllib.parse.unquote(self.remote_location) % vars(
|
|
356
|
-
self.downloader.config
|
|
357
|
-
)
|
|
358
|
-
if not self.location.startswith("file"):
|
|
359
|
-
self.location = urllib.parse.unquote(self.location)
|
|
360
|
-
|
|
361
333
|
progress_callback, close_progress_callback = self._init_progress_bar(
|
|
362
334
|
progress_callback
|
|
363
335
|
)
|
|
@@ -469,9 +441,13 @@ class EOProduct:
|
|
|
469
441
|
if base_dir is not None:
|
|
470
442
|
quicklooks_base_dir = os.path.abspath(os.path.realpath(base_dir))
|
|
471
443
|
else:
|
|
472
|
-
|
|
473
|
-
|
|
444
|
+
tempdir = tempfile.gettempdir()
|
|
445
|
+
outputs_prefix = (
|
|
446
|
+
getattr(self.downloader.config, "outputs_prefix", tempdir)
|
|
447
|
+
if self.downloader
|
|
448
|
+
else tempdir
|
|
474
449
|
)
|
|
450
|
+
quicklooks_base_dir = os.path.join(outputs_prefix, "quicklooks")
|
|
475
451
|
if not os.path.isdir(quicklooks_base_dir):
|
|
476
452
|
os.makedirs(quicklooks_base_dir)
|
|
477
453
|
quicklook_file = os.path.join(
|
|
@@ -497,6 +473,8 @@ class EOProduct:
|
|
|
497
473
|
if self.downloader_auth is not None
|
|
498
474
|
else None
|
|
499
475
|
)
|
|
476
|
+
if not isinstance(auth, AuthBase):
|
|
477
|
+
auth = None
|
|
500
478
|
with requests.get(
|
|
501
479
|
self.properties["quicklook"],
|
|
502
480
|
stream=True,
|