eodag 3.10.0__py3-none-any.whl → 4.0.0a1__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 +378 -419
- eodag/api/product/__init__.py +3 -3
- eodag/api/product/_product.py +68 -40
- eodag/api/product/drivers/__init__.py +3 -5
- eodag/api/product/drivers/base.py +1 -18
- eodag/api/product/metadata_mapping.py +151 -215
- eodag/api/search_result.py +13 -7
- eodag/cli.py +72 -395
- eodag/config.py +46 -50
- eodag/plugins/apis/base.py +2 -2
- eodag/plugins/apis/ecmwf.py +20 -21
- eodag/plugins/apis/usgs.py +37 -33
- eodag/plugins/authentication/base.py +1 -3
- eodag/plugins/crunch/filter_date.py +3 -3
- eodag/plugins/crunch/filter_latest_intersect.py +2 -2
- eodag/plugins/crunch/filter_latest_tpl_name.py +1 -1
- eodag/plugins/download/aws.py +45 -41
- eodag/plugins/download/base.py +13 -14
- eodag/plugins/download/http.py +65 -65
- eodag/plugins/manager.py +28 -29
- eodag/plugins/search/__init__.py +3 -4
- eodag/plugins/search/base.py +128 -77
- eodag/plugins/search/build_search_result.py +105 -107
- eodag/plugins/search/cop_marine.py +44 -47
- eodag/plugins/search/csw.py +33 -33
- eodag/plugins/search/qssearch.py +335 -354
- eodag/plugins/search/stac_list_assets.py +1 -1
- eodag/plugins/search/static_stac_search.py +31 -31
- eodag/resources/{product_types.yml → collections.yml} +2353 -2429
- eodag/resources/ext_collections.json +1 -1
- eodag/resources/providers.yml +2427 -2719
- eodag/resources/stac_provider.yml +46 -90
- eodag/types/queryables.py +55 -91
- eodag/types/search_args.py +1 -1
- eodag/utils/__init__.py +94 -21
- eodag/utils/exceptions.py +6 -6
- eodag/utils/free_text_search.py +3 -3
- {eodag-3.10.0.dist-info → eodag-4.0.0a1.dist-info}/METADATA +10 -87
- eodag-4.0.0a1.dist-info/RECORD +92 -0
- {eodag-3.10.0.dist-info → eodag-4.0.0a1.dist-info}/entry_points.txt +0 -4
- eodag/plugins/authentication/oauth.py +0 -60
- eodag/plugins/download/creodias_s3.py +0 -71
- eodag/plugins/download/s3rest.py +0 -351
- eodag/plugins/search/data_request_search.py +0 -565
- eodag/resources/stac.yml +0 -294
- eodag/resources/stac_api.yml +0 -2105
- eodag/rest/__init__.py +0 -24
- eodag/rest/cache.py +0 -70
- eodag/rest/config.py +0 -67
- eodag/rest/constants.py +0 -26
- eodag/rest/core.py +0 -764
- eodag/rest/errors.py +0 -210
- eodag/rest/server.py +0 -604
- eodag/rest/server.wsgi +0 -6
- eodag/rest/stac.py +0 -1032
- eodag/rest/templates/README +0 -1
- eodag/rest/types/__init__.py +0 -18
- eodag/rest/types/collections_search.py +0 -44
- eodag/rest/types/eodag_search.py +0 -386
- eodag/rest/types/queryables.py +0 -174
- eodag/rest/types/stac_search.py +0 -272
- eodag/rest/utils/__init__.py +0 -207
- eodag/rest/utils/cql_evaluate.py +0 -119
- eodag/rest/utils/rfc3339.py +0 -64
- eodag-3.10.0.dist-info/RECORD +0 -116
- {eodag-3.10.0.dist-info → eodag-4.0.0a1.dist-info}/WHEEL +0 -0
- {eodag-3.10.0.dist-info → eodag-4.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {eodag-3.10.0.dist-info → eodag-4.0.0a1.dist-info}/top_level.txt +0 -0
eodag/api/product/__init__.py
CHANGED
|
@@ -55,8 +55,8 @@ def unregistered_product_from_item(
|
|
|
55
55
|
# properties cleanup
|
|
56
56
|
for prop in ("start_datetime", "end_datetime"):
|
|
57
57
|
products[0].properties.pop(prop, None)
|
|
58
|
-
# set
|
|
59
|
-
if products[0].
|
|
60
|
-
products[0].
|
|
58
|
+
# set collection if not already set
|
|
59
|
+
if products[0].collection is None:
|
|
60
|
+
products[0].collection = products[0].properties.get("collection")
|
|
61
61
|
return products[0]
|
|
62
62
|
return None
|
eodag/api/product/_product.py
CHANGED
|
@@ -51,9 +51,10 @@ from eodag.utils import (
|
|
|
51
51
|
DEFAULT_STREAM_REQUESTS_TIMEOUT,
|
|
52
52
|
USER_AGENT,
|
|
53
53
|
ProgressCallback,
|
|
54
|
+
format_string,
|
|
54
55
|
get_geometry_from_various,
|
|
55
56
|
)
|
|
56
|
-
from eodag.utils.exceptions import DownloadError, MisconfiguredError
|
|
57
|
+
from eodag.utils.exceptions import DownloadError, MisconfiguredError, ValidationError
|
|
57
58
|
from eodag.utils.repr import dict_to_html_table
|
|
58
59
|
|
|
59
60
|
if TYPE_CHECKING:
|
|
@@ -104,8 +105,8 @@ class EOProduct:
|
|
|
104
105
|
provider: str
|
|
105
106
|
#: The metadata of the product
|
|
106
107
|
properties: dict[str, Any]
|
|
107
|
-
#: The
|
|
108
|
-
|
|
108
|
+
#: The collection
|
|
109
|
+
collection: Optional[str]
|
|
109
110
|
#: The geometry of the product
|
|
110
111
|
geometry: BaseGeometry
|
|
111
112
|
#: The intersection between the product's geometry and the search area.
|
|
@@ -127,8 +128,12 @@ class EOProduct:
|
|
|
127
128
|
self, provider: str, properties: dict[str, Any], **kwargs: Any
|
|
128
129
|
) -> None:
|
|
129
130
|
self.provider = provider
|
|
130
|
-
self.
|
|
131
|
-
|
|
131
|
+
self.collection = (
|
|
132
|
+
kwargs.get("collection")
|
|
133
|
+
or properties.pop("collection", None)
|
|
134
|
+
or properties.get("_collection")
|
|
135
|
+
)
|
|
136
|
+
self.location = self.remote_location = properties.get("eodag:download_link", "")
|
|
132
137
|
self.assets = AssetsDict(self)
|
|
133
138
|
self.properties = {
|
|
134
139
|
key: value
|
|
@@ -136,19 +141,32 @@ class EOProduct:
|
|
|
136
141
|
if key != "geometry"
|
|
137
142
|
and value != NOT_MAPPED
|
|
138
143
|
and NOT_AVAILABLE not in str(value)
|
|
144
|
+
and not key.startswith("_")
|
|
145
|
+
}
|
|
146
|
+
common_stac_properties = {
|
|
147
|
+
key: self.properties[key]
|
|
148
|
+
for key in sorted(self.properties)
|
|
149
|
+
if ":" not in key
|
|
150
|
+
}
|
|
151
|
+
extensions_stac_properties = {
|
|
152
|
+
key: self.properties[key] for key in sorted(self.properties) if ":" in key
|
|
139
153
|
}
|
|
154
|
+
self.properties = common_stac_properties | extensions_stac_properties
|
|
155
|
+
|
|
140
156
|
if "geometry" not in properties or (
|
|
141
157
|
(
|
|
142
158
|
properties["geometry"] == NOT_AVAILABLE
|
|
143
159
|
or properties["geometry"] == NOT_MAPPED
|
|
144
160
|
)
|
|
145
|
-
and "
|
|
161
|
+
and "eodag:default_geometry" not in properties
|
|
146
162
|
):
|
|
147
163
|
raise MisconfiguredError(
|
|
148
164
|
f"No geometry available to build EOProduct(id={properties.get('id')}, provider={provider})"
|
|
149
165
|
)
|
|
150
166
|
elif not properties["geometry"] or properties["geometry"] == NOT_AVAILABLE:
|
|
151
|
-
product_geometry = properties.pop(
|
|
167
|
+
product_geometry = properties.pop(
|
|
168
|
+
"eodag:default_geometry", DEFAULT_GEOMETRY
|
|
169
|
+
)
|
|
152
170
|
else:
|
|
153
171
|
product_geometry = properties["geometry"]
|
|
154
172
|
|
|
@@ -192,9 +210,9 @@ class EOProduct:
|
|
|
192
210
|
"id": self.properties["id"],
|
|
193
211
|
"assets": self.assets.as_dict(),
|
|
194
212
|
"properties": {
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"
|
|
213
|
+
"eodag:collection": self.collection,
|
|
214
|
+
"eodag:provider": self.provider,
|
|
215
|
+
"eodag:search_intersection": search_intersection,
|
|
198
216
|
**{
|
|
199
217
|
key: value
|
|
200
218
|
for key, value in self.properties.items()
|
|
@@ -213,16 +231,22 @@ class EOProduct:
|
|
|
213
231
|
:param feature: The representation of a :class:`~eodag.api.product._product.EOProduct`
|
|
214
232
|
as a Python dict
|
|
215
233
|
:returns: An instance of :class:`~eodag.api.product._product.EOProduct`
|
|
234
|
+
:raises: :class:`~eodag.utils.exceptions.ValidationError`
|
|
216
235
|
"""
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
236
|
+
try:
|
|
237
|
+
properties = feature["properties"]
|
|
238
|
+
properties["geometry"] = feature["geometry"]
|
|
239
|
+
properties["id"] = feature["id"]
|
|
240
|
+
provider = properties.pop("eodag:provider")
|
|
241
|
+
collection = properties.pop("eodag:collection")
|
|
242
|
+
search_intersection = properties.pop("eodag:search_intersection")
|
|
243
|
+
except KeyError as e:
|
|
244
|
+
raise ValidationError(
|
|
245
|
+
"Key %s not found in geojson, make sure it comes from a serialized SearchResult"
|
|
246
|
+
% e.args[0]
|
|
247
|
+
) from e
|
|
248
|
+
obj = cls(provider, properties, collection=collection)
|
|
249
|
+
obj.search_intersection = geometry.shape(search_intersection)
|
|
226
250
|
obj.assets = AssetsDict(obj, feature.get("assets", {}))
|
|
227
251
|
return obj
|
|
228
252
|
|
|
@@ -252,12 +276,12 @@ class EOProduct:
|
|
|
252
276
|
download_plugin = plugins_manager.get_download_plugin(self)
|
|
253
277
|
if len(self.assets) > 0:
|
|
254
278
|
matching_url = next(iter(self.assets.values()))["href"]
|
|
255
|
-
elif self.properties.get("
|
|
256
|
-
matching_url = self.properties.get(
|
|
257
|
-
"
|
|
258
|
-
)
|
|
279
|
+
elif self.properties.get("order:status") != ONLINE_STATUS:
|
|
280
|
+
matching_url = self.properties.get(
|
|
281
|
+
"eodag:order_link"
|
|
282
|
+
) or self.properties.get("eodag:download_link")
|
|
259
283
|
else:
|
|
260
|
-
matching_url = self.properties.get("
|
|
284
|
+
matching_url = self.properties.get("eodag:download_link")
|
|
261
285
|
|
|
262
286
|
try:
|
|
263
287
|
auth_plugin = next(
|
|
@@ -424,7 +448,7 @@ class EOProduct:
|
|
|
424
448
|
:raises HTTPError: If the HTTP request to the quicklook URL fails.
|
|
425
449
|
"""
|
|
426
450
|
with requests.get(
|
|
427
|
-
self.properties["quicklook"],
|
|
451
|
+
self.properties["eodag:quicklook"],
|
|
428
452
|
stream=True,
|
|
429
453
|
auth=auth,
|
|
430
454
|
headers=USER_AGENT,
|
|
@@ -468,17 +492,19 @@ class EOProduct:
|
|
|
468
492
|
def format_quicklook_address() -> None:
|
|
469
493
|
"""If the quicklook address is a Python format string, resolve the
|
|
470
494
|
formatting with the properties of the product."""
|
|
471
|
-
fstrmatch = re.match(r".*{.+}*.*", self.properties["quicklook"])
|
|
495
|
+
fstrmatch = re.match(r".*{.+}*.*", self.properties["eodag:quicklook"])
|
|
472
496
|
if fstrmatch:
|
|
473
|
-
self.properties["quicklook"]
|
|
474
|
-
|
|
497
|
+
self.properties["eodag:quicklook"] = format_string(
|
|
498
|
+
None,
|
|
499
|
+
self.properties["eodag:quicklook"],
|
|
500
|
+
**{
|
|
475
501
|
prop_key: prop_val
|
|
476
502
|
for prop_key, prop_val in self.properties.items()
|
|
477
|
-
if prop_key != "quicklook"
|
|
478
|
-
}
|
|
503
|
+
if prop_key != "eodag:quicklook"
|
|
504
|
+
},
|
|
479
505
|
)
|
|
480
506
|
|
|
481
|
-
if self.properties.get("quicklook") is None:
|
|
507
|
+
if self.properties.get("eodag:quicklook") is None:
|
|
482
508
|
logger.warning(
|
|
483
509
|
"Missing information to retrieve quicklook for EO product: %s",
|
|
484
510
|
self.properties["id"],
|
|
@@ -521,11 +547,11 @@ class EOProduct:
|
|
|
521
547
|
# it is a HTTP URL. If not, we assume it is a base64 string, in which case
|
|
522
548
|
# we just decode the content, write it into the quicklook_file and return it.
|
|
523
549
|
if not (
|
|
524
|
-
self.properties["quicklook"].startswith("http")
|
|
525
|
-
or self.properties["quicklook"].startswith("https")
|
|
550
|
+
self.properties["eodag:quicklook"].startswith("http")
|
|
551
|
+
or self.properties["eodag:quicklook"].startswith("https")
|
|
526
552
|
):
|
|
527
553
|
with open(quicklook_file, "wb") as fd:
|
|
528
|
-
img = self.properties["quicklook"].encode("ascii")
|
|
554
|
+
img = self.properties["eodag:quicklook"].encode("ascii")
|
|
529
555
|
fd.write(base64.b64decode(img))
|
|
530
556
|
return quicklook_file
|
|
531
557
|
|
|
@@ -588,7 +614,9 @@ class EOProduct:
|
|
|
588
614
|
return NoDriver()
|
|
589
615
|
|
|
590
616
|
def _repr_html_(self):
|
|
591
|
-
thumbnail = self.properties.get("thumbnail")
|
|
617
|
+
thumbnail = self.properties.get("eodag:thumbnail") or self.properties.get(
|
|
618
|
+
"eodag:quicklook"
|
|
619
|
+
)
|
|
592
620
|
thumbnail_html = (
|
|
593
621
|
f"<img src='{thumbnail}' width=100 alt='thumbnail'/>"
|
|
594
622
|
if thumbnail and not thumbnail.startswith("s3")
|
|
@@ -608,13 +636,13 @@ class EOProduct:
|
|
|
608
636
|
<td style='text-align: left; vertical-align: top;'>
|
|
609
637
|
{dict_to_html_table({
|
|
610
638
|
"provider": self.provider,
|
|
611
|
-
"
|
|
639
|
+
"collection": self.collection,
|
|
612
640
|
"properties["id"]": self.properties.get('id'),
|
|
613
|
-
"properties["
|
|
614
|
-
'
|
|
641
|
+
"properties["start_datetime"]": self.properties.get(
|
|
642
|
+
'start_datetime'
|
|
615
643
|
),
|
|
616
|
-
"properties["
|
|
617
|
-
'
|
|
644
|
+
"properties["end_datetime"]": self.properties.get(
|
|
645
|
+
'end_datetime'
|
|
618
646
|
),
|
|
619
647
|
}, brackets=False)}
|
|
620
648
|
<details><summary style='color: grey; margin-top: 10px;'>properties: ({len(
|
|
@@ -56,7 +56,7 @@ DRIVERS: list[DriverCriteria] = [
|
|
|
56
56
|
{
|
|
57
57
|
"criteria": [
|
|
58
58
|
lambda prod: True
|
|
59
|
-
if (prod.
|
|
59
|
+
if (prod.collection or "").startswith("S2_MSI_")
|
|
60
60
|
else False
|
|
61
61
|
],
|
|
62
62
|
"driver": Sentinel2Driver(),
|
|
@@ -64,7 +64,7 @@ DRIVERS: list[DriverCriteria] = [
|
|
|
64
64
|
{
|
|
65
65
|
"criteria": [
|
|
66
66
|
lambda prod: True
|
|
67
|
-
if (prod.
|
|
67
|
+
if (prod.collection or "").startswith("S1_SAR_")
|
|
68
68
|
else False
|
|
69
69
|
],
|
|
70
70
|
"driver": Sentinel1Driver(),
|
|
@@ -90,9 +90,7 @@ LEGACY_DRIVERS: list[DriverCriteria] = [
|
|
|
90
90
|
},
|
|
91
91
|
{
|
|
92
92
|
"criteria": [
|
|
93
|
-
lambda prod: True
|
|
94
|
-
if getattr(prod, "product_type") == "S2_MSI_L1C"
|
|
95
|
-
else False
|
|
93
|
+
lambda prod: True if getattr(prod, "collection") == "S2_MSI_L1C" else False
|
|
96
94
|
],
|
|
97
95
|
"driver": Sentinel2L1C_cube(),
|
|
98
96
|
},
|
|
@@ -21,8 +21,6 @@ import logging
|
|
|
21
21
|
import re
|
|
22
22
|
from typing import TYPE_CHECKING, Optional, TypedDict
|
|
23
23
|
|
|
24
|
-
from eodag.utils import _deprecated
|
|
25
|
-
|
|
26
24
|
if TYPE_CHECKING:
|
|
27
25
|
from eodag.api.product import EOProduct
|
|
28
26
|
|
|
@@ -82,25 +80,10 @@ class DatasetDriver(metaclass=type):
|
|
|
82
80
|
logger.debug(f"No key & roles could be guessed for {href}")
|
|
83
81
|
return None, None
|
|
84
82
|
|
|
85
|
-
@_deprecated(reason="Method used by deprecated get_data", version="3.1.0")
|
|
86
|
-
def get_data_address(self, eo_product: EOProduct, band: str) -> str:
|
|
87
|
-
"""Retrieve the address of the dataset represented by `eo_product`.
|
|
88
|
-
|
|
89
|
-
:param eo_product: The product whom underlying dataset address is to be retrieved
|
|
90
|
-
:param band: The band to retrieve (e.g: 'B01')
|
|
91
|
-
:returns: An address for the dataset
|
|
92
|
-
:raises: :class:`~eodag.utils.exceptions.AddressNotFound`
|
|
93
|
-
:raises: :class:`~eodag.utils.exceptions.UnsupportedDatasetAddressScheme`
|
|
94
|
-
|
|
95
|
-
.. deprecated:: 3.1.0
|
|
96
|
-
Method used by deprecated :meth:`~eodag_cube.api.product._product.EOProduct.get_data`
|
|
97
|
-
"""
|
|
98
|
-
raise NotImplementedError
|
|
99
|
-
|
|
100
83
|
|
|
101
84
|
class NoDriver(DatasetDriver):
|
|
102
85
|
"""A default :attr:`~eodag.api.product.drivers.base.DatasetDriver.legacy` driver that does not implement any of the
|
|
103
|
-
methods it should implement, used for all
|
|
86
|
+
methods it should implement, used for all collections for which the deprecated
|
|
104
87
|
:meth:`~eodag_cube.api.product._product.EOProduct.get_data` method is not implemented. Expect a
|
|
105
88
|
:exc:`NotImplementedError` when trying to get the data in that case.
|
|
106
89
|
"""
|