eodag 2.12.0__py3-none-any.whl → 3.0.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/__init__.py +6 -8
- eodag/api/core.py +654 -538
- eodag/api/product/__init__.py +12 -2
- eodag/api/product/_assets.py +59 -16
- eodag/api/product/_product.py +100 -93
- eodag/api/product/drivers/__init__.py +7 -2
- eodag/api/product/drivers/base.py +0 -3
- eodag/api/product/metadata_mapping.py +192 -96
- eodag/api/search_result.py +69 -10
- eodag/cli.py +55 -25
- eodag/config.py +391 -116
- eodag/plugins/apis/base.py +11 -165
- eodag/plugins/apis/ecmwf.py +36 -25
- eodag/plugins/apis/usgs.py +80 -35
- eodag/plugins/authentication/aws_auth.py +13 -4
- eodag/plugins/authentication/base.py +10 -1
- eodag/plugins/authentication/generic.py +2 -2
- eodag/plugins/authentication/header.py +31 -6
- eodag/plugins/authentication/keycloak.py +17 -84
- eodag/plugins/authentication/oauth.py +3 -3
- eodag/plugins/authentication/openid_connect.py +268 -49
- eodag/plugins/authentication/qsauth.py +4 -1
- eodag/plugins/authentication/sas_auth.py +9 -2
- eodag/plugins/authentication/token.py +98 -47
- eodag/plugins/authentication/token_exchange.py +122 -0
- eodag/plugins/crunch/base.py +3 -1
- eodag/plugins/crunch/filter_date.py +3 -9
- eodag/plugins/crunch/filter_latest_intersect.py +0 -3
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -4
- eodag/plugins/crunch/filter_overlap.py +4 -8
- eodag/plugins/crunch/filter_property.py +5 -11
- eodag/plugins/download/aws.py +149 -185
- eodag/plugins/download/base.py +88 -97
- eodag/plugins/download/creodias_s3.py +1 -1
- eodag/plugins/download/http.py +638 -310
- eodag/plugins/download/s3rest.py +47 -45
- eodag/plugins/manager.py +228 -88
- eodag/plugins/search/__init__.py +36 -0
- eodag/plugins/search/base.py +239 -30
- eodag/plugins/search/build_search_result.py +382 -37
- eodag/plugins/search/cop_marine.py +441 -0
- eodag/plugins/search/creodias_s3.py +25 -20
- eodag/plugins/search/csw.py +5 -7
- eodag/plugins/search/data_request_search.py +61 -30
- eodag/plugins/search/qssearch.py +713 -255
- eodag/plugins/search/static_stac_search.py +106 -40
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +1921 -34
- eodag/resources/providers.yml +4091 -3655
- eodag/resources/stac.yml +50 -216
- eodag/resources/stac_api.yml +71 -25
- eodag/resources/stac_provider.yml +5 -0
- eodag/resources/user_conf_template.yml +89 -32
- eodag/rest/__init__.py +6 -0
- eodag/rest/cache.py +70 -0
- eodag/rest/config.py +68 -0
- eodag/rest/constants.py +26 -0
- eodag/rest/core.py +735 -0
- eodag/rest/errors.py +178 -0
- eodag/rest/server.py +264 -431
- eodag/rest/stac.py +442 -836
- eodag/rest/types/collections_search.py +44 -0
- eodag/rest/types/eodag_search.py +238 -47
- eodag/rest/types/queryables.py +164 -0
- eodag/rest/types/stac_search.py +273 -0
- eodag/rest/utils/__init__.py +216 -0
- eodag/rest/utils/cql_evaluate.py +119 -0
- eodag/rest/utils/rfc3339.py +64 -0
- eodag/types/__init__.py +106 -10
- eodag/types/bbox.py +15 -14
- eodag/types/download_args.py +40 -0
- eodag/types/search_args.py +57 -7
- eodag/types/whoosh.py +79 -0
- eodag/utils/__init__.py +110 -91
- eodag/utils/constraints.py +37 -45
- eodag/utils/exceptions.py +39 -22
- eodag/utils/import_system.py +0 -4
- eodag/utils/logging.py +37 -80
- eodag/utils/notebook.py +4 -4
- eodag/utils/repr.py +113 -0
- eodag/utils/requests.py +128 -0
- eodag/utils/rest.py +100 -0
- eodag/utils/stac_reader.py +93 -21
- {eodag-2.12.0.dist-info → eodag-3.0.0.dist-info}/METADATA +88 -53
- eodag-3.0.0.dist-info/RECORD +109 -0
- {eodag-2.12.0.dist-info → eodag-3.0.0.dist-info}/WHEEL +1 -1
- {eodag-2.12.0.dist-info → eodag-3.0.0.dist-info}/entry_points.txt +7 -5
- eodag/plugins/apis/cds.py +0 -540
- eodag/rest/types/stac_queryables.py +0 -134
- eodag/rest/utils.py +0 -1133
- eodag-2.12.0.dist-info/RECORD +0 -94
- {eodag-2.12.0.dist-info → eodag-3.0.0.dist-info}/LICENSE +0 -0
- {eodag-2.12.0.dist-info → eodag-3.0.0.dist-info}/top_level.txt +0 -0
eodag/api/product/__init__.py
CHANGED
|
@@ -15,8 +15,18 @@
|
|
|
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
|
+
#
|
|
18
19
|
"""EODAG product package"""
|
|
19
20
|
try:
|
|
20
|
-
from
|
|
21
|
+
# import from eodag-cube if installed
|
|
22
|
+
from eodag_cube.api.product import ( # pyright: ignore[reportMissingImports]
|
|
23
|
+
Asset,
|
|
24
|
+
AssetsDict,
|
|
25
|
+
EOProduct,
|
|
26
|
+
)
|
|
21
27
|
except ImportError:
|
|
22
|
-
from .
|
|
28
|
+
from ._assets import Asset, AssetsDict # type: ignore[assignment]
|
|
29
|
+
from ._product import EOProduct # type: ignore[assignment]
|
|
30
|
+
|
|
31
|
+
# exportable content
|
|
32
|
+
__all__ = ["Asset", "AssetsDict", "EOProduct"]
|
eodag/api/product/_assets.py
CHANGED
|
@@ -19,12 +19,15 @@ 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
|
+
from eodag.utils.repr import dict_to_html_table
|
|
25
26
|
|
|
26
27
|
if TYPE_CHECKING:
|
|
27
28
|
from eodag.api.product import EOProduct
|
|
29
|
+
from eodag.types.download_args import DownloadConf
|
|
30
|
+
from eodag.utils import Unpack
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
class AssetsDict(UserDict):
|
|
@@ -32,11 +35,8 @@ class AssetsDict(UserDict):
|
|
|
32
35
|
:class:`~eodag.api.product._product.EOProduct` resulting from a search.
|
|
33
36
|
|
|
34
37
|
:param product: Product resulting from a search
|
|
35
|
-
:type product: :class:`~eodag.api.product._product.EOProduct`
|
|
36
38
|
:param args: (optional) Arguments used to init the dictionary
|
|
37
|
-
:type args: Any
|
|
38
39
|
:param kwargs: (optional) Additional named-arguments used to init the dictionary
|
|
39
|
-
:type kwargs: Any
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
42
|
product: EOProduct
|
|
@@ -53,17 +53,15 @@ class AssetsDict(UserDict):
|
|
|
53
53
|
|
|
54
54
|
:returns: The representation of a :class:`~eodag.api.product._assets.AssetsDict`
|
|
55
55
|
as a Python dict
|
|
56
|
-
:rtype: dict
|
|
57
56
|
"""
|
|
58
57
|
return {k: v.as_dict() for k, v in self.data.items()}
|
|
59
58
|
|
|
60
59
|
def get_values(self, asset_filter: str = "") -> List[Asset]:
|
|
61
60
|
"""
|
|
62
61
|
retrieves the assets matching the given filter
|
|
63
|
-
|
|
64
|
-
:
|
|
62
|
+
|
|
63
|
+
:param asset_filter: regex filter with which the assets should be matched
|
|
65
64
|
:return: list of assets
|
|
66
|
-
:rtype: List[Asset]
|
|
67
65
|
"""
|
|
68
66
|
if asset_filter:
|
|
69
67
|
filter_regex = re.compile(asset_filter)
|
|
@@ -82,22 +80,58 @@ class AssetsDict(UserDict):
|
|
|
82
80
|
else:
|
|
83
81
|
return [a for a in self.values() if "href" in a]
|
|
84
82
|
|
|
83
|
+
def _repr_html_(self, embeded=False):
|
|
84
|
+
thead = (
|
|
85
|
+
f"""<thead><tr><td style='text-align: left; color: grey;'>
|
|
86
|
+
{type(self).__name__} ({len(self)})
|
|
87
|
+
</td></tr></thead>
|
|
88
|
+
"""
|
|
89
|
+
if not embeded
|
|
90
|
+
else ""
|
|
91
|
+
)
|
|
92
|
+
tr_style = "style='background-color: transparent;'" if embeded else ""
|
|
93
|
+
return (
|
|
94
|
+
f"<table>{thead}"
|
|
95
|
+
+ "".join(
|
|
96
|
+
[
|
|
97
|
+
f"""<tr {tr_style}><td style='text-align: left;'>
|
|
98
|
+
<details><summary style='color: grey;'>
|
|
99
|
+
<span style='color: black'>'{k}'</span>: 
|
|
100
|
+
{{
|
|
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
|
+
...
|
|
108
|
+
}}
|
|
109
|
+
</summary>
|
|
110
|
+
{dict_to_html_table(v, depth=1)}
|
|
111
|
+
</details>
|
|
112
|
+
</td></tr>
|
|
113
|
+
"""
|
|
114
|
+
for k, v in self.items()
|
|
115
|
+
]
|
|
116
|
+
)
|
|
117
|
+
+ "</table>"
|
|
118
|
+
)
|
|
119
|
+
|
|
85
120
|
|
|
86
121
|
class Asset(UserDict):
|
|
87
122
|
"""A UserDict object containg one of the assets of a
|
|
88
123
|
:class:`~eodag.api.product._product.EOProduct` resulting from a search.
|
|
89
124
|
|
|
90
125
|
:param product: Product resulting from a search
|
|
91
|
-
:type product: :class:`~eodag.api.product._product.EOProduct`
|
|
92
126
|
:param key: asset key
|
|
93
|
-
:type key: str
|
|
94
127
|
:param args: (optional) Arguments used to init the dictionary
|
|
95
|
-
:type args: Any
|
|
96
128
|
:param kwargs: (optional) Additional named-arguments used to init the dictionary
|
|
97
|
-
:type kwargs: Any
|
|
98
129
|
"""
|
|
99
130
|
|
|
100
131
|
product: EOProduct
|
|
132
|
+
size: int
|
|
133
|
+
filename: Optional[str]
|
|
134
|
+
rel_path: str
|
|
101
135
|
|
|
102
136
|
def __init__(self, product: EOProduct, key: str, *args: Any, **kwargs: Any) -> None:
|
|
103
137
|
self.product = product
|
|
@@ -109,16 +143,25 @@ class Asset(UserDict):
|
|
|
109
143
|
|
|
110
144
|
:returns: The representation of a :class:`~eodag.api.product._assets.Asset` as a
|
|
111
145
|
Python dict
|
|
112
|
-
:rtype: dict
|
|
113
146
|
"""
|
|
114
147
|
return self.data
|
|
115
148
|
|
|
116
|
-
def download(self, **kwargs:
|
|
149
|
+
def download(self, **kwargs: Unpack[DownloadConf]) -> str:
|
|
117
150
|
"""Downloads a single asset
|
|
118
151
|
|
|
119
152
|
:param kwargs: (optional) Additional named-arguments passed to `plugin.download()`
|
|
120
|
-
:type kwargs: Any
|
|
121
153
|
:returns: The absolute path to the downloaded product on the local filesystem
|
|
122
|
-
:rtype: str
|
|
123
154
|
"""
|
|
124
155
|
return self.product.download(asset=self.key, **kwargs)
|
|
156
|
+
|
|
157
|
+
def _repr_html_(self):
|
|
158
|
+
thead = f"""<thead><tr><td style='text-align: left; color: grey;'>
|
|
159
|
+
{type(self).__name__} - {self.key}
|
|
160
|
+
</td></tr></thead>
|
|
161
|
+
"""
|
|
162
|
+
return f"""<table>{thead}
|
|
163
|
+
<tr><td style='text-align: left;'>
|
|
164
|
+
{dict_to_html_table(self)}
|
|
165
|
+
</details>
|
|
166
|
+
</td></tr>
|
|
167
|
+
</table>"""
|
eodag/api/product/_product.py
CHANGED
|
@@ -21,17 +21,29 @@ 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 ( # pyright: ignore[reportMissingImports]
|
|
36
|
+
AssetsDict,
|
|
37
|
+
)
|
|
38
|
+
except ImportError:
|
|
39
|
+
from eodag.api.product._assets import AssetsDict
|
|
40
|
+
|
|
33
41
|
from eodag.api.product.drivers import DRIVERS, NoDriver
|
|
34
|
-
from eodag.api.product.metadata_mapping import
|
|
42
|
+
from eodag.api.product.metadata_mapping import (
|
|
43
|
+
DEFAULT_GEOMETRY,
|
|
44
|
+
NOT_AVAILABLE,
|
|
45
|
+
NOT_MAPPED,
|
|
46
|
+
)
|
|
35
47
|
from eodag.utils import (
|
|
36
48
|
DEFAULT_DOWNLOAD_TIMEOUT,
|
|
37
49
|
DEFAULT_DOWNLOAD_WAIT,
|
|
@@ -41,6 +53,7 @@ from eodag.utils import (
|
|
|
41
53
|
get_geometry_from_various,
|
|
42
54
|
)
|
|
43
55
|
from eodag.utils.exceptions import DownloadError, MisconfiguredError
|
|
56
|
+
from eodag.utils.repr import dict_to_html_table
|
|
44
57
|
|
|
45
58
|
if TYPE_CHECKING:
|
|
46
59
|
from shapely.geometry.base import BaseGeometry
|
|
@@ -49,6 +62,8 @@ if TYPE_CHECKING:
|
|
|
49
62
|
from eodag.plugins.apis.base import Api
|
|
50
63
|
from eodag.plugins.authentication.base import Authentication
|
|
51
64
|
from eodag.plugins.download.base import Download
|
|
65
|
+
from eodag.types.download_args import DownloadConf
|
|
66
|
+
from eodag.utils import Unpack
|
|
52
67
|
|
|
53
68
|
try:
|
|
54
69
|
from shapely.errors import GEOSException
|
|
@@ -73,9 +88,7 @@ class EOProduct:
|
|
|
73
88
|
parameters that led to its creation.
|
|
74
89
|
|
|
75
90
|
:param provider: The provider from which the product originates
|
|
76
|
-
:type provider: str
|
|
77
91
|
:param properties: The metadata of the product
|
|
78
|
-
:type properties: dict
|
|
79
92
|
:ivar product_type: The product type
|
|
80
93
|
:vartype product_type: str
|
|
81
94
|
:ivar location: The path to the product, either remote or local if downloaded
|
|
@@ -133,40 +146,15 @@ class EOProduct:
|
|
|
133
146
|
raise MisconfiguredError(
|
|
134
147
|
f"No geometry available to build EOProduct(id={properties.get('id', None)}, provider={provider})"
|
|
135
148
|
)
|
|
136
|
-
elif properties["geometry"] == NOT_AVAILABLE:
|
|
137
|
-
product_geometry = properties.pop("defaultGeometry")
|
|
149
|
+
elif not properties["geometry"] or properties["geometry"] == NOT_AVAILABLE:
|
|
150
|
+
product_geometry = properties.pop("defaultGeometry", DEFAULT_GEOMETRY)
|
|
138
151
|
else:
|
|
139
152
|
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)
|
|
153
|
+
|
|
154
|
+
self.geometry = self.search_intersection = get_geometry_from_various(
|
|
155
|
+
geometry=product_geometry
|
|
156
|
+
)
|
|
157
|
+
|
|
170
158
|
self.search_kwargs = kwargs
|
|
171
159
|
if self.search_kwargs.get("geometry") is not None:
|
|
172
160
|
searched_geom = get_geometry_from_various(
|
|
@@ -192,7 +180,6 @@ class EOProduct:
|
|
|
192
180
|
|
|
193
181
|
:returns: The representation of a :class:`~eodag.api.product._product.EOProduct` as a
|
|
194
182
|
Python dict
|
|
195
|
-
:rtype: dict
|
|
196
183
|
"""
|
|
197
184
|
search_intersection = None
|
|
198
185
|
if self.search_intersection is not None:
|
|
@@ -224,9 +211,7 @@ class EOProduct:
|
|
|
224
211
|
|
|
225
212
|
:param feature: The representation of a :class:`~eodag.api.product._product.EOProduct`
|
|
226
213
|
as a Python dict
|
|
227
|
-
:type feature: dict
|
|
228
214
|
:returns: An instance of :class:`~eodag.api.product._product.EOProduct`
|
|
229
|
-
:rtype: :class:`~eodag.api.product._product.EOProduct`
|
|
230
215
|
"""
|
|
231
216
|
properties = feature["properties"]
|
|
232
217
|
properties["geometry"] = feature["geometry"]
|
|
@@ -260,11 +245,9 @@ class EOProduct:
|
|
|
260
245
|
"""Give to the product the information needed to download itself.
|
|
261
246
|
|
|
262
247
|
:param downloader: The download method that it can use
|
|
263
|
-
:type downloader: Concrete subclass of
|
|
264
248
|
:class:`~eodag.plugins.download.base.Download` or
|
|
265
249
|
:class:`~eodag.plugins.api.base.Api`
|
|
266
250
|
:param authenticator: The authentication method needed to perform the download
|
|
267
|
-
:type authenticator: Concrete subclass of
|
|
268
251
|
:class:`~eodag.plugins.authentication.base.Authentication`
|
|
269
252
|
"""
|
|
270
253
|
self.downloader = downloader
|
|
@@ -273,31 +256,23 @@ class EOProduct:
|
|
|
273
256
|
# resolve locations and properties if needed with downloader configuration
|
|
274
257
|
location_attrs = ("location", "remote_location")
|
|
275
258
|
for location_attr in location_attrs:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
259
|
+
if "%(" in getattr(self, location_attr):
|
|
260
|
+
try:
|
|
261
|
+
setattr(
|
|
262
|
+
self,
|
|
263
|
+
location_attr,
|
|
264
|
+
getattr(self, location_attr) % vars(self.downloader.config),
|
|
265
|
+
)
|
|
266
|
+
except ValueError as e:
|
|
267
|
+
logger.debug(
|
|
268
|
+
f"Could not resolve product.{location_attr} ({getattr(self, location_attr)})"
|
|
269
|
+
f" in register_downloader: {str(e)}"
|
|
270
|
+
)
|
|
288
271
|
|
|
289
272
|
for k, v in self.properties.items():
|
|
290
|
-
if isinstance(v, str):
|
|
273
|
+
if isinstance(v, str) and "%(" in v:
|
|
291
274
|
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)
|
|
275
|
+
self.properties[k] = v % vars(self.downloader.config)
|
|
301
276
|
except (TypeError, ValueError) as e:
|
|
302
277
|
logger.debug(
|
|
303
278
|
f"Could not resolve {k} property ({v}) in register_downloader: {str(e)}"
|
|
@@ -308,7 +283,7 @@ class EOProduct:
|
|
|
308
283
|
progress_callback: Optional[ProgressCallback] = None,
|
|
309
284
|
wait: int = DEFAULT_DOWNLOAD_WAIT,
|
|
310
285
|
timeout: int = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
311
|
-
**kwargs:
|
|
286
|
+
**kwargs: Unpack[DownloadConf],
|
|
312
287
|
) -> str:
|
|
313
288
|
"""Download the EO product using the provided download plugin and the
|
|
314
289
|
authenticator if necessary.
|
|
@@ -322,20 +297,15 @@ class EOProduct:
|
|
|
322
297
|
size as inputs and handle progress bar
|
|
323
298
|
creation and update to give the user a
|
|
324
299
|
feedback on the download progress
|
|
325
|
-
:type progress_callback: :class:`~eodag.utils.ProgressCallback` or None
|
|
326
300
|
:param wait: (optional) If download fails, wait time in minutes between
|
|
327
301
|
two download tries
|
|
328
|
-
:type wait: int
|
|
329
302
|
:param timeout: (optional) If download fails, maximum time in minutes
|
|
330
303
|
before stop retrying to download
|
|
331
|
-
:
|
|
332
|
-
:param kwargs: `outputs_prefix` (str), `extract` (bool), `delete_archive` (bool)
|
|
304
|
+
:param kwargs: `output_dir` (str), `extract` (bool), `delete_archive` (bool)
|
|
333
305
|
and `dl_url_params` (dict) can be provided as additional kwargs
|
|
334
306
|
and will override any other values defined in a configuration
|
|
335
307
|
file or with environment variables.
|
|
336
|
-
:type kwargs: Union[str, bool, dict]
|
|
337
308
|
:returns: The absolute path to the downloaded product on the local filesystem
|
|
338
|
-
:rtype: str
|
|
339
309
|
:raises: :class:`~eodag.utils.exceptions.PluginImplementationError`
|
|
340
310
|
:raises: :class:`RuntimeError`
|
|
341
311
|
"""
|
|
@@ -351,13 +321,6 @@ class EOProduct:
|
|
|
351
321
|
else self.downloader_auth
|
|
352
322
|
)
|
|
353
323
|
|
|
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
324
|
progress_callback, close_progress_callback = self._init_progress_bar(
|
|
362
325
|
progress_callback
|
|
363
326
|
)
|
|
@@ -410,7 +373,7 @@ class EOProduct:
|
|
|
410
373
|
def get_quicklook(
|
|
411
374
|
self,
|
|
412
375
|
filename: Optional[str] = None,
|
|
413
|
-
|
|
376
|
+
output_dir: Optional[str] = None,
|
|
414
377
|
progress_callback: Optional[ProgressCallback] = None,
|
|
415
378
|
) -> str:
|
|
416
379
|
"""Download the quicklook image of a given EOProduct from its provider if it
|
|
@@ -418,18 +381,14 @@ class EOProduct:
|
|
|
418
381
|
|
|
419
382
|
:param filename: (optional) The name to give to the downloaded quicklook. If not
|
|
420
383
|
given, it defaults to the product's ID (without file extension).
|
|
421
|
-
:
|
|
422
|
-
:param base_dir: (optional) The absolute path of the directory where to store
|
|
384
|
+
:param output_dir: (optional) The absolute path of the directory where to store
|
|
423
385
|
the quicklooks in the filesystem. If not given, it defaults to the
|
|
424
|
-
`quicklooks` directory under this EO product downloader's ``
|
|
386
|
+
`quicklooks` directory under this EO product downloader's ``output_dir``
|
|
425
387
|
config param (e.g. '/tmp/quicklooks/')
|
|
426
|
-
:type base_dir: str
|
|
427
388
|
:param progress_callback: (optional) A method or a callable object which takes
|
|
428
389
|
a current size and a maximum size as inputs and handle progress bar
|
|
429
390
|
creation and update to give the user a feedback on the download progress
|
|
430
|
-
:type progress_callback: :class:`~eodag.utils.ProgressCallback` or None
|
|
431
391
|
:returns: The absolute path of the downloaded quicklook
|
|
432
|
-
:rtype: str
|
|
433
392
|
"""
|
|
434
393
|
|
|
435
394
|
def format_quicklook_address() -> None:
|
|
@@ -466,16 +425,20 @@ class EOProduct:
|
|
|
466
425
|
|
|
467
426
|
format_quicklook_address()
|
|
468
427
|
|
|
469
|
-
if
|
|
470
|
-
|
|
428
|
+
if output_dir is not None:
|
|
429
|
+
quicklooks_output_dir = os.path.abspath(os.path.realpath(output_dir))
|
|
471
430
|
else:
|
|
472
|
-
|
|
473
|
-
|
|
431
|
+
tempdir = tempfile.gettempdir()
|
|
432
|
+
downloader_output_dir = (
|
|
433
|
+
getattr(self.downloader.config, "output_dir", tempdir)
|
|
434
|
+
if self.downloader
|
|
435
|
+
else tempdir
|
|
474
436
|
)
|
|
475
|
-
|
|
476
|
-
|
|
437
|
+
quicklooks_output_dir = os.path.join(downloader_output_dir, "quicklooks")
|
|
438
|
+
if not os.path.isdir(quicklooks_output_dir):
|
|
439
|
+
os.makedirs(quicklooks_output_dir)
|
|
477
440
|
quicklook_file = os.path.join(
|
|
478
|
-
|
|
441
|
+
quicklooks_output_dir,
|
|
479
442
|
filename if filename is not None else self.properties["id"],
|
|
480
443
|
)
|
|
481
444
|
|
|
@@ -497,6 +460,8 @@ class EOProduct:
|
|
|
497
460
|
if self.downloader_auth is not None
|
|
498
461
|
else None
|
|
499
462
|
)
|
|
463
|
+
if not isinstance(auth, AuthBase):
|
|
464
|
+
auth = None
|
|
500
465
|
with requests.get(
|
|
501
466
|
self.properties["quicklook"],
|
|
502
467
|
stream=True,
|
|
@@ -539,3 +504,45 @@ class EOProduct:
|
|
|
539
504
|
)
|
|
540
505
|
pass
|
|
541
506
|
return NoDriver()
|
|
507
|
+
|
|
508
|
+
def _repr_html_(self):
|
|
509
|
+
thumbnail = self.properties.get("thumbnail", None)
|
|
510
|
+
thumbnail_html = (
|
|
511
|
+
f"<img src='{thumbnail}' width=100 alt='thumbnail'/>"
|
|
512
|
+
if thumbnail and not thumbnail.startswith("s3")
|
|
513
|
+
else ""
|
|
514
|
+
)
|
|
515
|
+
geom_style = "style='color: grey; text-align: center; min-width:100px; vertical-align: top;'"
|
|
516
|
+
thumbnail_style = (
|
|
517
|
+
"style='padding-top: 1.5em; min-width:100px; vertical-align: top;'"
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
return f"""<table>
|
|
521
|
+
<thead><tr style='background-color: transparent;'><td style='text-align: left; color: grey;'>
|
|
522
|
+
{type(self).__name__}
|
|
523
|
+
</td></tr></thead>
|
|
524
|
+
|
|
525
|
+
<tr style='background-color: transparent;'>
|
|
526
|
+
<td style='text-align: left; vertical-align: top;'>
|
|
527
|
+
{dict_to_html_table({
|
|
528
|
+
"provider": self.provider,
|
|
529
|
+
"product_type": self.product_type,
|
|
530
|
+
"properties["id"]": self.properties.get('id', None),
|
|
531
|
+
"properties["startTimeFromAscendingNode"]": self.properties.get(
|
|
532
|
+
'startTimeFromAscendingNode', None
|
|
533
|
+
),
|
|
534
|
+
"properties["completionTimeFromAscendingNode"]": self.properties.get(
|
|
535
|
+
'completionTimeFromAscendingNode', None
|
|
536
|
+
),
|
|
537
|
+
}, brackets=False)}
|
|
538
|
+
<details><summary style='color: grey; margin-top: 10px;'>properties: ({
|
|
539
|
+
len(self.properties)
|
|
540
|
+
})</summary>{dict_to_html_table(self.properties, depth=1)}</details>
|
|
541
|
+
<details><summary style='color: grey; margin-top: 10px;'>assets: ({
|
|
542
|
+
len(self.assets)
|
|
543
|
+
})</summary>{self.assets._repr_html_(embeded=True)}</details>
|
|
544
|
+
</td>
|
|
545
|
+
<td {geom_style} title='geometry'>geometry<br />{self.geometry._repr_svg_()}</td>
|
|
546
|
+
<td {thumbnail_style} title='properties["thumbnail"]'>{thumbnail_html}</td>
|
|
547
|
+
</tr>
|
|
548
|
+
</table>"""
|
|
@@ -16,9 +16,14 @@
|
|
|
16
16
|
# See the License for the specific language governing permissions and
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
"""EODAG drivers package"""
|
|
19
|
-
from eodag.api.product.drivers.base import DatasetDriver, NoDriver
|
|
19
|
+
from eodag.api.product.drivers.base import DatasetDriver, NoDriver
|
|
20
20
|
|
|
21
21
|
try:
|
|
22
|
-
from eodag_cube.api.product.drivers import
|
|
22
|
+
from eodag_cube.api.product.drivers import ( # pyright: ignore[reportMissingImports]
|
|
23
|
+
DRIVERS,
|
|
24
|
+
)
|
|
23
25
|
except ImportError:
|
|
24
26
|
DRIVERS = []
|
|
27
|
+
|
|
28
|
+
# exportable content
|
|
29
|
+
__all__ = ["DRIVERS", "DatasetDriver", "NoDriver"]
|
|
@@ -30,11 +30,8 @@ class DatasetDriver(metaclass=type):
|
|
|
30
30
|
"""Retrieve the address of the dataset represented by `eo_product`.
|
|
31
31
|
|
|
32
32
|
:param eo_product: The product whom underlying dataset address is to be retrieved
|
|
33
|
-
:type eo_product: :class:`~eodag.api.product._product.EOProduct`
|
|
34
33
|
:param band: The band to retrieve (e.g: 'B01')
|
|
35
|
-
:type band: str
|
|
36
34
|
:returns: An address for the dataset
|
|
37
|
-
:rtype: str
|
|
38
35
|
:raises: :class:`~eodag.utils.exceptions.AddressNotFound`
|
|
39
36
|
:raises: :class:`~eodag.utils.exceptions.UnsupportedDatasetAddressScheme`
|
|
40
37
|
"""
|