eodag 3.0.0b2__py3-none-any.whl → 3.0.1__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 +295 -287
- eodag/api/product/__init__.py +10 -4
- eodag/api/product/_assets.py +2 -14
- eodag/api/product/_product.py +16 -30
- eodag/api/product/drivers/__init__.py +7 -2
- eodag/api/product/drivers/base.py +0 -3
- eodag/api/product/metadata_mapping.py +12 -31
- eodag/api/search_result.py +33 -12
- eodag/cli.py +35 -19
- eodag/config.py +455 -155
- eodag/plugins/apis/base.py +13 -7
- eodag/plugins/apis/ecmwf.py +16 -7
- eodag/plugins/apis/usgs.py +68 -16
- eodag/plugins/authentication/aws_auth.py +25 -7
- eodag/plugins/authentication/base.py +10 -1
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +12 -4
- eodag/plugins/authentication/keycloak.py +41 -22
- eodag/plugins/authentication/oauth.py +11 -1
- eodag/plugins/authentication/openid_connect.py +183 -167
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +19 -2
- eodag/plugins/authentication/token.py +59 -11
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/crunch/base.py +7 -2
- eodag/plugins/crunch/filter_date.py +8 -11
- eodag/plugins/crunch/filter_latest_intersect.py +5 -7
- eodag/plugins/crunch/filter_latest_tpl_name.py +2 -5
- eodag/plugins/crunch/filter_overlap.py +9 -15
- eodag/plugins/crunch/filter_property.py +9 -14
- eodag/plugins/download/aws.py +84 -99
- eodag/plugins/download/base.py +36 -77
- eodag/plugins/download/creodias_s3.py +11 -2
- eodag/plugins/download/http.py +134 -109
- eodag/plugins/download/s3rest.py +37 -43
- eodag/plugins/manager.py +173 -41
- eodag/plugins/search/__init__.py +9 -9
- eodag/plugins/search/base.py +35 -35
- eodag/plugins/search/build_search_result.py +55 -64
- eodag/plugins/search/cop_marine.py +113 -32
- eodag/plugins/search/creodias_s3.py +20 -8
- eodag/plugins/search/csw.py +41 -1
- eodag/plugins/search/data_request_search.py +119 -14
- eodag/plugins/search/qssearch.py +619 -197
- eodag/plugins/search/static_stac_search.py +25 -23
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +211 -56
- eodag/resources/providers.yml +1762 -1809
- eodag/resources/stac.yml +3 -163
- eodag/resources/user_conf_template.yml +134 -119
- eodag/rest/config.py +1 -2
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +70 -92
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +24 -330
- eodag/rest/stac.py +105 -630
- eodag/rest/types/eodag_search.py +17 -15
- eodag/rest/types/queryables.py +5 -14
- eodag/rest/types/stac_search.py +18 -13
- eodag/rest/utils/rfc3339.py +0 -1
- eodag/types/__init__.py +24 -6
- eodag/types/download_args.py +14 -5
- eodag/types/queryables.py +1 -2
- eodag/types/search_args.py +10 -11
- eodag/types/whoosh.py +0 -2
- eodag/utils/__init__.py +97 -136
- eodag/utils/constraints.py +0 -8
- eodag/utils/exceptions.py +23 -9
- eodag/utils/import_system.py +0 -4
- eodag/utils/logging.py +37 -80
- eodag/utils/notebook.py +4 -4
- eodag/utils/requests.py +13 -23
- eodag/utils/rest.py +0 -4
- eodag/utils/stac_reader.py +3 -15
- {eodag-3.0.0b2.dist-info → eodag-3.0.1.dist-info}/METADATA +41 -24
- eodag-3.0.1.dist-info/RECORD +109 -0
- {eodag-3.0.0b2.dist-info → eodag-3.0.1.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b2.dist-info → eodag-3.0.1.dist-info}/entry_points.txt +1 -0
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag-3.0.0b2.dist-info/RECORD +0 -110
- {eodag-3.0.0b2.dist-info → eodag-3.0.1.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b2.dist-info → eodag-3.0.1.dist-info}/top_level.txt +0 -0
eodag/utils/constraints.py
CHANGED
|
@@ -41,15 +41,10 @@ def get_constraint_queryables_with_additional_params(
|
|
|
41
41
|
gets the queryables from the constraints using the given parameters
|
|
42
42
|
For all queryables only values matching the given parameters based on the constraints will be returned
|
|
43
43
|
:param constraints: list of constraints fetched from the provider
|
|
44
|
-
:type constraints: List[Any]
|
|
45
44
|
:param input_params: conditions the constraints should fulfil
|
|
46
|
-
:type input_params: dict
|
|
47
45
|
:param plugin: search or api plugin that is used
|
|
48
|
-
:type plugin: Union[Search, Api]
|
|
49
46
|
:param product_type: product type for which the data should be fetched
|
|
50
|
-
:type product_type: str
|
|
51
47
|
:returns: dict containing queryable data
|
|
52
|
-
:rtype: Dict[str, Dict[str, Set[Any]]]
|
|
53
48
|
"""
|
|
54
49
|
defaults = copy.deepcopy(input_params)
|
|
55
50
|
constraint_matches = {}
|
|
@@ -174,11 +169,8 @@ def fetch_constraints(
|
|
|
174
169
|
"""
|
|
175
170
|
fetches the constraints from a provider
|
|
176
171
|
:param constraints_url: url from which the constraints can be fetched
|
|
177
|
-
:type constraints_url: str
|
|
178
172
|
:param plugin: api or search plugin of the provider
|
|
179
|
-
:type plugin: Union[Search, Api]
|
|
180
173
|
:returns: list of constraints fetched from the provider
|
|
181
|
-
:rtype: List[Dict[Any, Any]]
|
|
182
174
|
"""
|
|
183
175
|
auth = (
|
|
184
176
|
plugin.auth
|
eodag/utils/exceptions.py
CHANGED
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from typing import TYPE_CHECKING
|
|
20
|
+
from typing import TYPE_CHECKING, Annotated
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
|
-
from typing import Optional, Set
|
|
23
|
+
from typing import Optional, Set
|
|
24
|
+
|
|
25
|
+
from typing_extensions import Doc
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class EodagError(Exception):
|
|
@@ -84,14 +86,26 @@ class RequestError(EodagError):
|
|
|
84
86
|
"""An error indicating that a request has failed. Usually eodag functions
|
|
85
87
|
and methods should catch and skip this"""
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
status_code: Annotated[Optional[int], Doc("HTTP status code")] = None
|
|
90
|
+
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_error(cls, error: Exception, msg: Optional[str] = None):
|
|
93
|
+
"""Generate a RequestError from an Exception"""
|
|
94
|
+
status_code = getattr(error, "code", None)
|
|
95
|
+
text = getattr(error, "msg", None)
|
|
96
|
+
|
|
97
|
+
response = getattr(error, "response", None)
|
|
98
|
+
# Explicitly test for None because response objects are considered false if they
|
|
99
|
+
# have a status code other than 200
|
|
100
|
+
if response is not None:
|
|
101
|
+
status_code = response.status_code
|
|
102
|
+
text = response.text
|
|
103
|
+
|
|
104
|
+
text = text or str(error)
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
repr += f"- {str(err_tuple)}"
|
|
94
|
-
return repr
|
|
106
|
+
e = cls(msg, text) if msg else cls(text)
|
|
107
|
+
e.status_code = status_code
|
|
108
|
+
return e
|
|
95
109
|
|
|
96
110
|
|
|
97
111
|
class NoMatchingProductType(EodagError):
|
eodag/utils/import_system.py
CHANGED
|
@@ -52,12 +52,9 @@ def import_all_modules(
|
|
|
52
52
|
import_all_modules(base_package)
|
|
53
53
|
|
|
54
54
|
:param base_package: The package from where we must import all the modules
|
|
55
|
-
:type base_package: `module`
|
|
56
55
|
:param depth: (optional) If `base_package` has sub packages, import all the modules recursively up to this level.
|
|
57
56
|
Defaults to 1 (limits to the level of `base_package`)
|
|
58
|
-
:type depth: int
|
|
59
57
|
:param exclude: (optional) The sub packages and modules to ignore while importing. Empty by default
|
|
60
|
-
:type exclude: tuple(str, ...)
|
|
61
58
|
|
|
62
59
|
.. note::
|
|
63
60
|
if `package` and `subpackage` have a module of the same name and this name is included in the exclude
|
|
@@ -88,7 +85,6 @@ def patch_owslib_requests(verify: bool = True) -> Generator[None, Any, None]:
|
|
|
88
85
|
these functions in `owslib <https://geopython.github.io/OWSLib/>`_.
|
|
89
86
|
|
|
90
87
|
:param verify: (optional) Whether to verify the use of https or not
|
|
91
|
-
:type verify: bool
|
|
92
88
|
"""
|
|
93
89
|
from owslib.util import requests
|
|
94
90
|
|
eodag/utils/logging.py
CHANGED
|
@@ -32,95 +32,53 @@ def setup_logging(verbose: int, no_progress_bar: bool = False) -> None:
|
|
|
32
32
|
* 1: no logging but still displays progress bars
|
|
33
33
|
* 2: INFO level
|
|
34
34
|
* 3: DEBUG level
|
|
35
|
-
:type verbose: int
|
|
36
35
|
:param no_progress_bar: (optional) Disable progress bars
|
|
37
|
-
:type no_progress_bar: bool
|
|
38
36
|
"""
|
|
39
37
|
global disable_tqdm
|
|
40
38
|
disable_tqdm = no_progress_bar
|
|
41
39
|
|
|
40
|
+
if verbose > 3:
|
|
41
|
+
raise ValueError("'verbose' must be one of: 0, 1, 2, 3")
|
|
42
|
+
|
|
42
43
|
if verbose < 1:
|
|
43
44
|
disable_tqdm = True
|
|
44
45
|
|
|
45
|
-
if verbose
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"formatter": "standard",
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
"loggers": {
|
|
76
|
-
"eodag": {
|
|
77
|
-
"handlers": ["console"],
|
|
78
|
-
"propagate": True,
|
|
79
|
-
"level": "INFO",
|
|
80
|
-
},
|
|
81
|
-
"sentinelsat": {
|
|
82
|
-
"handlers": ["console"],
|
|
83
|
-
"propagate": True,
|
|
84
|
-
"level": "INFO",
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
)
|
|
89
|
-
elif verbose == 3:
|
|
90
|
-
logging.config.dictConfig(
|
|
91
|
-
{
|
|
92
|
-
"version": 1,
|
|
93
|
-
"disable_existing_loggers": False,
|
|
94
|
-
"formatters": {
|
|
95
|
-
"verbose": {
|
|
96
|
-
"format": (
|
|
97
|
-
"%(asctime)-15s %(name)-32s [%(levelname)-8s] (tid=%(thread)d) %(message)s"
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
"handlers": {
|
|
102
|
-
"console": {
|
|
103
|
-
"level": "DEBUG",
|
|
104
|
-
"class": "logging.StreamHandler",
|
|
105
|
-
"formatter": "verbose",
|
|
106
|
-
}
|
|
46
|
+
level = "DEBUG" if verbose == 3 else "INFO"
|
|
47
|
+
|
|
48
|
+
handlers = {
|
|
49
|
+
"console": {
|
|
50
|
+
"level": level,
|
|
51
|
+
"class": "logging.StreamHandler",
|
|
52
|
+
"formatter": "standard",
|
|
53
|
+
},
|
|
54
|
+
"null": {"level": level, "class": "logging.NullHandler"},
|
|
55
|
+
}
|
|
56
|
+
handler = "console" if verbose > 1 else "null"
|
|
57
|
+
|
|
58
|
+
logging.config.dictConfig(
|
|
59
|
+
{
|
|
60
|
+
"version": 1,
|
|
61
|
+
"disable_existing_loggers": False,
|
|
62
|
+
"formatters": {
|
|
63
|
+
"standard": {
|
|
64
|
+
"format": "%(asctime)-15s %(name)-32s [%(levelname)-8s] %(message)s"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"handlers": handlers,
|
|
68
|
+
"loggers": {
|
|
69
|
+
"eodag": {
|
|
70
|
+
"handlers": [handler],
|
|
71
|
+
"propagate": True,
|
|
72
|
+
"level": f"{level}",
|
|
107
73
|
},
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"level": "DEBUG",
|
|
113
|
-
},
|
|
114
|
-
"sentinelsat": {
|
|
115
|
-
"handlers": ["console"],
|
|
116
|
-
"propagate": True,
|
|
117
|
-
"level": "DEBUG",
|
|
118
|
-
},
|
|
74
|
+
"eodag-cube": {
|
|
75
|
+
"handlers": [handler],
|
|
76
|
+
"propagate": True,
|
|
77
|
+
"level": f"{level}",
|
|
119
78
|
},
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
raise ValueError("'verbose' must be one of: 0, 1, 2, 3")
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
)
|
|
124
82
|
|
|
125
83
|
|
|
126
84
|
def get_logging_verbose() -> Optional[int]:
|
|
@@ -142,7 +100,6 @@ def get_logging_verbose() -> Optional[int]:
|
|
|
142
100
|
3
|
|
143
101
|
|
|
144
102
|
:returns: Verbose level in ``[0, 1, 2, 3]`` or None if not set
|
|
145
|
-
:rtype: int or None
|
|
146
103
|
"""
|
|
147
104
|
global disable_tqdm
|
|
148
105
|
logger = logging.getLogger("eodag")
|
eodag/utils/notebook.py
CHANGED
|
@@ -23,7 +23,7 @@ from typing import Any, Optional
|
|
|
23
23
|
def check_ipython() -> bool:
|
|
24
24
|
"""Check if called from ipython"""
|
|
25
25
|
try:
|
|
26
|
-
__IPYTHON__
|
|
26
|
+
__IPYTHON__ # type: ignore[name-defined]
|
|
27
27
|
return True
|
|
28
28
|
except NameError:
|
|
29
29
|
return False
|
|
@@ -32,7 +32,7 @@ def check_ipython() -> bool:
|
|
|
32
32
|
def check_notebook() -> bool:
|
|
33
33
|
"""Check if called from a notebook"""
|
|
34
34
|
try:
|
|
35
|
-
shell = get_ipython().__class__.__name__
|
|
35
|
+
shell = get_ipython().__class__.__name__ # type: ignore[name-defined]
|
|
36
36
|
if shell == "ZMQInteractiveShell":
|
|
37
37
|
return True # Jupyter notebook or qtconsole
|
|
38
38
|
elif shell == "TerminalInteractiveShell":
|
|
@@ -69,7 +69,7 @@ class NotebookWidgets:
|
|
|
69
69
|
if not self.is_notebook:
|
|
70
70
|
return None
|
|
71
71
|
|
|
72
|
-
self.html_box
|
|
72
|
+
setattr(self.html_box, "data", html_value)
|
|
73
73
|
|
|
74
74
|
if not self.html_box_shown:
|
|
75
75
|
self._html_handle = self.display(self.html_box, display_id=True)
|
|
@@ -83,5 +83,5 @@ class NotebookWidgets:
|
|
|
83
83
|
if not self.is_notebook:
|
|
84
84
|
return None
|
|
85
85
|
|
|
86
|
-
self.html_box
|
|
86
|
+
setattr(self.html_box, "data", "")
|
|
87
87
|
self._update_display(self.html_box, display_id=self._html_handle.display_id)
|
eodag/utils/requests.py
CHANGED
|
@@ -32,22 +32,17 @@ logger = logging.getLogger("eodag.utils.requests")
|
|
|
32
32
|
def fetch_json(
|
|
33
33
|
file_url: str,
|
|
34
34
|
req_session: Optional[requests.Session] = None,
|
|
35
|
-
auth: Optional[requests.AuthBase] = None,
|
|
35
|
+
auth: Optional[requests.auth.AuthBase] = None,
|
|
36
36
|
timeout: float = HTTP_REQ_TIMEOUT,
|
|
37
37
|
) -> Any:
|
|
38
38
|
"""
|
|
39
39
|
Fetches http/distant or local json file
|
|
40
40
|
|
|
41
41
|
:param file_url: url from which the file can be fetched
|
|
42
|
-
:type file_url: str
|
|
43
42
|
:param req_session: (optional) requests session
|
|
44
|
-
:type req_session: requests.Session
|
|
45
43
|
:param auth: (optional) authenticated object if request needs authentication
|
|
46
|
-
:type auth: Optional[requests.AuthBase]
|
|
47
44
|
:param timeout: (optional) authenticated object
|
|
48
|
-
:type timeout: float
|
|
49
45
|
:returns: json file content
|
|
50
|
-
:rtype: Any
|
|
51
46
|
"""
|
|
52
47
|
if req_session is None:
|
|
53
48
|
req_session = requests.Session()
|
|
@@ -68,9 +63,7 @@ def fetch_json(
|
|
|
68
63
|
except requests.exceptions.Timeout as exc:
|
|
69
64
|
raise TimeOutError(exc, timeout=HTTP_REQ_TIMEOUT) from exc
|
|
70
65
|
except requests.exceptions.RequestException as exc:
|
|
71
|
-
raise RequestError(
|
|
72
|
-
f"Unable to fetch {file_url}: {str(exc)}",
|
|
73
|
-
) from exc
|
|
66
|
+
raise RequestError.from_error(exc, f"Unable to fetch {file_url}") from exc
|
|
74
67
|
else:
|
|
75
68
|
return res.json()
|
|
76
69
|
|
|
@@ -86,11 +79,8 @@ class LocalFileAdapter(requests.adapters.BaseAdapter):
|
|
|
86
79
|
"""Return an HTTP status for the given filesystem path.
|
|
87
80
|
|
|
88
81
|
:param method: method of the request
|
|
89
|
-
:type method: str
|
|
90
82
|
:param path: path of the given file
|
|
91
|
-
:type path: str
|
|
92
83
|
:returns: HTTP status and its associated message
|
|
93
|
-
:rtype: Tuple[int, str]
|
|
94
84
|
"""
|
|
95
85
|
if method.lower() in ("put", "delete"):
|
|
96
86
|
return 501, "Not Implemented" # TODO
|
|
@@ -105,31 +95,31 @@ class LocalFileAdapter(requests.adapters.BaseAdapter):
|
|
|
105
95
|
else:
|
|
106
96
|
return 200, "OK"
|
|
107
97
|
|
|
108
|
-
def send(
|
|
98
|
+
def send(
|
|
99
|
+
self, request: requests.PreparedRequest, *args: Any, **kwargs: Any
|
|
100
|
+
) -> requests.Response:
|
|
109
101
|
"""Wraps a file, described in request, in a Response object.
|
|
110
102
|
|
|
111
103
|
:param req: The PreparedRequest being "sent".
|
|
112
|
-
:type req: :class:`~requests.PreparedRequest`
|
|
113
104
|
:param kwargs: (not used) additionnal arguments of the request
|
|
114
|
-
:type kwargs: Any
|
|
115
105
|
:returns: a Response object containing the file
|
|
116
|
-
:rtype: :class:`~requests.Response`
|
|
117
106
|
"""
|
|
118
107
|
response = requests.Response()
|
|
119
108
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if req.method is None or req.url is None:
|
|
109
|
+
if request.method is None or request.url is None:
|
|
123
110
|
raise RequestError("Method or url of the request is missing")
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
|
|
112
|
+
path_url = uri_to_path(request.url)
|
|
113
|
+
|
|
114
|
+
response.status_code, response.reason = self._chkpath(request.method, path_url)
|
|
115
|
+
if response.status_code == 200 and request.method.lower() != "head":
|
|
126
116
|
try:
|
|
127
117
|
response.raw = open(path_url, "rb")
|
|
128
118
|
except (OSError, IOError) as err:
|
|
129
119
|
response.status_code = 500
|
|
130
120
|
response.reason = str(err)
|
|
131
|
-
response.url =
|
|
132
|
-
response.request =
|
|
121
|
+
response.url = request.url
|
|
122
|
+
response.request = request
|
|
133
123
|
|
|
134
124
|
return response
|
|
135
125
|
|
eodag/utils/rest.py
CHANGED
|
@@ -39,9 +39,7 @@ def get_datetime(arguments: Dict[str, Any]) -> Tuple[Optional[str], Optional[str
|
|
|
39
39
|
"""Get start and end dates from a dict containing `/` separated dates in `datetime` item
|
|
40
40
|
|
|
41
41
|
:param arguments: dict containing a single date or `/` separated dates in `datetime` item
|
|
42
|
-
:type arguments: dict
|
|
43
42
|
:returns: Start date and end date from datetime string (duplicate value if only one date as input)
|
|
44
|
-
:rtype: Tuple[Optional[str], Optional[str]]
|
|
45
43
|
"""
|
|
46
44
|
datetime_str = arguments.pop("datetime", None)
|
|
47
45
|
|
|
@@ -86,10 +84,8 @@ def rfc3339_str_to_datetime(s: str) -> datetime.datetime:
|
|
|
86
84
|
"""Convert a string conforming to RFC 3339 to a :class:`datetime.datetime`.
|
|
87
85
|
|
|
88
86
|
:param s: The string to convert to :class:`datetime.datetime`
|
|
89
|
-
:type s: str
|
|
90
87
|
|
|
91
88
|
:returns: The datetime represented by the ISO8601 (RFC 3339) formatted string
|
|
92
|
-
:rtype: :class:`datetime.datetime`
|
|
93
89
|
|
|
94
90
|
raises: :class:`ValidationError`
|
|
95
91
|
"""
|
eodag/utils/stac_reader.py
CHANGED
|
@@ -112,23 +112,17 @@ def fetch_stac_items(
|
|
|
112
112
|
"""Fetch STAC item from a single item file or items from a catalog.
|
|
113
113
|
|
|
114
114
|
:param stac_path: A STAC object filepath
|
|
115
|
-
:type stac_path: str
|
|
116
115
|
:param recursive: (optional) Browse recursively in child nodes if True
|
|
117
|
-
:
|
|
118
|
-
:param max_connections: (optional) Maximum number of connections for HTTP requests
|
|
119
|
-
:type max_connections: int
|
|
116
|
+
:param max_connections: (optional) Maximum number of connections for concurrent HTTP requests
|
|
120
117
|
:param timeout: (optional) Timeout in seconds for each internal HTTP request
|
|
121
|
-
:type timeout: int
|
|
122
118
|
:param ssl_verify: (optional) SSL Verification for HTTP request
|
|
123
|
-
:type ssl_verify: bool
|
|
124
119
|
:returns: The items found in `stac_path`
|
|
125
|
-
:rtype: :class:`list`
|
|
126
120
|
"""
|
|
127
121
|
|
|
128
122
|
# URI opener used by PySTAC internally, instantiated here
|
|
129
123
|
# to retrieve the timeout.
|
|
130
124
|
_text_opener = _TextOpener(timeout, ssl_verify)
|
|
131
|
-
pystac.StacIO.read_text = _text_opener
|
|
125
|
+
pystac.StacIO.read_text = _text_opener # type: ignore[assignment]
|
|
132
126
|
|
|
133
127
|
stac_obj = pystac.read_file(stac_path)
|
|
134
128
|
# Single STAC item
|
|
@@ -198,22 +192,16 @@ def fetch_stac_collections(
|
|
|
198
192
|
"""Fetch STAC collection(s) from a catalog.
|
|
199
193
|
|
|
200
194
|
:param stac_path: A STAC object filepath
|
|
201
|
-
:type stac_path: str
|
|
202
195
|
:param collection: the collection to fetch
|
|
203
|
-
:type collection: Optional[str]
|
|
204
196
|
:param max_connections: (optional) Maximum number of connections for HTTP requests
|
|
205
|
-
:type max_connections: int
|
|
206
197
|
:param timeout: (optional) Timeout in seconds for each internal HTTP request
|
|
207
|
-
:type timeout: int
|
|
208
198
|
:param ssl_verify: (optional) SSL Verification for HTTP request
|
|
209
|
-
:type ssl_verify: bool
|
|
210
199
|
:returns: The collection(s) found in `stac_path`
|
|
211
|
-
:rtype: :class:`list`
|
|
212
200
|
"""
|
|
213
201
|
|
|
214
202
|
# URI opener used by PySTAC internally, instantiated here to retrieve the timeout.
|
|
215
203
|
_text_opener = _TextOpener(timeout, ssl_verify)
|
|
216
|
-
pystac.StacIO.read_text = _text_opener
|
|
204
|
+
pystac.StacIO.read_text = _text_opener # type: ignore[assignment]
|
|
217
205
|
|
|
218
206
|
stac_obj = pystac.read_file(stac_path)
|
|
219
207
|
if isinstance(stac_obj, pystac.Catalog):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eodag
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.1
|
|
4
4
|
Summary: Earth Observation Data Access Gateway
|
|
5
5
|
Home-page: https://github.com/CS-SI/eodag
|
|
6
6
|
Author: CS GROUP - France
|
|
@@ -18,15 +18,16 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
18
18
|
Classifier: Operating System :: POSIX :: Linux
|
|
19
19
|
Classifier: Programming Language :: Python
|
|
20
20
|
Classifier: Programming Language :: Python :: 3
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
25
24
|
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
27
27
|
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
28
28
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
29
29
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Classifier: Typing :: Typed
|
|
30
31
|
Requires-Python: >=3.6
|
|
31
32
|
Description-Content-Type: text/x-rst
|
|
32
33
|
License-File: LICENSE
|
|
@@ -39,6 +40,7 @@ Requires-Dist: jsonpath-ng <1.6.0
|
|
|
39
40
|
Requires-Dist: lxml
|
|
40
41
|
Requires-Dist: pydantic >=2.1.0
|
|
41
42
|
Requires-Dist: pydantic-core
|
|
43
|
+
Requires-Dist: PyJWT >=2.5.0
|
|
42
44
|
Requires-Dist: pyproj >=2.1.0
|
|
43
45
|
Requires-Dist: pyshp
|
|
44
46
|
Requires-Dist: pystac >=1.0.0b1
|
|
@@ -46,7 +48,7 @@ Requires-Dist: python-dateutil
|
|
|
46
48
|
Requires-Dist: PyYAML
|
|
47
49
|
Requires-Dist: requests
|
|
48
50
|
Requires-Dist: setuptools
|
|
49
|
-
Requires-Dist: shapely >=2.0.
|
|
51
|
+
Requires-Dist: shapely >=2.0.6
|
|
50
52
|
Requires-Dist: stream-zip
|
|
51
53
|
Requires-Dist: tqdm
|
|
52
54
|
Requires-Dist: typing-extensions >=4.8.0
|
|
@@ -61,7 +63,7 @@ Requires-Dist: eodag[ecmwf,usgs] ; extra == 'all-providers'
|
|
|
61
63
|
Provides-Extra: csw
|
|
62
64
|
Requires-Dist: OWSLib >=0.27.1 ; extra == 'csw'
|
|
63
65
|
Provides-Extra: dev
|
|
64
|
-
Requires-Dist: eodag[all-providers,csw,server] ; extra == 'dev'
|
|
66
|
+
Requires-Dist: eodag[all-providers,csw,server,stubs] ; extra == 'dev'
|
|
65
67
|
Requires-Dist: pytest ; extra == 'dev'
|
|
66
68
|
Requires-Dist: pytest-cov ; extra == 'dev'
|
|
67
69
|
Requires-Dist: py >=1.8.2 ; extra == 'dev'
|
|
@@ -70,6 +72,7 @@ Requires-Dist: pytest-xdist ; extra == 'dev'
|
|
|
70
72
|
Requires-Dist: pytest-socket ; extra == 'dev'
|
|
71
73
|
Requires-Dist: pytest-instafail ; extra == 'dev'
|
|
72
74
|
Requires-Dist: tox ; extra == 'dev'
|
|
75
|
+
Requires-Dist: tox-uv ; extra == 'dev'
|
|
73
76
|
Requires-Dist: faker ; extra == 'dev'
|
|
74
77
|
Requires-Dist: moto ; extra == 'dev'
|
|
75
78
|
Requires-Dist: twine ; extra == 'dev'
|
|
@@ -79,15 +82,16 @@ Requires-Dist: pre-commit ; extra == 'dev'
|
|
|
79
82
|
Requires-Dist: responses <0.24.0 ; extra == 'dev'
|
|
80
83
|
Requires-Dist: fastapi[all] ; extra == 'dev'
|
|
81
84
|
Requires-Dist: stdlib-list ; extra == 'dev'
|
|
82
|
-
Requires-Dist:
|
|
83
|
-
Requires-Dist: types-lxml ; extra == 'dev'
|
|
85
|
+
Requires-Dist: mypy ; extra == 'dev'
|
|
84
86
|
Provides-Extra: docs
|
|
85
|
-
Requires-Dist: eodag[all] ; extra == 'docs'
|
|
87
|
+
Requires-Dist: eodag[all,stubs] ; extra == 'docs'
|
|
86
88
|
Requires-Dist: sphinx ; extra == 'docs'
|
|
87
|
-
Requires-Dist: sphinx-book-theme ; extra == 'docs'
|
|
89
|
+
Requires-Dist: sphinx-book-theme >=1.0.0 ; extra == 'docs'
|
|
88
90
|
Requires-Dist: sphinx-copybutton ; extra == 'docs'
|
|
89
91
|
Requires-Dist: sphinx-tabs ; extra == 'docs'
|
|
90
92
|
Requires-Dist: nbsphinx ; extra == 'docs'
|
|
93
|
+
Requires-Dist: sphinx-autodoc-typehints ; extra == 'docs'
|
|
94
|
+
Requires-Dist: sphinxemoji ; extra == 'docs'
|
|
91
95
|
Provides-Extra: ecmwf
|
|
92
96
|
Requires-Dist: ecmwf-api-client ; extra == 'ecmwf'
|
|
93
97
|
Provides-Extra: notebook
|
|
@@ -99,8 +103,17 @@ Requires-Dist: starlette ; extra == 'server'
|
|
|
99
103
|
Requires-Dist: uvicorn[standard] ; extra == 'server'
|
|
100
104
|
Requires-Dist: pydantic-settings ; extra == 'server'
|
|
101
105
|
Requires-Dist: cachetools ; extra == 'server'
|
|
106
|
+
Provides-Extra: stubs
|
|
107
|
+
Requires-Dist: boto3-stubs[essential] ; extra == 'stubs'
|
|
108
|
+
Requires-Dist: types-lxml ; extra == 'stubs'
|
|
109
|
+
Requires-Dist: types-cachetools ; extra == 'stubs'
|
|
110
|
+
Requires-Dist: types-requests ; extra == 'stubs'
|
|
111
|
+
Requires-Dist: types-python-dateutil ; extra == 'stubs'
|
|
112
|
+
Requires-Dist: types-setuptools ; extra == 'stubs'
|
|
113
|
+
Requires-Dist: types-tqdm ; extra == 'stubs'
|
|
114
|
+
Requires-Dist: types-urllib3 ; extra == 'stubs'
|
|
102
115
|
Provides-Extra: tutorials
|
|
103
|
-
Requires-Dist: eodag[notebook] ; extra == 'tutorials'
|
|
116
|
+
Requires-Dist: eodag[ecmwf,notebook] ; extra == 'tutorials'
|
|
104
117
|
Requires-Dist: eodag-cube >=0.2.0 ; extra == 'tutorials'
|
|
105
118
|
Requires-Dist: jupyter ; extra == 'tutorials'
|
|
106
119
|
Requires-Dist: ipyleaflet >=0.10.0 ; extra == 'tutorials'
|
|
@@ -138,8 +151,6 @@ Requires-Dist: usgs >=0.3.1 ; extra == 'usgs'
|
|
|
138
151
|
|
|
139
152
|
|pypi-badge| |conda-badge| |rtd-badge| |gha-badge| |ghi-badge| |binder-badge|
|
|
140
153
|
|
|
141
|
-
|
|
|
142
|
-
|
|
143
154
|
.. |license-badge| image:: https://img.shields.io/pypi/l/eodag.svg
|
|
144
155
|
:target: https://pypi.org/project/eodag/
|
|
145
156
|
|
|
@@ -199,8 +210,14 @@ And with ``conda`` from the `conda-forge channel <https://anaconda.org/conda-for
|
|
|
199
210
|
|
|
200
211
|
conda install -c conda-forge eodag
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
|
|
213
|
+
..
|
|
214
|
+
|
|
215
|
+
[!IMPORTANT]
|
|
216
|
+
|
|
217
|
+
`Breaking change <https://eodag.readthedocs.io/en/latest/breaking_changes.html>`_ **in v3.0.0**:
|
|
218
|
+
Please note that EODAG
|
|
219
|
+
comes with a minimal set of dependencies. If you want more features, please install using one of the
|
|
220
|
+
`available extras <https://eodag.readthedocs.io/en/latest/getting_started_guide/install.html#optional-dependencies>`_.
|
|
204
221
|
|
|
205
222
|
Usage
|
|
206
223
|
=====
|
|
@@ -234,8 +251,13 @@ This will search for Sentinel 2 level-1C products on the default provider and re
|
|
|
234
251
|
an estimated total number of products matching the search criteria. And then it will download these products. Please
|
|
235
252
|
check the `Python API User Guide <https://eodag.readthedocs.io/en/latest/api_user_guide.html>`_ for more details.
|
|
236
253
|
|
|
237
|
-
|
|
238
|
-
|
|
254
|
+
..
|
|
255
|
+
|
|
256
|
+
[!IMPORTANT]
|
|
257
|
+
|
|
258
|
+
`Breaking change <https://eodag.readthedocs.io/en/latest/breaking_changes.html>`_ **in v3.0.0**:
|
|
259
|
+
`search() <https://eodag.readthedocs.io/en/latest/api_reference/core.html#eodag.api.core.EODataAccessGateway.search>`_ method now returns
|
|
260
|
+
only a single ``SearchResult`` instead of a 2 values tuple.
|
|
239
261
|
|
|
240
262
|
STAC REST API
|
|
241
263
|
-------------
|
|
@@ -280,25 +302,20 @@ An eodag instance can be exposed through a STAC compliant REST api from the comm
|
|
|
280
302
|
| jq ".numberMatched"
|
|
281
303
|
6
|
|
282
304
|
|
|
283
|
-
# browse for items
|
|
284
|
-
$ curl "http://127.0.0.1:5000/catalogs/S2_MSI_L1C/country/FRA/year/2021/month/01/day/25/cloud_cover/10/items" \
|
|
285
|
-
| jq ".numberMatched"
|
|
286
|
-
9
|
|
287
|
-
|
|
288
305
|
# get download link
|
|
289
|
-
$ curl "http://127.0.0.1:5000/
|
|
306
|
+
$ curl "http://127.0.0.1:5000/collections/S2_MSI_L1C/items" \
|
|
290
307
|
| jq ".features[0].assets.downloadLink.href"
|
|
291
|
-
"http://127.0.0.1:
|
|
308
|
+
"http://127.0.0.1:5002/collections/S2_MSI_L1C/items/S2B_MSIL1C_20240917T115259_N0511_R137_T21CWS_20240917T145134/download"
|
|
292
309
|
|
|
293
310
|
# download
|
|
294
|
-
$ wget "http://127.0.0.1:
|
|
311
|
+
$ wget "http://127.0.0.1:5002/collections/S2_MSI_L1C/items/S2B_MSIL1C_20240917T115259_N0511_R137_T21CWS_20240917T145134/download"
|
|
295
312
|
|
|
296
313
|
|
|
297
314
|
``eodag-server`` is available on `https://hub.docker.com/r/csspace/eodag-server <https://hub.docker.com/r/csspace/eodag-server>`_:
|
|
298
315
|
|
|
299
316
|
.. code-block:: bash
|
|
300
317
|
|
|
301
|
-
docker run -p 5000:5000 --rm csspace/eodag-server:3.0.
|
|
318
|
+
docker run -p 5000:5000 --rm csspace/eodag-server:3.0.1
|
|
302
319
|
|
|
303
320
|
You can also browse over your STAC API server using `STAC Browser <https://github.com/radiantearth/stac-browser>`_.
|
|
304
321
|
Simply run:
|