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/plugins/download/http.py
CHANGED
|
@@ -92,7 +92,6 @@ if TYPE_CHECKING:
|
|
|
92
92
|
from eodag.api.product import Asset, EOProduct # type: ignore
|
|
93
93
|
from eodag.api.search_result import SearchResult
|
|
94
94
|
from eodag.config import PluginConfig
|
|
95
|
-
from eodag.types import S3SessionKwargs
|
|
96
95
|
from eodag.types.download_args import DownloadConf
|
|
97
96
|
from eodag.utils import DownloadedCallback, Unpack
|
|
98
97
|
|
|
@@ -119,7 +118,8 @@ class HTTPDownload(Download):
|
|
|
119
118
|
default: ``1``
|
|
120
119
|
* :attr:`~eodag.config.PluginConfig.flatten_top_dirs` (``bool``): if the directory structure should be
|
|
121
120
|
flattened; default: ``True``
|
|
122
|
-
* :attr:`~eodag.config.PluginConfig.ignore_assets` (``bool``): ignore assets and download using
|
|
121
|
+
* :attr:`~eodag.config.PluginConfig.ignore_assets` (``bool``): ignore assets and download using
|
|
122
|
+
eodag:download_link;
|
|
123
123
|
default: ``False``
|
|
124
124
|
* :attr:`~eodag.config.PluginConfig.timeout` (``int``): time to wait until request timeout in seconds;
|
|
125
125
|
default: ``5``
|
|
@@ -128,8 +128,8 @@ class HTTPDownload(Download):
|
|
|
128
128
|
* :attr:`~eodag.config.PluginConfig.no_auth_download` (``bool``): if the download should be done without
|
|
129
129
|
authentication; default: ``True``
|
|
130
130
|
* :attr:`~eodag.config.PluginConfig.order_enabled` (``bool``): if the product has to be ordered to download it;
|
|
131
|
-
if this parameter is set to true, a mapping for
|
|
132
|
-
the search plugin used for the provider; default: ``False``
|
|
131
|
+
if this parameter is set to true, a mapping for ``eodag:order_link`` has to be added to the metadata mapping
|
|
132
|
+
of the search plugin used for the provider; default: ``False``
|
|
133
133
|
* :attr:`~eodag.config.PluginConfig.order_method` (``str``): HTTP request method for the order request (``GET``
|
|
134
134
|
or ``POST``); default: ``GET``
|
|
135
135
|
* :attr:`~eodag.config.PluginConfig.order_headers` (``[dict[str, str]]``): headers to be added to the order
|
|
@@ -140,9 +140,9 @@ class HTTPDownload(Download):
|
|
|
140
140
|
* :attr:`~eodag.config.PluginConfig.order_status` (:class:`~eodag.config.PluginConfig.OrderStatus`):
|
|
141
141
|
configuration to handle the order status; contains information which method to use, how the response data is
|
|
142
142
|
interpreted, which status corresponds to success, ordered and error and what should be done on success.
|
|
143
|
-
* :attr:`~eodag.config.PluginConfig.products` (``dict[str, dict[str, Any]``):
|
|
144
|
-
keys are the
|
|
145
|
-
:attr:`~eodag.config.PluginConfig.extract` to overwrite the provider config for a specific
|
|
143
|
+
* :attr:`~eodag.config.PluginConfig.products` (``dict[str, dict[str, Any]``): collection specific config; the
|
|
144
|
+
keys are the collections, the values are dictionaries which can contain the key
|
|
145
|
+
:attr:`~eodag.config.PluginConfig.extract` to overwrite the provider config for a specific collection
|
|
146
146
|
|
|
147
147
|
"""
|
|
148
148
|
|
|
@@ -158,12 +158,12 @@ class HTTPDownload(Download):
|
|
|
158
158
|
|
|
159
159
|
"""Send product order request.
|
|
160
160
|
|
|
161
|
-
It will be executed once before the download retry loop, if the product is
|
|
162
|
-
and has
|
|
161
|
+
It will be executed once before the download retry loop, if the product is orderable
|
|
162
|
+
and has ``eodag:order_link`` in its properties.
|
|
163
163
|
Product ordering can be configured using the following download plugin parameters:
|
|
164
164
|
|
|
165
165
|
- :attr:`~eodag.config.PluginConfig.order_enabled`: Wether order is enabled or not (may not use this method
|
|
166
|
-
if no
|
|
166
|
+
if no ``eodag:order_link`` exists)
|
|
167
167
|
|
|
168
168
|
- :attr:`~eodag.config.PluginConfig.order_method`: (optional) HTTP request method, GET (default) or POST
|
|
169
169
|
|
|
@@ -174,14 +174,14 @@ class HTTPDownload(Download):
|
|
|
174
174
|
|
|
175
175
|
Product properties used for order:
|
|
176
176
|
|
|
177
|
-
- **
|
|
177
|
+
- **eodag:order_link**: order request URL
|
|
178
178
|
|
|
179
179
|
:param product: The EO product to order
|
|
180
180
|
:param auth: (optional) authenticated object
|
|
181
181
|
:param kwargs: download additional kwargs
|
|
182
182
|
:returns: the returned json status response
|
|
183
183
|
"""
|
|
184
|
-
product.properties["
|
|
184
|
+
product.properties["order:status"] = STAGING_STATUS
|
|
185
185
|
|
|
186
186
|
order_method = getattr(self.config, "order_method", "GET").upper()
|
|
187
187
|
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
@@ -192,7 +192,7 @@ class HTTPDownload(Download):
|
|
|
192
192
|
order_kwargs: OrderKwargs = {}
|
|
193
193
|
if order_method == "POST":
|
|
194
194
|
# separate url & parameters
|
|
195
|
-
parts = urlparse(str(product.properties["
|
|
195
|
+
parts = urlparse(str(product.properties["eodag:order_link"]))
|
|
196
196
|
query_dict = {}
|
|
197
197
|
# `parts.query` may be a JSON with query strings as one of values. If `parse_qs` is executed as first step,
|
|
198
198
|
# the resulting `query_dict` would be erroneous.
|
|
@@ -205,7 +205,7 @@ class HTTPDownload(Download):
|
|
|
205
205
|
if query_dict:
|
|
206
206
|
order_kwargs["json"] = query_dict
|
|
207
207
|
else:
|
|
208
|
-
order_url = product.properties["
|
|
208
|
+
order_url = product.properties["eodag:order_link"]
|
|
209
209
|
order_kwargs = {}
|
|
210
210
|
|
|
211
211
|
headers = {**getattr(self.config, "order_headers", {}), **USER_AGENT}
|
|
@@ -224,7 +224,7 @@ class HTTPDownload(Download):
|
|
|
224
224
|
response.raise_for_status()
|
|
225
225
|
ordered_message = response.text
|
|
226
226
|
logger.debug(ordered_message)
|
|
227
|
-
product.properties["
|
|
227
|
+
product.properties["order:status"] = STAGING_STATUS
|
|
228
228
|
except RequestException as e:
|
|
229
229
|
self._check_auth_exception(e)
|
|
230
230
|
msg = f"{product.properties['title']} could not be ordered"
|
|
@@ -269,16 +269,16 @@ class HTTPDownload(Download):
|
|
|
269
269
|
# the job id becomes the product id for EcmwfSearch products
|
|
270
270
|
if "ORDERABLE" in product.properties.get("id", ""):
|
|
271
271
|
product.properties["id"] = product.properties.get(
|
|
272
|
-
"
|
|
272
|
+
"eodag:order_id", product.properties["id"]
|
|
273
273
|
)
|
|
274
274
|
product.properties["title"] = (
|
|
275
|
-
(product.
|
|
275
|
+
(product.collection or product.provider).upper()
|
|
276
276
|
+ "_"
|
|
277
277
|
+ product.properties["id"]
|
|
278
278
|
)
|
|
279
|
-
if "
|
|
279
|
+
if "eodag:download_link" in product.properties:
|
|
280
280
|
product.remote_location = product.location = product.properties[
|
|
281
|
-
"
|
|
281
|
+
"eodag:download_link"
|
|
282
282
|
]
|
|
283
283
|
logger.debug(f"Product location updated to {product.location}")
|
|
284
284
|
|
|
@@ -298,7 +298,7 @@ class HTTPDownload(Download):
|
|
|
298
298
|
|
|
299
299
|
Product properties used for order status:
|
|
300
300
|
|
|
301
|
-
- **
|
|
301
|
+
- **eodag:status_link**: order status request URL
|
|
302
302
|
|
|
303
303
|
:param product: The ordered EO product
|
|
304
304
|
:param auth: (optional) authenticated object
|
|
@@ -355,14 +355,14 @@ class HTTPDownload(Download):
|
|
|
355
355
|
|
|
356
356
|
if status_request_method == "POST":
|
|
357
357
|
# separate url & parameters
|
|
358
|
-
parts = urlparse(str(product.properties["
|
|
358
|
+
parts = urlparse(str(product.properties["eodag:status_link"]))
|
|
359
359
|
status_url = parts._replace(query="").geturl()
|
|
360
360
|
query_dict = parse_qs(parts.query)
|
|
361
361
|
if not query_dict and parts.query:
|
|
362
362
|
query_dict = geojson.loads(parts.query)
|
|
363
363
|
json_data = query_dict if query_dict else None
|
|
364
364
|
else:
|
|
365
|
-
status_url = product.properties["
|
|
365
|
+
status_url = product.properties["eodag:status_link"]
|
|
366
366
|
json_data = None
|
|
367
367
|
|
|
368
368
|
# check header for success before full status request
|
|
@@ -443,8 +443,8 @@ class HTTPDownload(Download):
|
|
|
443
443
|
)
|
|
444
444
|
|
|
445
445
|
# display progress percentage
|
|
446
|
-
if "
|
|
447
|
-
status_percent = str(status_dict["
|
|
446
|
+
if "eodag:order_percent" in status_dict:
|
|
447
|
+
status_percent = str(status_dict["eodag:order_percent"])
|
|
448
448
|
if status_percent.isdigit():
|
|
449
449
|
status_percent += "%"
|
|
450
450
|
logger.info(
|
|
@@ -455,9 +455,11 @@ class HTTPDownload(Download):
|
|
|
455
455
|
{k: v for k, v in status_dict.items() if v != NOT_AVAILABLE}
|
|
456
456
|
)
|
|
457
457
|
|
|
458
|
-
product.properties["
|
|
458
|
+
product.properties["eodag:order_status"] = status_dict.get(
|
|
459
|
+
"eodag:order_status"
|
|
460
|
+
)
|
|
459
461
|
|
|
460
|
-
status_message = status_dict.get("
|
|
462
|
+
status_message = status_dict.get("eodag:order_message")
|
|
461
463
|
|
|
462
464
|
# handle status error
|
|
463
465
|
errors: dict[str, Any] = status_config.get("error", {})
|
|
@@ -466,16 +468,18 @@ class HTTPDownload(Download):
|
|
|
466
468
|
f"Provider {product.provider} returned: {status_dict.get('error_message', status_message)}"
|
|
467
469
|
)
|
|
468
470
|
|
|
469
|
-
product.properties["
|
|
471
|
+
product.properties["order:status"] = STAGING_STATUS
|
|
470
472
|
|
|
471
|
-
success_status: dict[str, Any] = status_config.get("success", {}).get(
|
|
473
|
+
success_status: dict[str, Any] = status_config.get("success", {}).get(
|
|
474
|
+
"eodag:order_status"
|
|
475
|
+
)
|
|
472
476
|
# if not success
|
|
473
|
-
if (
|
|
474
|
-
|
|
475
|
-
):
|
|
477
|
+
if (
|
|
478
|
+
success_status and success_status != status_dict.get("eodag:order_status")
|
|
479
|
+
) or (success_code and success_code != response.status_code):
|
|
476
480
|
return None
|
|
477
481
|
|
|
478
|
-
product.properties["
|
|
482
|
+
product.properties["order:status"] = ONLINE_STATUS
|
|
479
483
|
|
|
480
484
|
if not config_on_success:
|
|
481
485
|
# Nothing left to do
|
|
@@ -483,9 +487,13 @@ class HTTPDownload(Download):
|
|
|
483
487
|
|
|
484
488
|
# need search on success ?
|
|
485
489
|
if config_on_success.get("need_search"):
|
|
486
|
-
logger.debug(
|
|
490
|
+
logger.debug(
|
|
491
|
+
f"Search for new location: {product.properties['eodag:search_link']}"
|
|
492
|
+
)
|
|
487
493
|
try:
|
|
488
|
-
response = _request(
|
|
494
|
+
response = _request(
|
|
495
|
+
product.properties["eodag:search_link"], timeout=timeout
|
|
496
|
+
)
|
|
489
497
|
except RequestException as e:
|
|
490
498
|
logger.warning(
|
|
491
499
|
"%s order status could not be checked, request returned %s",
|
|
@@ -503,11 +511,7 @@ class HTTPDownload(Download):
|
|
|
503
511
|
|
|
504
512
|
on_success_mm_querypath = (
|
|
505
513
|
# append product.properties as input for on success response parsing
|
|
506
|
-
mtd_cfg_as_conversion_and_querypath(
|
|
507
|
-
dict(
|
|
508
|
-
{k: str(v) for k, v in product.properties.items()}, **on_success_mm
|
|
509
|
-
),
|
|
510
|
-
)
|
|
514
|
+
mtd_cfg_as_conversion_and_querypath(on_success_mm)
|
|
511
515
|
if on_success_mm
|
|
512
516
|
else {}
|
|
513
517
|
)
|
|
@@ -530,7 +534,7 @@ class HTTPDownload(Download):
|
|
|
530
534
|
if len(results) != 1:
|
|
531
535
|
raise DownloadError(
|
|
532
536
|
"Could not get a single result after order success for "
|
|
533
|
-
f"{product.properties['
|
|
537
|
+
f"{product.properties['eodag:search_link']} request. "
|
|
534
538
|
f"Please search and download {product} again"
|
|
535
539
|
)
|
|
536
540
|
assert isinstance(results, list), "results must be in a list"
|
|
@@ -581,9 +585,9 @@ class HTTPDownload(Download):
|
|
|
581
585
|
|
|
582
586
|
# update product
|
|
583
587
|
product.properties.update(properties_update)
|
|
584
|
-
if "
|
|
588
|
+
if "eodag:download_link" in properties_update:
|
|
585
589
|
product.location = product.remote_location = product.properties[
|
|
586
|
-
"
|
|
590
|
+
"eodag:download_link"
|
|
587
591
|
]
|
|
588
592
|
else:
|
|
589
593
|
self.order_response_process(response, product)
|
|
@@ -591,7 +595,7 @@ class HTTPDownload(Download):
|
|
|
591
595
|
def download(
|
|
592
596
|
self,
|
|
593
597
|
product: EOProduct,
|
|
594
|
-
auth: Optional[Union[AuthBase,
|
|
598
|
+
auth: Optional[Union[AuthBase, S3ServiceResource]] = None,
|
|
595
599
|
progress_callback: Optional[ProgressCallback] = None,
|
|
596
600
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
597
601
|
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
@@ -677,7 +681,7 @@ class HTTPDownload(Download):
|
|
|
677
681
|
raise DownloadError(f"product {product.properties['id']} is empty")
|
|
678
682
|
else:
|
|
679
683
|
# make sure storage status is online
|
|
680
|
-
product.properties["
|
|
684
|
+
product.properties["order:status"] = ONLINE_STATUS
|
|
681
685
|
|
|
682
686
|
return path
|
|
683
687
|
else:
|
|
@@ -720,14 +724,14 @@ class HTTPDownload(Download):
|
|
|
720
724
|
stream_size = int(self.stream.headers.get("content-length", 0))
|
|
721
725
|
if (
|
|
722
726
|
stream_size == 0
|
|
723
|
-
and "
|
|
724
|
-
and product.properties["
|
|
727
|
+
and "order:status" in product.properties
|
|
728
|
+
and product.properties["order:status"] != ONLINE_STATUS
|
|
725
729
|
):
|
|
726
730
|
raise NotAvailableError(
|
|
727
731
|
"%s(initially %s) ordered, got: %s"
|
|
728
732
|
% (
|
|
729
733
|
product.properties["title"],
|
|
730
|
-
product.properties["
|
|
734
|
+
product.properties["order:status"],
|
|
731
735
|
self.stream.reason,
|
|
732
736
|
)
|
|
733
737
|
)
|
|
@@ -755,7 +759,7 @@ class HTTPDownload(Download):
|
|
|
755
759
|
def _stream_download_dict(
|
|
756
760
|
self,
|
|
757
761
|
product: EOProduct,
|
|
758
|
-
auth: Optional[Union[AuthBase,
|
|
762
|
+
auth: Optional[Union[AuthBase, S3ServiceResource]] = None,
|
|
759
763
|
byte_range: tuple[Optional[int], Optional[int]] = (None, None),
|
|
760
764
|
compress: Literal["zip", "raw", "auto"] = "auto",
|
|
761
765
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
@@ -882,7 +886,7 @@ class HTTPDownload(Download):
|
|
|
882
886
|
e.response.text.strip() if e is not None and e.response is not None else ""
|
|
883
887
|
)
|
|
884
888
|
# product not available
|
|
885
|
-
if product.properties.get("
|
|
889
|
+
if product.properties.get("order:status", ONLINE_STATUS) != ONLINE_STATUS:
|
|
886
890
|
msg = (
|
|
887
891
|
ordered_message
|
|
888
892
|
if ordered_message and not response_text
|
|
@@ -893,7 +897,7 @@ class HTTPDownload(Download):
|
|
|
893
897
|
"%s(initially %s) requested, returned: %s"
|
|
894
898
|
% (
|
|
895
899
|
product.properties["title"],
|
|
896
|
-
product.properties["
|
|
900
|
+
product.properties["order:status"],
|
|
897
901
|
msg,
|
|
898
902
|
)
|
|
899
903
|
)
|
|
@@ -915,22 +919,22 @@ class HTTPDownload(Download):
|
|
|
915
919
|
auth: Optional[AuthBase],
|
|
916
920
|
) -> None:
|
|
917
921
|
if (
|
|
918
|
-
"
|
|
919
|
-
and product.properties.get("
|
|
920
|
-
and not product.properties.get("
|
|
922
|
+
"eodag:order_link" in product.properties
|
|
923
|
+
and product.properties.get("order:status") == OFFLINE_STATUS
|
|
924
|
+
and not product.properties.get("eodag:order_status")
|
|
921
925
|
):
|
|
922
926
|
self._order(product=product, auth=auth)
|
|
923
927
|
|
|
924
928
|
if (
|
|
925
|
-
product.properties.get("
|
|
926
|
-
and product.properties.get("
|
|
929
|
+
product.properties.get("eodag:status_link")
|
|
930
|
+
and product.properties.get("order:status") != ONLINE_STATUS
|
|
927
931
|
):
|
|
928
932
|
self._order_status(product=product, auth=auth)
|
|
929
933
|
|
|
930
934
|
def order(
|
|
931
935
|
self,
|
|
932
936
|
product: EOProduct,
|
|
933
|
-
auth: Optional[Union[AuthBase,
|
|
937
|
+
auth: Optional[Union[AuthBase, S3ServiceResource]] = None,
|
|
934
938
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
|
935
939
|
timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
|
|
936
940
|
) -> None:
|
|
@@ -982,7 +986,7 @@ class HTTPDownload(Download):
|
|
|
982
986
|
)
|
|
983
987
|
|
|
984
988
|
req_method = (
|
|
985
|
-
product.properties.get("
|
|
989
|
+
product.properties.get("eodag:download_method", "").lower()
|
|
986
990
|
or getattr(self.config, "method", "GET").lower()
|
|
987
991
|
)
|
|
988
992
|
url = product.remote_location
|
|
@@ -1041,7 +1045,7 @@ class HTTPDownload(Download):
|
|
|
1041
1045
|
).get(
|
|
1042
1046
|
"http_code"
|
|
1043
1047
|
):
|
|
1044
|
-
product.properties["
|
|
1048
|
+
product.properties["order:status"] = "ORDERED"
|
|
1045
1049
|
self._process_exception(None, product, ordered_message)
|
|
1046
1050
|
stream_size = self._check_stream_size(product) or None
|
|
1047
1051
|
|
|
@@ -1096,9 +1100,7 @@ class HTTPDownload(Download):
|
|
|
1096
1100
|
assets_common_subdir = os.path.commonpath(asset_rel_paths_list)
|
|
1097
1101
|
|
|
1098
1102
|
# product conf overrides provider conf for "flatten_top_dirs"
|
|
1099
|
-
product_conf = getattr(self.config, "products", {}).get(
|
|
1100
|
-
product.product_type, {}
|
|
1101
|
-
)
|
|
1103
|
+
product_conf = getattr(self.config, "products", {}).get(product.collection, {})
|
|
1102
1104
|
flatten_top_dirs = product_conf.get(
|
|
1103
1105
|
"flatten_top_dirs", getattr(self.config, "flatten_top_dirs", True)
|
|
1104
1106
|
)
|
|
@@ -1246,9 +1248,7 @@ class HTTPDownload(Download):
|
|
|
1246
1248
|
os.makedirs(fs_dir_path)
|
|
1247
1249
|
|
|
1248
1250
|
# product conf overrides provider conf for "flatten_top_dirs"
|
|
1249
|
-
product_conf = getattr(self.config, "products", {}).get(
|
|
1250
|
-
product.product_type, {}
|
|
1251
|
-
)
|
|
1251
|
+
product_conf = getattr(self.config, "products", {}).get(product.collection, {})
|
|
1252
1252
|
flatten_top_dirs = product_conf.get(
|
|
1253
1253
|
"flatten_top_dirs", getattr(self.config, "flatten_top_dirs", True)
|
|
1254
1254
|
)
|
|
@@ -1413,7 +1413,7 @@ class HTTPDownload(Download):
|
|
|
1413
1413
|
def download_all(
|
|
1414
1414
|
self,
|
|
1415
1415
|
products: SearchResult,
|
|
1416
|
-
auth: Optional[Union[AuthBase,
|
|
1416
|
+
auth: Optional[Union[AuthBase, S3ServiceResource]] = None,
|
|
1417
1417
|
downloaded_callback: Optional[DownloadedCallback] = None,
|
|
1418
1418
|
progress_callback: Optional[ProgressCallback] = None,
|
|
1419
1419
|
wait: float = DEFAULT_DOWNLOAD_WAIT,
|
eodag/plugins/manager.py
CHANGED
|
@@ -36,7 +36,7 @@ from eodag.plugins.base import EODAGPluginMount
|
|
|
36
36
|
from eodag.plugins.crunch.base import Crunch
|
|
37
37
|
from eodag.plugins.download.base import Download
|
|
38
38
|
from eodag.plugins.search.base import Search
|
|
39
|
-
from eodag.utils import
|
|
39
|
+
from eodag.utils import GENERIC_COLLECTION, deepcopy, dict_md5sum
|
|
40
40
|
from eodag.utils.exceptions import (
|
|
41
41
|
AuthenticationError,
|
|
42
42
|
MisconfiguredError,
|
|
@@ -50,7 +50,6 @@ if TYPE_CHECKING:
|
|
|
50
50
|
from eodag.api.product import EOProduct
|
|
51
51
|
from eodag.config import PluginConfig, ProviderConfig
|
|
52
52
|
from eodag.plugins.base import PluginTopic
|
|
53
|
-
from eodag.types import S3SessionKwargs
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
logger = logging.getLogger("eodag.plugins.manager")
|
|
@@ -74,7 +73,7 @@ class PluginManager:
|
|
|
74
73
|
|
|
75
74
|
supported_topics = set(PLUGINS_TOPICS_KEYS)
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
collection_to_provider_config_map: dict[str, list[ProviderConfig]]
|
|
78
77
|
|
|
79
78
|
skipped_plugins: list[str]
|
|
80
79
|
|
|
@@ -134,12 +133,12 @@ class PluginManager:
|
|
|
134
133
|
if providers_config is not None:
|
|
135
134
|
self.providers_config = providers_config
|
|
136
135
|
|
|
137
|
-
self.
|
|
136
|
+
self.build_collection_to_provider_config_map()
|
|
138
137
|
self._built_plugins_cache: dict[tuple[str, str, str], Any] = {}
|
|
139
138
|
|
|
140
|
-
def
|
|
141
|
-
"""Build mapping conf between
|
|
142
|
-
self.
|
|
139
|
+
def build_collection_to_provider_config_map(self) -> None:
|
|
140
|
+
"""Build mapping conf between collections and providers"""
|
|
141
|
+
self.collection_to_provider_config_map = {}
|
|
143
142
|
for provider in list(self.providers_config):
|
|
144
143
|
provider_config = self.providers_config[provider]
|
|
145
144
|
if not hasattr(provider_config, "products") or not provider_config.products:
|
|
@@ -154,26 +153,26 @@ class PluginManager:
|
|
|
154
153
|
if getattr(provider_config, "priority", None) is None:
|
|
155
154
|
self.providers_config[provider].priority = provider_config.priority = 0
|
|
156
155
|
|
|
157
|
-
for
|
|
158
|
-
|
|
159
|
-
self.
|
|
160
|
-
|
|
156
|
+
for collection in provider_config.products:
|
|
157
|
+
collection_providers = (
|
|
158
|
+
self.collection_to_provider_config_map.setdefault( # noqa
|
|
159
|
+
collection, []
|
|
161
160
|
)
|
|
162
161
|
)
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
collection_providers.append(provider_config)
|
|
163
|
+
collection_providers.sort(key=attrgetter("priority"), reverse=True)
|
|
165
164
|
|
|
166
165
|
def get_search_plugins(
|
|
167
|
-
self,
|
|
166
|
+
self, collection: Optional[str] = None, provider: Optional[str] = None
|
|
168
167
|
) -> Iterator[Union[Search, Api]]:
|
|
169
|
-
"""Build and return all the search plugins supporting the given
|
|
168
|
+
"""Build and return all the search plugins supporting the given collection,
|
|
170
169
|
ordered by highest priority, or the search plugin of the given provider
|
|
171
170
|
|
|
172
|
-
:param
|
|
171
|
+
:param collection: (optional) The collection that the constructed plugins
|
|
173
172
|
must support
|
|
174
173
|
:param provider: (optional) The provider or the provider group on which to get
|
|
175
174
|
the search plugins
|
|
176
|
-
:returns: All the plugins supporting the
|
|
175
|
+
:returns: All the plugins supporting the collection, one by one (a generator
|
|
177
176
|
object)
|
|
178
177
|
or :class:`~eodag.plugins.download.Api`)
|
|
179
178
|
:raises: :class:`~eodag.utils.exceptions.UnsupportedProvider`
|
|
@@ -196,13 +195,13 @@ class PluginManager:
|
|
|
196
195
|
return plugin
|
|
197
196
|
|
|
198
197
|
configs: Optional[list[ProviderConfig]]
|
|
199
|
-
if
|
|
200
|
-
configs = self.
|
|
198
|
+
if collection:
|
|
199
|
+
configs = self.collection_to_provider_config_map.get(collection)
|
|
201
200
|
if not configs:
|
|
202
201
|
logger.info(
|
|
203
|
-
"
|
|
202
|
+
"UnsupportedCollection: %s, using generic settings", collection
|
|
204
203
|
)
|
|
205
|
-
configs = self.
|
|
204
|
+
configs = self.collection_to_provider_config_map[GENERIC_COLLECTION]
|
|
206
205
|
else:
|
|
207
206
|
configs = list(self.providers_config.values())
|
|
208
207
|
|
|
@@ -211,9 +210,9 @@ class PluginManager:
|
|
|
211
210
|
c for c in configs if provider in [getattr(c, "group", None), c.name]
|
|
212
211
|
]
|
|
213
212
|
|
|
214
|
-
if not configs and
|
|
213
|
+
if not configs and collection:
|
|
215
214
|
raise UnsupportedProvider(
|
|
216
|
-
f"{provider} is not (yet) supported for {
|
|
215
|
+
f"{provider} is not (yet) supported for {collection}"
|
|
217
216
|
)
|
|
218
217
|
if not configs:
|
|
219
218
|
raise UnsupportedProvider(f"{provider} is not (yet) supported")
|
|
@@ -265,8 +264,8 @@ class PluginManager:
|
|
|
265
264
|
matching_url = next(iter(product.assets.values()))["href"]
|
|
266
265
|
elif product is not None:
|
|
267
266
|
matching_url = product.properties.get(
|
|
268
|
-
"
|
|
269
|
-
) or product.properties.get("
|
|
267
|
+
"eodag:download_link"
|
|
268
|
+
) or product.properties.get("eodag:order_link")
|
|
270
269
|
else:
|
|
271
270
|
# search auth
|
|
272
271
|
matching_url = getattr(associated_plugin.config, "api_endpoint", None)
|
|
@@ -289,7 +288,7 @@ class PluginManager:
|
|
|
289
288
|
matching_url: Optional[str] = None,
|
|
290
289
|
matching_conf: Optional[PluginConfig] = None,
|
|
291
290
|
) -> Iterator[Authentication]:
|
|
292
|
-
"""Build and return the authentication plugin for the given
|
|
291
|
+
"""Build and return the authentication plugin for the given collection and
|
|
293
292
|
provider
|
|
294
293
|
|
|
295
294
|
:param provider: The provider for which to get the authentication plugin
|
|
@@ -362,7 +361,7 @@ class PluginManager:
|
|
|
362
361
|
provider: str,
|
|
363
362
|
matching_url: Optional[str] = None,
|
|
364
363
|
matching_conf: Optional[PluginConfig] = None,
|
|
365
|
-
) -> Optional[Union[AuthBase,
|
|
364
|
+
) -> Optional[Union[AuthBase, S3ServiceResource]]:
|
|
366
365
|
"""Authenticate and return the authenticated object for the first matching
|
|
367
366
|
authentication plugin
|
|
368
367
|
|
|
@@ -400,7 +399,7 @@ class PluginManager:
|
|
|
400
399
|
|
|
401
400
|
def sort_providers(self) -> None:
|
|
402
401
|
"""Sort providers taking into account current priority order"""
|
|
403
|
-
for provider_configs in self.
|
|
402
|
+
for provider_configs in self.collection_to_provider_config_map.values():
|
|
404
403
|
provider_configs.sort(key=attrgetter("priority"), reverse=True)
|
|
405
404
|
|
|
406
405
|
def set_priority(self, provider: str, priority: int) -> None:
|
|
@@ -414,7 +413,7 @@ class PluginManager:
|
|
|
414
413
|
for (
|
|
415
414
|
_,
|
|
416
415
|
provider_configs,
|
|
417
|
-
) in self.
|
|
416
|
+
) in self.collection_to_provider_config_map.items():
|
|
418
417
|
for config in provider_configs:
|
|
419
418
|
if config.name == provider:
|
|
420
419
|
config.priority = priority
|
eodag/plugins/search/__init__.py
CHANGED
|
@@ -30,17 +30,16 @@ if TYPE_CHECKING:
|
|
|
30
30
|
from requests.auth import AuthBase
|
|
31
31
|
|
|
32
32
|
from eodag.plugins.authentication.base import Authentication
|
|
33
|
-
from eodag.types import S3SessionKwargs
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
@dataclass
|
|
37
36
|
class PreparedSearch:
|
|
38
37
|
"""An object collecting needed information for search."""
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
collection: Optional[str] = None
|
|
41
40
|
page: Optional[int] = DEFAULT_PAGE
|
|
42
41
|
items_per_page: Optional[int] = DEFAULT_ITEMS_PER_PAGE
|
|
43
|
-
auth: Optional[Union[AuthBase,
|
|
42
|
+
auth: Optional[Union[AuthBase, S3ServiceResource]] = None
|
|
44
43
|
auth_plugin: Optional[Authentication] = None
|
|
45
44
|
count: bool = True
|
|
46
45
|
url: Optional[str] = None
|
|
@@ -51,6 +50,6 @@ class PreparedSearch:
|
|
|
51
50
|
query_params: dict[str, Any] = field(init=False, repr=False)
|
|
52
51
|
query_string: str = field(init=False, repr=False)
|
|
53
52
|
search_urls: list[str] = field(init=False, repr=False)
|
|
54
|
-
|
|
53
|
+
collection_def_params: dict[str, Any] = field(init=False, repr=False)
|
|
55
54
|
total_items_nb: int = field(init=False, repr=False)
|
|
56
55
|
sort_by_qs: str = field(init=False, repr=False)
|