eodag 4.0.0a3__py3-none-any.whl → 4.0.0a4__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/collection.py +8 -8
- eodag/api/core.py +199 -310
- eodag/api/product/_product.py +3 -3
- eodag/api/provider.py +990 -0
- eodag/cli.py +1 -3
- eodag/config.py +73 -444
- eodag/plugins/authentication/token.py +0 -1
- eodag/plugins/download/http.py +0 -1
- eodag/plugins/manager.py +24 -34
- eodag/resources/ext_collections.json +1 -1
- eodag/resources/ext_product_types.json +1 -1
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/METADATA +1 -1
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/RECORD +17 -16
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/WHEEL +0 -0
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/entry_points.txt +0 -0
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/licenses/LICENSE +0 -0
- {eodag-4.0.0a3.dist-info → eodag-4.0.0a4.dist-info}/top_level.txt +0 -0
eodag/api/core.py
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
20
|
import datetime
|
|
21
|
+
import itertools
|
|
21
22
|
import logging
|
|
22
23
|
import os
|
|
23
24
|
import re
|
|
@@ -25,19 +26,18 @@ import shutil
|
|
|
25
26
|
import tempfile
|
|
26
27
|
import warnings
|
|
27
28
|
from collections import deque
|
|
29
|
+
from copy import deepcopy
|
|
28
30
|
from importlib.metadata import version
|
|
29
31
|
from importlib.resources import files as res_files
|
|
30
32
|
from operator import attrgetter, itemgetter
|
|
31
|
-
from typing import TYPE_CHECKING, Any, Iterator, Optional, Union
|
|
33
|
+
from typing import TYPE_CHECKING, Any, Iterator, Optional, Union, cast
|
|
32
34
|
|
|
33
35
|
import geojson
|
|
34
36
|
import yaml
|
|
35
37
|
|
|
36
38
|
from eodag.api.collection import Collection, CollectionsDict, CollectionsList
|
|
37
|
-
from eodag.api.product.metadata_mapping import
|
|
38
|
-
|
|
39
|
-
mtd_cfg_as_conversion_and_querypath,
|
|
40
|
-
)
|
|
39
|
+
from eodag.api.product.metadata_mapping import mtd_cfg_as_conversion_and_querypath
|
|
40
|
+
from eodag.api.provider import Provider, ProvidersDict
|
|
41
41
|
from eodag.api.search_result import SearchResult
|
|
42
42
|
from eodag.config import (
|
|
43
43
|
PLUGINS_TOPICS_KEYS,
|
|
@@ -46,13 +46,7 @@ from eodag.config import (
|
|
|
46
46
|
credentials_in_auth,
|
|
47
47
|
get_ext_collections_conf,
|
|
48
48
|
load_default_config,
|
|
49
|
-
load_stac_provider_config,
|
|
50
49
|
load_yml_config,
|
|
51
|
-
override_config_from_env,
|
|
52
|
-
override_config_from_file,
|
|
53
|
-
override_config_from_mapping,
|
|
54
|
-
provider_config_init,
|
|
55
|
-
share_credentials,
|
|
56
50
|
)
|
|
57
51
|
from eodag.plugins.manager import PluginManager
|
|
58
52
|
from eodag.plugins.search import PreparedSearch
|
|
@@ -124,7 +118,8 @@ class EODataAccessGateway:
|
|
|
124
118
|
)
|
|
125
119
|
collections_config_dict = SimpleYamlProxyConfig(collections_config_path).source
|
|
126
120
|
self.collections_config = self._collections_config_init(collections_config_dict)
|
|
127
|
-
|
|
121
|
+
|
|
122
|
+
self._providers = ProvidersDict.from_configs(load_default_config())
|
|
128
123
|
|
|
129
124
|
env_var_cfg_dir = "EODAG_CFG_DIR"
|
|
130
125
|
self.conf_dir = os.getenv(
|
|
@@ -148,9 +143,8 @@ class EODataAccessGateway:
|
|
|
148
143
|
self.conf_dir = tmp_conf_dir
|
|
149
144
|
makedirs(self.conf_dir)
|
|
150
145
|
|
|
151
|
-
self._plugins_manager = PluginManager(self.
|
|
152
|
-
|
|
153
|
-
self.providers_config = self._plugins_manager.providers_config
|
|
146
|
+
self._plugins_manager = PluginManager(self._providers)
|
|
147
|
+
self._providers = self._plugins_manager.providers
|
|
154
148
|
|
|
155
149
|
# First level override: From a user configuration file
|
|
156
150
|
if user_conf_file_path is None:
|
|
@@ -166,67 +160,29 @@ class EODataAccessGateway:
|
|
|
166
160
|
),
|
|
167
161
|
standard_configuration_path,
|
|
168
162
|
)
|
|
169
|
-
|
|
163
|
+
self._providers.update_from_config_file(user_conf_file_path)
|
|
170
164
|
|
|
171
165
|
# Second level override: From environment variables
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
# share credentials between updated plugins confs
|
|
175
|
-
share_credentials(self.providers_config)
|
|
166
|
+
self._providers.update_from_env()
|
|
176
167
|
|
|
177
168
|
# init updated providers conf
|
|
178
169
|
strict_mode = is_env_var_true("EODAG_STRICT_COLLECTIONS")
|
|
179
|
-
available_collections = set(self.collections_config.keys())
|
|
180
170
|
|
|
181
|
-
for provider in self.
|
|
182
|
-
|
|
183
|
-
self.providers_config[provider],
|
|
184
|
-
load_stac_provider_config(),
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
self._sync_provider_collections(
|
|
188
|
-
provider, available_collections, strict_mode
|
|
189
|
-
)
|
|
171
|
+
for provider in self._providers.values():
|
|
172
|
+
provider.sync_collections(self, strict_mode)
|
|
190
173
|
|
|
191
174
|
# re-build _plugins_manager using up-to-date providers_config
|
|
192
|
-
self._plugins_manager.rebuild(self.
|
|
175
|
+
self._plugins_manager.rebuild(self._providers)
|
|
193
176
|
|
|
194
177
|
# store pruned providers configs
|
|
195
178
|
self._pruned_providers_config: dict[str, Any] = {}
|
|
179
|
+
|
|
196
180
|
# filter out providers needing auth that have no credentials set
|
|
197
181
|
self._prune_providers_list()
|
|
198
182
|
|
|
199
183
|
# Sort providers taking into account of possible new priority orders
|
|
200
184
|
self._plugins_manager.sort_providers()
|
|
201
185
|
|
|
202
|
-
# set locations configuration
|
|
203
|
-
if locations_conf_path is None:
|
|
204
|
-
locations_conf_path = os.getenv("EODAG_LOCS_CFG_FILE")
|
|
205
|
-
if locations_conf_path is None:
|
|
206
|
-
locations_conf_path = os.path.join(self.conf_dir, "locations.yml")
|
|
207
|
-
if not os.path.isfile(locations_conf_path):
|
|
208
|
-
# copy locations conf file and replace path example
|
|
209
|
-
locations_conf_template = str(
|
|
210
|
-
res_files("eodag") / "resources" / "locations_conf_template.yml"
|
|
211
|
-
)
|
|
212
|
-
with (
|
|
213
|
-
open(locations_conf_template) as infile,
|
|
214
|
-
open(locations_conf_path, "w") as outfile,
|
|
215
|
-
):
|
|
216
|
-
# The template contains paths in the form of:
|
|
217
|
-
# /path/to/locations/file.shp
|
|
218
|
-
path_template = "/path/to/locations/"
|
|
219
|
-
for line in infile:
|
|
220
|
-
line = line.replace(
|
|
221
|
-
path_template,
|
|
222
|
-
os.path.join(self.conf_dir, "shp") + os.path.sep,
|
|
223
|
-
)
|
|
224
|
-
outfile.write(line)
|
|
225
|
-
# copy sample shapefile dir
|
|
226
|
-
shutil.copytree(
|
|
227
|
-
str(res_files("eodag") / "resources" / "shp"),
|
|
228
|
-
os.path.join(self.conf_dir, "shp"),
|
|
229
|
-
)
|
|
230
186
|
self.set_locations_conf(locations_conf_path)
|
|
231
187
|
|
|
232
188
|
def _collections_config_init(
|
|
@@ -243,57 +199,19 @@ class EODataAccessGateway:
|
|
|
243
199
|
]
|
|
244
200
|
return CollectionsDict(collections)
|
|
245
201
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
In strict mode, removes collections not in available_collections.
|
|
256
|
-
In permissive mode, adds empty collection configs for missing types.
|
|
257
|
-
|
|
258
|
-
:param provider: The provider name whose collections should be synchronized.
|
|
259
|
-
:param available_collections: The set of available collection IDs.
|
|
260
|
-
:param strict_mode: If True, remove unknown collections; if False, add empty configs for them.
|
|
261
|
-
:returns: None
|
|
262
|
-
"""
|
|
263
|
-
provider_products = self.providers_config[provider].products
|
|
264
|
-
products_to_remove: list[str] = []
|
|
265
|
-
products_to_add: list[str] = []
|
|
266
|
-
|
|
267
|
-
for product_id in provider_products:
|
|
268
|
-
if product_id == GENERIC_COLLECTION:
|
|
269
|
-
continue
|
|
270
|
-
|
|
271
|
-
if product_id not in available_collections:
|
|
272
|
-
if strict_mode:
|
|
273
|
-
products_to_remove.append(product_id)
|
|
274
|
-
continue
|
|
275
|
-
|
|
276
|
-
empty_product = Collection.create_with_dag(
|
|
277
|
-
self, id=product_id, title=product_id, description=NOT_AVAILABLE
|
|
278
|
-
)
|
|
279
|
-
self.collections_config[product_id] = empty_product
|
|
280
|
-
products_to_add.append(product_id)
|
|
281
|
-
|
|
282
|
-
if products_to_add:
|
|
283
|
-
logger.debug(
|
|
284
|
-
"Collections permissive mode, %s added (provider %s)",
|
|
285
|
-
", ".join(products_to_add),
|
|
286
|
-
provider,
|
|
202
|
+
@property
|
|
203
|
+
def providers(self) -> ProvidersDict:
|
|
204
|
+
"""Providers of eodag configuration sorted by priority in descending order and by name in ascending order."""
|
|
205
|
+
providers = deepcopy(self._providers)
|
|
206
|
+
# Sort: priority descending, then name ascending
|
|
207
|
+
providers.data = {
|
|
208
|
+
k: v
|
|
209
|
+
for k, v in sorted(
|
|
210
|
+
providers.data.items(), key=lambda item: (-item[1].priority, item[0])
|
|
287
211
|
)
|
|
212
|
+
}
|
|
288
213
|
|
|
289
|
-
|
|
290
|
-
logger.debug(
|
|
291
|
-
"Collections strict mode, ignoring %s (provider %s)",
|
|
292
|
-
", ".join(products_to_remove),
|
|
293
|
-
provider,
|
|
294
|
-
)
|
|
295
|
-
for id in products_to_remove:
|
|
296
|
-
del self.providers_config[provider].products[id]
|
|
214
|
+
return providers
|
|
297
215
|
|
|
298
216
|
def get_version(self) -> str:
|
|
299
217
|
"""Get eodag package version"""
|
|
@@ -305,10 +223,11 @@ class EODataAccessGateway:
|
|
|
305
223
|
:param provider: The name of the provider that should be considered as the
|
|
306
224
|
preferred provider to be used for this instance
|
|
307
225
|
"""
|
|
308
|
-
if provider not in self.
|
|
226
|
+
if provider not in self.providers.names:
|
|
309
227
|
raise UnsupportedProvider(
|
|
310
228
|
f"This provider is not recognised by eodag: {provider}"
|
|
311
229
|
)
|
|
230
|
+
|
|
312
231
|
preferred_provider, max_priority = self.get_preferred_provider()
|
|
313
232
|
if preferred_provider != provider:
|
|
314
233
|
new_priority = max_priority + 1
|
|
@@ -320,12 +239,7 @@ class EODataAccessGateway:
|
|
|
320
239
|
|
|
321
240
|
:returns: The provider with the maximum priority and its priority
|
|
322
241
|
"""
|
|
323
|
-
|
|
324
|
-
(provider, conf.priority)
|
|
325
|
-
for provider, conf in self.providers_config.items()
|
|
326
|
-
]
|
|
327
|
-
preferred, priority = max(providers_with_priority, key=itemgetter(1))
|
|
328
|
-
return preferred, priority
|
|
242
|
+
return max(self._providers.priorities.items(), key=itemgetter(1))
|
|
329
243
|
|
|
330
244
|
def update_providers_config(
|
|
331
245
|
self,
|
|
@@ -347,27 +261,17 @@ class EODataAccessGateway:
|
|
|
347
261
|
return None
|
|
348
262
|
|
|
349
263
|
# restore the pruned configuration
|
|
350
|
-
for
|
|
351
|
-
|
|
264
|
+
for name in list(self._pruned_providers_config):
|
|
265
|
+
config = self._pruned_providers_config[name]
|
|
266
|
+
if name in conf_update:
|
|
352
267
|
logger.info(
|
|
353
|
-
"%s: provider restored from the pruned configurations",
|
|
354
|
-
provider,
|
|
355
|
-
)
|
|
356
|
-
self.providers_config[provider] = self._pruned_providers_config.pop(
|
|
357
|
-
provider
|
|
268
|
+
"%s: provider restored from the pruned configurations", name
|
|
358
269
|
)
|
|
270
|
+
self._providers[name] = Provider(config)
|
|
271
|
+
self._pruned_providers_config.pop(name)
|
|
359
272
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
# share credentials between updated plugins confs
|
|
363
|
-
share_credentials(self.providers_config)
|
|
273
|
+
self._providers.update_from_configs(conf_update)
|
|
364
274
|
|
|
365
|
-
for provider in conf_update.keys():
|
|
366
|
-
provider_config_init(
|
|
367
|
-
self.providers_config[provider],
|
|
368
|
-
load_stac_provider_config(),
|
|
369
|
-
)
|
|
370
|
-
setattr(self.providers_config[provider], "collections_fetched", False)
|
|
371
275
|
# re-create _plugins_manager using up-to-date providers_config
|
|
372
276
|
self._plugins_manager.build_collection_to_provider_config_map()
|
|
373
277
|
|
|
@@ -398,10 +302,11 @@ class EODataAccessGateway:
|
|
|
398
302
|
:param search: Search :class:`~eodag.config.PluginConfig` mapping
|
|
399
303
|
:param products: Provider collections mapping
|
|
400
304
|
:param download: Download :class:`~eodag.config.PluginConfig` mapping
|
|
401
|
-
:param kwargs: Additional :class:`~eodag.
|
|
305
|
+
:param kwargs: Additional :class:`~eodag.api.provider.ProviderConfig` mapping
|
|
402
306
|
"""
|
|
403
307
|
conf_dict: dict[str, Any] = {
|
|
404
308
|
name: {
|
|
309
|
+
"name": name,
|
|
405
310
|
"url": url,
|
|
406
311
|
"search": {"type": "StacSearch", **search},
|
|
407
312
|
"products": {
|
|
@@ -440,8 +345,10 @@ class EODataAccessGateway:
|
|
|
440
345
|
def _prune_providers_list(self) -> None:
|
|
441
346
|
"""Removes from config providers needing auth that have no credentials set."""
|
|
442
347
|
update_needed = False
|
|
443
|
-
|
|
444
|
-
|
|
348
|
+
|
|
349
|
+
# loop over a copy to allow popping items
|
|
350
|
+
for name, provider in list(self._providers.items()):
|
|
351
|
+
conf = provider.config
|
|
445
352
|
|
|
446
353
|
# remove providers using skipped plugins
|
|
447
354
|
if [
|
|
@@ -450,7 +357,7 @@ class EODataAccessGateway:
|
|
|
450
357
|
if isinstance(v, PluginConfig)
|
|
451
358
|
and getattr(v, "type", None) in self._plugins_manager.skipped_plugins
|
|
452
359
|
]:
|
|
453
|
-
self.
|
|
360
|
+
del self._providers[provider.name]
|
|
454
361
|
logger.debug(
|
|
455
362
|
f"{provider}: provider needing unavailable plugin has been removed"
|
|
456
363
|
)
|
|
@@ -461,26 +368,28 @@ class EODataAccessGateway:
|
|
|
461
368
|
credentials_exist = credentials_in_auth(conf.api)
|
|
462
369
|
if not credentials_exist:
|
|
463
370
|
# credentials needed but not found
|
|
464
|
-
self._pruned_providers_config[provider] =
|
|
465
|
-
|
|
466
|
-
|
|
371
|
+
self._pruned_providers_config[provider.name] = conf
|
|
372
|
+
del self._providers[provider.name]
|
|
373
|
+
|
|
467
374
|
update_needed = True
|
|
468
375
|
logger.info(
|
|
469
376
|
"%s: provider needing auth for search has been pruned because no credentials could be found",
|
|
470
377
|
provider,
|
|
471
378
|
)
|
|
379
|
+
|
|
472
380
|
elif hasattr(conf, "search") and getattr(conf.search, "need_auth", False):
|
|
473
381
|
if not hasattr(conf, "auth") and not hasattr(conf, "search_auth"):
|
|
474
382
|
# credentials needed but no auth plugin was found
|
|
475
|
-
self._pruned_providers_config[provider] =
|
|
476
|
-
|
|
477
|
-
|
|
383
|
+
self._pruned_providers_config[provider.name] = conf
|
|
384
|
+
del self._providers[provider.name]
|
|
385
|
+
|
|
478
386
|
update_needed = True
|
|
479
387
|
logger.info(
|
|
480
388
|
"%s: provider needing auth for search has been pruned because no auth plugin could be found",
|
|
481
389
|
provider,
|
|
482
390
|
)
|
|
483
391
|
continue
|
|
392
|
+
|
|
484
393
|
credentials_exist = (
|
|
485
394
|
hasattr(conf, "search_auth")
|
|
486
395
|
and credentials_in_auth(conf.search_auth)
|
|
@@ -491,30 +400,31 @@ class EODataAccessGateway:
|
|
|
491
400
|
)
|
|
492
401
|
if not credentials_exist:
|
|
493
402
|
# credentials needed but not found
|
|
494
|
-
self._pruned_providers_config[provider] =
|
|
495
|
-
|
|
496
|
-
|
|
403
|
+
self._pruned_providers_config[provider.name] = conf
|
|
404
|
+
del self._providers[provider.name]
|
|
405
|
+
|
|
497
406
|
update_needed = True
|
|
498
407
|
logger.info(
|
|
499
408
|
"%s: provider needing auth for search has been pruned because no credentials could be found",
|
|
500
409
|
provider,
|
|
501
410
|
)
|
|
411
|
+
|
|
502
412
|
elif not hasattr(conf, "api") and not hasattr(conf, "search"):
|
|
503
413
|
# provider should have at least an api or search plugin
|
|
504
|
-
self._pruned_providers_config[provider] =
|
|
505
|
-
|
|
506
|
-
|
|
414
|
+
self._pruned_providers_config[provider.name] = conf
|
|
415
|
+
del self._providers[provider.name]
|
|
416
|
+
|
|
417
|
+
update_needed = True
|
|
507
418
|
logger.info(
|
|
508
419
|
"%s: provider has been pruned because no api or search plugin could be found",
|
|
509
420
|
provider,
|
|
510
421
|
)
|
|
511
|
-
update_needed = True
|
|
512
422
|
|
|
513
423
|
if update_needed:
|
|
514
424
|
# rebuild _plugins_manager with updated providers list
|
|
515
|
-
self._plugins_manager.rebuild(self.
|
|
425
|
+
self._plugins_manager.rebuild(self._providers)
|
|
516
426
|
|
|
517
|
-
def set_locations_conf(self, locations_conf_path: str) -> None:
|
|
427
|
+
def set_locations_conf(self, locations_conf_path: Optional[str]) -> None:
|
|
518
428
|
"""Set locations configuration.
|
|
519
429
|
This configuration (YML format) will contain a shapefile list associated
|
|
520
430
|
to a name and attribute parameters needed to identify the needed geometry.
|
|
@@ -537,6 +447,34 @@ class EODataAccessGateway:
|
|
|
537
447
|
|
|
538
448
|
:param locations_conf_path: Path to the locations configuration file
|
|
539
449
|
"""
|
|
450
|
+
if locations_conf_path is None:
|
|
451
|
+
locations_conf_path = os.getenv("EODAG_LOCS_CFG_FILE")
|
|
452
|
+
if locations_conf_path is None:
|
|
453
|
+
locations_conf_path = os.path.join(self.conf_dir, "locations.yml")
|
|
454
|
+
if not os.path.isfile(locations_conf_path):
|
|
455
|
+
# copy locations conf file and replace path example
|
|
456
|
+
locations_conf_template = str(
|
|
457
|
+
res_files("eodag") / "resources" / "locations_conf_template.yml"
|
|
458
|
+
)
|
|
459
|
+
with (
|
|
460
|
+
open(locations_conf_template) as infile,
|
|
461
|
+
open(locations_conf_path, "w") as outfile,
|
|
462
|
+
):
|
|
463
|
+
# The template contains paths in the form of:
|
|
464
|
+
# /path/to/locations/file.shp
|
|
465
|
+
path_template = "/path/to/locations/"
|
|
466
|
+
for line in infile:
|
|
467
|
+
line = line.replace(
|
|
468
|
+
path_template,
|
|
469
|
+
os.path.join(self.conf_dir, "shp") + os.path.sep,
|
|
470
|
+
)
|
|
471
|
+
outfile.write(line)
|
|
472
|
+
# copy sample shapefile dir
|
|
473
|
+
shutil.copytree(
|
|
474
|
+
str(res_files("eodag") / "resources" / "shp"),
|
|
475
|
+
os.path.join(self.conf_dir, "shp"),
|
|
476
|
+
)
|
|
477
|
+
|
|
540
478
|
if os.path.isfile(locations_conf_path):
|
|
541
479
|
locations_config = load_yml_config(locations_conf_path)
|
|
542
480
|
|
|
@@ -567,17 +505,11 @@ class EODataAccessGateway:
|
|
|
567
505
|
# First, update collections list if possible
|
|
568
506
|
self.fetch_collections_list(provider=provider)
|
|
569
507
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
if not provider
|
|
573
|
-
else [
|
|
574
|
-
p
|
|
575
|
-
for p in self.providers_config.values()
|
|
576
|
-
if provider in [p.name, getattr(p, "group", None)]
|
|
577
|
-
]
|
|
508
|
+
providers_iter, providers_check = itertools.tee(
|
|
509
|
+
self._providers.filter_by_name_or_group(provider)
|
|
578
510
|
)
|
|
579
511
|
|
|
580
|
-
if provider and not
|
|
512
|
+
if provider and not any(providers_check):
|
|
581
513
|
raise UnsupportedProvider(
|
|
582
514
|
f"The requested provider is not (yet) supported: {provider}"
|
|
583
515
|
)
|
|
@@ -585,8 +517,8 @@ class EODataAccessGateway:
|
|
|
585
517
|
# unique collection ids from providers configs
|
|
586
518
|
collection_ids = {
|
|
587
519
|
collection_id
|
|
588
|
-
for p in
|
|
589
|
-
for collection_id in p.
|
|
520
|
+
for p in providers_iter
|
|
521
|
+
for collection_id in p.collections_config
|
|
590
522
|
if collection_id != GENERIC_COLLECTION
|
|
591
523
|
}
|
|
592
524
|
|
|
@@ -611,42 +543,18 @@ class EODataAccessGateway:
|
|
|
611
543
|
if strict_mode:
|
|
612
544
|
return
|
|
613
545
|
|
|
614
|
-
providers_to_fetch = list(self.providers_config.keys())
|
|
615
|
-
# check if some providers are grouped under a group name which is not a provider name
|
|
616
|
-
if provider is not None and provider not in self.providers_config:
|
|
617
|
-
providers_to_fetch = [
|
|
618
|
-
p
|
|
619
|
-
for p, pconf in self.providers_config.items()
|
|
620
|
-
if provider == getattr(pconf, "group", None)
|
|
621
|
-
]
|
|
622
|
-
if providers_to_fetch:
|
|
623
|
-
logger.info(
|
|
624
|
-
f"Fetch collections for {provider} group: {', '.join(providers_to_fetch)}"
|
|
625
|
-
)
|
|
626
|
-
else:
|
|
627
|
-
return None
|
|
628
|
-
elif provider is not None:
|
|
629
|
-
providers_to_fetch = [provider]
|
|
630
|
-
|
|
631
546
|
# providers discovery confs that are fetchable
|
|
632
|
-
providers_discovery_configs_fetchable: dict[
|
|
547
|
+
providers_discovery_configs_fetchable: dict[
|
|
548
|
+
str, PluginConfig.DiscoverCollections
|
|
549
|
+
] = {}
|
|
633
550
|
# check if any provider has not already been fetched for collections
|
|
634
551
|
already_fetched = True
|
|
635
|
-
for provider_to_fetch in
|
|
636
|
-
|
|
637
|
-
# get discovery conf
|
|
638
|
-
if hasattr(provider_config, "search"):
|
|
639
|
-
provider_search_config = provider_config.search
|
|
640
|
-
elif hasattr(provider_config, "api"):
|
|
641
|
-
provider_search_config = provider_config.api
|
|
642
|
-
else:
|
|
643
|
-
continue
|
|
644
|
-
discovery_conf = getattr(provider_search_config, "discover_collections", {})
|
|
645
|
-
if discovery_conf.get("fetch_url"):
|
|
552
|
+
for provider_to_fetch in self._providers.filter_by_name_or_group(provider):
|
|
553
|
+
if provider_to_fetch.fetchable and provider_to_fetch.search_config:
|
|
646
554
|
providers_discovery_configs_fetchable[
|
|
647
|
-
provider_to_fetch
|
|
648
|
-
] =
|
|
649
|
-
if not
|
|
555
|
+
provider_to_fetch.name
|
|
556
|
+
] = provider_to_fetch.search_config.discover_collections
|
|
557
|
+
if not provider_to_fetch.collections_fetched:
|
|
650
558
|
already_fetched = False
|
|
651
559
|
|
|
652
560
|
if not already_fetched:
|
|
@@ -672,54 +580,55 @@ class EODataAccessGateway:
|
|
|
672
580
|
# and collections list would need to be fetched
|
|
673
581
|
|
|
674
582
|
# get ext_collections conf for user modified providers
|
|
675
|
-
|
|
583
|
+
default_providers = ProvidersDict.from_configs(load_default_config())
|
|
676
584
|
for (
|
|
677
585
|
provider,
|
|
678
586
|
user_discovery_conf,
|
|
679
587
|
) in providers_discovery_configs_fetchable.items():
|
|
680
588
|
# default discover_collections conf
|
|
681
|
-
if provider in
|
|
682
|
-
|
|
683
|
-
if
|
|
684
|
-
default_provider_search_config = default_provider_config.search
|
|
685
|
-
elif hasattr(default_provider_config, "api"):
|
|
686
|
-
default_provider_search_config = default_provider_config.api
|
|
687
|
-
else:
|
|
589
|
+
if provider in default_providers:
|
|
590
|
+
default_provider = default_providers[provider]
|
|
591
|
+
if not default_provider.search_config:
|
|
688
592
|
continue
|
|
689
|
-
|
|
690
|
-
|
|
593
|
+
|
|
594
|
+
default_discovery_conf = (
|
|
595
|
+
default_provider.search_config.discover_collections
|
|
691
596
|
)
|
|
597
|
+
|
|
692
598
|
# compare confs
|
|
693
599
|
if default_discovery_conf["result_type"] == "json" and isinstance(
|
|
694
600
|
default_discovery_conf["results_entry"], str
|
|
695
601
|
):
|
|
696
|
-
default_discovery_conf_parsed =
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
602
|
+
default_discovery_conf_parsed = cast(
|
|
603
|
+
PluginConfig.DiscoverCollections,
|
|
604
|
+
dict(
|
|
605
|
+
default_discovery_conf,
|
|
606
|
+
**{
|
|
607
|
+
"results_entry": string_to_jsonpath(
|
|
608
|
+
default_discovery_conf["results_entry"], force=True
|
|
609
|
+
)
|
|
610
|
+
},
|
|
611
|
+
**mtd_cfg_as_conversion_and_querypath(
|
|
612
|
+
dict(
|
|
613
|
+
generic_collection_id=default_discovery_conf[
|
|
614
|
+
"generic_collection_id"
|
|
615
|
+
]
|
|
616
|
+
)
|
|
617
|
+
),
|
|
618
|
+
**dict(
|
|
619
|
+
generic_collection_parsable_properties=mtd_cfg_as_conversion_and_querypath(
|
|
620
|
+
default_discovery_conf[
|
|
621
|
+
"generic_collection_parsable_properties"
|
|
622
|
+
]
|
|
623
|
+
)
|
|
624
|
+
),
|
|
625
|
+
**dict(
|
|
626
|
+
generic_collection_parsable_metadata=mtd_cfg_as_conversion_and_querypath(
|
|
627
|
+
default_discovery_conf[
|
|
628
|
+
"generic_collection_parsable_metadata"
|
|
629
|
+
]
|
|
630
|
+
)
|
|
631
|
+
),
|
|
723
632
|
),
|
|
724
633
|
)
|
|
725
634
|
else:
|
|
@@ -757,51 +666,34 @@ class EODataAccessGateway:
|
|
|
757
666
|
all providers (None value).
|
|
758
667
|
:returns: external collections configuration
|
|
759
668
|
"""
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
if provider and
|
|
766
|
-
logger.info(
|
|
767
|
-
f"Discover collections for {provider} group: {', '.join(grouped_providers)}"
|
|
768
|
-
)
|
|
769
|
-
elif provider and provider not in self.providers_config:
|
|
669
|
+
|
|
670
|
+
providers_iter, providers_check = itertools.tee(
|
|
671
|
+
self.providers.filter_by_name_or_group(provider)
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
if provider and not any(providers_check):
|
|
770
675
|
raise UnsupportedProvider(
|
|
771
676
|
f"The requested provider is not (yet) supported: {provider}"
|
|
772
677
|
)
|
|
678
|
+
|
|
773
679
|
ext_collections_conf: dict[str, Any] = {}
|
|
774
|
-
|
|
775
|
-
p
|
|
776
|
-
for p in (
|
|
777
|
-
[
|
|
778
|
-
p
|
|
779
|
-
for p in self.providers_config
|
|
780
|
-
if p in grouped_providers + [provider]
|
|
781
|
-
]
|
|
782
|
-
if provider
|
|
783
|
-
else self.available_providers()
|
|
784
|
-
)
|
|
785
|
-
]
|
|
680
|
+
|
|
786
681
|
kwargs: dict[str, Any] = {}
|
|
787
|
-
for
|
|
788
|
-
if
|
|
789
|
-
search_plugin_config = self.providers_config[provider].search
|
|
790
|
-
elif hasattr(self.providers_config[provider], "api"):
|
|
791
|
-
search_plugin_config = self.providers_config[provider].api
|
|
792
|
-
else:
|
|
682
|
+
for p in providers_iter:
|
|
683
|
+
if not p.search_config:
|
|
793
684
|
return None
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
):
|
|
685
|
+
|
|
686
|
+
if p.fetchable:
|
|
797
687
|
search_plugin: Union[Search, Api] = next(
|
|
798
|
-
self._plugins_manager.get_search_plugins(provider=
|
|
688
|
+
self._plugins_manager.get_search_plugins(provider=p.name)
|
|
799
689
|
)
|
|
690
|
+
|
|
800
691
|
# check after plugin init if still fetchable
|
|
801
692
|
if not getattr(search_plugin.config, "discover_collections", {}).get(
|
|
802
693
|
"fetch_url"
|
|
803
694
|
):
|
|
804
695
|
continue
|
|
696
|
+
|
|
805
697
|
# append auth to search plugin if needed
|
|
806
698
|
if getattr(search_plugin.config, "need_auth", False):
|
|
807
699
|
if auth := self._plugins_manager.get_auth(
|
|
@@ -812,12 +704,12 @@ class EODataAccessGateway:
|
|
|
812
704
|
kwargs["auth"] = auth
|
|
813
705
|
else:
|
|
814
706
|
logger.debug(
|
|
815
|
-
f"Could not authenticate on {
|
|
707
|
+
f"Could not authenticate on {p} for collections discovery"
|
|
816
708
|
)
|
|
817
|
-
ext_collections_conf[
|
|
709
|
+
ext_collections_conf[p.name] = None
|
|
818
710
|
continue
|
|
819
711
|
|
|
820
|
-
ext_collections_conf[
|
|
712
|
+
ext_collections_conf[p.name] = search_plugin.discover_collections(
|
|
821
713
|
**kwargs
|
|
822
714
|
)
|
|
823
715
|
|
|
@@ -831,20 +723,15 @@ class EODataAccessGateway:
|
|
|
831
723
|
:param ext_collections_conf: external collections configuration
|
|
832
724
|
"""
|
|
833
725
|
for provider, new_collections_conf in ext_collections_conf.items():
|
|
834
|
-
if new_collections_conf and provider in self.
|
|
726
|
+
if new_collections_conf and provider in self._providers:
|
|
835
727
|
try:
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
) or getattr(self.providers_config[provider], "api", None)
|
|
839
|
-
if search_plugin_config is None:
|
|
840
|
-
continue
|
|
841
|
-
if not getattr(
|
|
842
|
-
search_plugin_config, "discover_collections", {}
|
|
843
|
-
).get("fetch_url"):
|
|
728
|
+
fetchable = self._providers[provider].fetchable
|
|
729
|
+
if not fetchable:
|
|
844
730
|
# conf has been updated and provider collections are no more discoverable
|
|
845
731
|
continue
|
|
732
|
+
|
|
846
733
|
provider_products_config = (
|
|
847
|
-
self.
|
|
734
|
+
self._providers[provider].collections_config or {}
|
|
848
735
|
)
|
|
849
736
|
except UnsupportedProvider:
|
|
850
737
|
logger.debug(
|
|
@@ -852,6 +739,7 @@ class EODataAccessGateway:
|
|
|
852
739
|
provider,
|
|
853
740
|
)
|
|
854
741
|
continue
|
|
742
|
+
|
|
855
743
|
new_collections: list[str] = []
|
|
856
744
|
bad_formatted_col_count = 0
|
|
857
745
|
for (
|
|
@@ -861,11 +749,10 @@ class EODataAccessGateway:
|
|
|
861
749
|
if new_collection not in provider_products_config:
|
|
862
750
|
for existing_collection in provider_products_config.copy():
|
|
863
751
|
# compare parsed extracted conf (without metadata_mapping entry)
|
|
864
|
-
unparsable_keys =
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
)
|
|
752
|
+
unparsable_keys = self._providers[
|
|
753
|
+
provider
|
|
754
|
+
].unparsable_properties
|
|
755
|
+
|
|
869
756
|
new_parsed_collections_conf = {
|
|
870
757
|
k: v
|
|
871
758
|
for k, v in new_collection_conf.items()
|
|
@@ -930,19 +817,27 @@ class EODataAccessGateway:
|
|
|
930
817
|
provider,
|
|
931
818
|
)
|
|
932
819
|
|
|
933
|
-
elif provider not in self.
|
|
820
|
+
elif provider not in self._providers:
|
|
934
821
|
# unknown provider
|
|
935
822
|
continue
|
|
936
|
-
|
|
823
|
+
|
|
824
|
+
self._providers[provider].collections_fetched = True
|
|
937
825
|
|
|
938
826
|
# re-create _plugins_manager using up-to-date providers_config
|
|
939
827
|
self._plugins_manager.build_collection_to_provider_config_map()
|
|
940
828
|
|
|
829
|
+
@_deprecated(
|
|
830
|
+
reason="Please use 'EODataAccessGateway.providers' instead",
|
|
831
|
+
version="4.0.0",
|
|
832
|
+
)
|
|
941
833
|
def available_providers(
|
|
942
834
|
self, collection: Optional[str] = None, by_group: bool = False
|
|
943
835
|
) -> list[str]:
|
|
944
836
|
"""Gives the sorted list of the available providers or groups
|
|
945
837
|
|
|
838
|
+
.. deprecated:: v4.0.0
|
|
839
|
+
Please use :attr:`eodag.api.core.EODataAccessGateway.providers` instead.
|
|
840
|
+
|
|
946
841
|
The providers or groups are sorted first by their priority level in descending order,
|
|
947
842
|
and then alphabetically in ascending order for providers or groups with the same
|
|
948
843
|
priority level.
|
|
@@ -952,32 +847,26 @@ class EODataAccessGateway:
|
|
|
952
847
|
of providers, mixed with other providers
|
|
953
848
|
:returns: the sorted list of the available providers or groups
|
|
954
849
|
"""
|
|
850
|
+
candidates = []
|
|
955
851
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
if collection in getattr(v, "products", {}).keys()
|
|
961
|
-
]
|
|
962
|
-
else:
|
|
963
|
-
providers = [
|
|
964
|
-
(v.group if by_group and hasattr(v, "group") else k, v.priority)
|
|
965
|
-
for k, v in self.providers_config.items()
|
|
966
|
-
]
|
|
852
|
+
# use "providers" property to get sorted providers
|
|
853
|
+
for key, provider in self.providers.items():
|
|
854
|
+
if collection and collection not in provider.collections_config:
|
|
855
|
+
continue
|
|
967
856
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
for name, priority in providers:
|
|
972
|
-
if name not in group_priority or priority > group_priority[name]:
|
|
973
|
-
group_priority[name] = priority
|
|
974
|
-
providers = list(group_priority.items())
|
|
857
|
+
group = getattr(provider.config, "group", None)
|
|
858
|
+
name = group if by_group and group else key
|
|
859
|
+
candidates.append((name, provider.priority))
|
|
975
860
|
|
|
976
|
-
|
|
977
|
-
|
|
861
|
+
if by_group:
|
|
862
|
+
# Keep only the highest-priority entry per group
|
|
863
|
+
grouped: dict[str, int] = {}
|
|
864
|
+
for name, priority in candidates:
|
|
865
|
+
if name not in grouped or priority > grouped[name]:
|
|
866
|
+
grouped[name] = priority
|
|
867
|
+
candidates = list(grouped.items())
|
|
978
868
|
|
|
979
|
-
|
|
980
|
-
return [name for name, _ in providers]
|
|
869
|
+
return [name for name, _ in candidates]
|
|
981
870
|
|
|
982
871
|
def get_collection_from_alias(self, alias_or_id: str) -> str:
|
|
983
872
|
"""Return the id of a collection by either its id or alias
|
|
@@ -1253,7 +1142,7 @@ class EODataAccessGateway:
|
|
|
1253
1142
|
warnings.warn(
|
|
1254
1143
|
"Usage of deprecated search parameter 'page' "
|
|
1255
1144
|
"(Please use 'SearchResult.next_page()' instead)"
|
|
1256
|
-
" -- Deprecated since
|
|
1145
|
+
" -- Deprecated since v4.0.0",
|
|
1257
1146
|
DeprecationWarning,
|
|
1258
1147
|
stacklevel=2,
|
|
1259
1148
|
)
|
|
@@ -1323,7 +1212,7 @@ class EODataAccessGateway:
|
|
|
1323
1212
|
|
|
1324
1213
|
@_deprecated(
|
|
1325
1214
|
reason="Please use 'SearchResult.next_page()' instead",
|
|
1326
|
-
version="
|
|
1215
|
+
version="4.0.0",
|
|
1327
1216
|
)
|
|
1328
1217
|
def search_iter_page(
|
|
1329
1218
|
self,
|
|
@@ -1336,7 +1225,7 @@ class EODataAccessGateway:
|
|
|
1336
1225
|
) -> Iterator[SearchResult]:
|
|
1337
1226
|
"""Iterate over the pages of a products search.
|
|
1338
1227
|
|
|
1339
|
-
.. deprecated::
|
|
1228
|
+
.. deprecated:: v4.0.0
|
|
1340
1229
|
Please use :meth:`eodag.api.search_result.SearchResult.next_page` instead.
|
|
1341
1230
|
|
|
1342
1231
|
:param items_per_page: (optional) The number of results requested per page
|
|
@@ -1391,7 +1280,7 @@ class EODataAccessGateway:
|
|
|
1391
1280
|
|
|
1392
1281
|
@_deprecated(
|
|
1393
1282
|
reason="Please use 'SearchResult.next_page()' instead",
|
|
1394
|
-
version="
|
|
1283
|
+
version="4.0.0",
|
|
1395
1284
|
)
|
|
1396
1285
|
def search_iter_page_plugin(
|
|
1397
1286
|
self,
|
|
@@ -1401,7 +1290,7 @@ class EODataAccessGateway:
|
|
|
1401
1290
|
) -> Iterator[SearchResult]:
|
|
1402
1291
|
"""Iterate over the pages of a products search using a given search plugin.
|
|
1403
1292
|
|
|
1404
|
-
.. deprecated::
|
|
1293
|
+
.. deprecated:: v4.0.0
|
|
1405
1294
|
Please use :meth:`eodag.api.search_result.SearchResult.next_page` instead.
|
|
1406
1295
|
|
|
1407
1296
|
:param items_per_page: (optional) The number of results requested per page
|