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
|
@@ -28,7 +28,13 @@ from requests.auth import AuthBase
|
|
|
28
28
|
from urllib3 import Retry
|
|
29
29
|
|
|
30
30
|
from eodag.plugins.authentication.base import Authentication
|
|
31
|
-
from eodag.utils import
|
|
31
|
+
from eodag.utils import (
|
|
32
|
+
HTTP_REQ_TIMEOUT,
|
|
33
|
+
REQ_RETRY_BACKOFF_FACTOR,
|
|
34
|
+
REQ_RETRY_STATUS_FORCELIST,
|
|
35
|
+
REQ_RETRY_TOTAL,
|
|
36
|
+
USER_AGENT,
|
|
37
|
+
)
|
|
32
38
|
from eodag.utils.exceptions import AuthenticationError, MisconfiguredError, TimeOutError
|
|
33
39
|
|
|
34
40
|
if TYPE_CHECKING:
|
|
@@ -41,7 +47,36 @@ logger = logging.getLogger("eodag.authentication.token")
|
|
|
41
47
|
|
|
42
48
|
|
|
43
49
|
class TokenAuth(Authentication):
|
|
44
|
-
"""TokenAuth authentication plugin
|
|
50
|
+
"""TokenAuth authentication plugin - fetches a token which is added to search/download requests
|
|
51
|
+
|
|
52
|
+
:param provider: provider name
|
|
53
|
+
:param config: Authentication plugin configuration:
|
|
54
|
+
|
|
55
|
+
* :attr:`~eodag.config.PluginConfig.type` (``str``) (**mandatory**): TokenAuth
|
|
56
|
+
* :attr:`~eodag.config.PluginConfig.auth_uri` (``str``) (**mandatory**): url used to fetch
|
|
57
|
+
the access token with user/password
|
|
58
|
+
* :attr:`~eodag.config.PluginConfig.refresh_uri` (``str``) : url used to fetch the
|
|
59
|
+
access token with a refresh token
|
|
60
|
+
* :attr:`~eodag.config.PluginConfig.token_type` (``str``): type of the token (``json``
|
|
61
|
+
or ``text``); default: ``text``
|
|
62
|
+
* :attr:`~eodag.config.PluginConfig.token_key` (``str``): (mandatory if token_type=json)
|
|
63
|
+
key to get the access token in the response to the token request
|
|
64
|
+
* :attr:`~eodag.config.PluginConfig.refresh_token_key` (``str``): key to get the refresh
|
|
65
|
+
token in the response to the token request
|
|
66
|
+
* :attr:`~eodag.config.PluginConfig.ssl_verify` (``bool``): if the ssl certificates
|
|
67
|
+
should be verified in the requests; default: ``True``
|
|
68
|
+
* :attr:`~eodag.config.PluginConfig.auth_error_code` (``int``): which error code is
|
|
69
|
+
returned in case of an authentication error
|
|
70
|
+
* :attr:`~eodag.config.PluginConfig.req_data` (``Dict[str, Any]``): if the credentials
|
|
71
|
+
should be sent as data in the post request, the json structure can be given in this parameter
|
|
72
|
+
* :attr:`~eodag.config.PluginConfig.retry_total` (``int``): :class:`urllib3.util.Retry` ``total`` parameter,
|
|
73
|
+
total number of retries to allow; default: ``3``
|
|
74
|
+
* :attr:`~eodag.config.PluginConfig.retry_backoff_factor` (``int``): :class:`urllib3.util.Retry`
|
|
75
|
+
``backoff_factor`` parameter, backoff factor to apply between attempts after the second try; default: ``2``
|
|
76
|
+
* :attr:`~eodag.config.PluginConfig.retry_status_forcelist` (``List[int]``): :class:`urllib3.util.Retry`
|
|
77
|
+
``status_forcelist`` parameter, list of integer HTTP status codes that we should force a retry on; default:
|
|
78
|
+
``[401, 429, 500, 502, 503, 504]``
|
|
79
|
+
"""
|
|
45
80
|
|
|
46
81
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
47
82
|
super(TokenAuth, self).__init__(provider, config)
|
|
@@ -89,14 +124,15 @@ class TokenAuth(Authentication):
|
|
|
89
124
|
and e.response.status_code in auth_errors
|
|
90
125
|
):
|
|
91
126
|
raise AuthenticationError(
|
|
92
|
-
f"
|
|
93
|
-
f"
|
|
94
|
-
|
|
127
|
+
f"Please check your credentials for {self.provider}.",
|
|
128
|
+
f"HTTP Error {e.response.status_code} returned.",
|
|
129
|
+
response_text,
|
|
130
|
+
) from e
|
|
95
131
|
# other error
|
|
96
132
|
else:
|
|
97
133
|
raise AuthenticationError(
|
|
98
|
-
|
|
99
|
-
)
|
|
134
|
+
"Could no get authentication token", str(e), response_text
|
|
135
|
+
) from e
|
|
100
136
|
else:
|
|
101
137
|
if getattr(self.config, "token_type", "text") == "json":
|
|
102
138
|
token = response.json()[self.config.token_key]
|
|
@@ -116,16 +152,25 @@ class TokenAuth(Authentication):
|
|
|
116
152
|
self,
|
|
117
153
|
session: requests.Session,
|
|
118
154
|
) -> requests.Response:
|
|
155
|
+
retry_total = getattr(self.config, "retry_total", REQ_RETRY_TOTAL)
|
|
156
|
+
retry_backoff_factor = getattr(
|
|
157
|
+
self.config, "retry_backoff_factor", REQ_RETRY_BACKOFF_FACTOR
|
|
158
|
+
)
|
|
159
|
+
retry_status_forcelist = getattr(
|
|
160
|
+
self.config, "retry_status_forcelist", REQ_RETRY_STATUS_FORCELIST
|
|
161
|
+
)
|
|
162
|
+
|
|
119
163
|
retries = Retry(
|
|
120
|
-
total=
|
|
121
|
-
backoff_factor=
|
|
122
|
-
status_forcelist=
|
|
164
|
+
total=retry_total,
|
|
165
|
+
backoff_factor=retry_backoff_factor,
|
|
166
|
+
status_forcelist=retry_status_forcelist,
|
|
123
167
|
)
|
|
124
168
|
|
|
125
169
|
# append headers to req if some are specified in config
|
|
126
170
|
req_kwargs: Dict[str, Any] = {
|
|
127
171
|
"headers": dict(self.config.headers, **USER_AGENT)
|
|
128
172
|
}
|
|
173
|
+
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
129
174
|
|
|
130
175
|
if self.refresh_token:
|
|
131
176
|
logger.debug("fetching access token with refresh token")
|
|
@@ -135,6 +180,7 @@ class TokenAuth(Authentication):
|
|
|
135
180
|
self.config.refresh_uri,
|
|
136
181
|
data={"refresh_token": self.refresh_token},
|
|
137
182
|
timeout=HTTP_REQ_TIMEOUT,
|
|
183
|
+
verify=ssl_verify,
|
|
138
184
|
**req_kwargs,
|
|
139
185
|
)
|
|
140
186
|
response.raise_for_status()
|
|
@@ -170,6 +216,7 @@ class TokenAuth(Authentication):
|
|
|
170
216
|
method=method,
|
|
171
217
|
url=self.config.auth_uri,
|
|
172
218
|
timeout=HTTP_REQ_TIMEOUT,
|
|
219
|
+
verify=ssl_verify,
|
|
173
220
|
**req_kwargs,
|
|
174
221
|
)
|
|
175
222
|
|
|
@@ -197,7 +244,8 @@ class RequestsTokenAuth(AuthBase):
|
|
|
197
244
|
if self.where == "qs":
|
|
198
245
|
parts = urlparse(str(request.url))
|
|
199
246
|
qs = parse_qs(parts.query)
|
|
200
|
-
|
|
247
|
+
if self.qs_key is not None:
|
|
248
|
+
qs[self.qs_key] = [self.token]
|
|
201
249
|
request.url = urlunparse(
|
|
202
250
|
(
|
|
203
251
|
parts.scheme,
|
|
@@ -38,25 +38,23 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
38
38
|
"""Token exchange implementation using
|
|
39
39
|
:class:`~eodag.plugins.authentication.openid_connect.OIDCAuthorizationCodeFlowAuth` token as subject.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
:param provider: provider name
|
|
42
|
+
:param config: Authentication plugin configuration:
|
|
43
|
+
|
|
44
|
+
* :attr:`~eodag.config.PluginConfig.subject` (``Dict[str, Any]``) (**mandatory**):
|
|
45
|
+
The full :class:`~eodag.plugins.authentication.openid_connect.OIDCAuthorizationCodeFlowAuth` plugin
|
|
46
|
+
configuration used to retrieve subject token
|
|
47
|
+
* :attr:`~eodag.config.PluginConfig.subject_issuer` (``str``) (**mandatory**): Identifies
|
|
48
|
+
the issuer of the subject_token
|
|
49
|
+
* :attr:`~eodag.config.PluginConfig.token_uri` (``str``) (**mandatory**): The url to
|
|
50
|
+
query to get the authorized token
|
|
51
|
+
* :attr:`~eodag.config.PluginConfig.client_id` (``str``) (**mandatory**): The OIDC
|
|
52
|
+
provider's client ID of the eodag provider
|
|
53
|
+
* :attr:`~eodag.config.PluginConfig.audience` (``str``) (**mandatory**): This parameter
|
|
54
|
+
specifies the target client you want the new token minted for.
|
|
55
|
+
* :attr:`~eodag.config.PluginConfig.token_key` (``str``) (**mandatory**): The key
|
|
56
|
+
pointing to the token in the json response to the POST request to the token server
|
|
42
57
|
|
|
43
|
-
# (mandatory) The full OIDCAuthorizationCodeFlowAuth plugin configuration used to retrieve subject token
|
|
44
|
-
subject:
|
|
45
|
-
|
|
46
|
-
# (mandatory) Identifies the issuer of the subject_token
|
|
47
|
-
subject_issuer:
|
|
48
|
-
|
|
49
|
-
# (mandatory) The url to query to get the authorized token
|
|
50
|
-
token_uri:
|
|
51
|
-
|
|
52
|
-
# (mandatory) The OIDC provider's client ID of the eodag provider
|
|
53
|
-
client_id:
|
|
54
|
-
|
|
55
|
-
# (mandatory) This parameter specifies the target client you want the new token minted for.
|
|
56
|
-
audience:
|
|
57
|
-
|
|
58
|
-
# (mandatory) The key pointing to the token in the json response to the POST request to the token server
|
|
59
|
-
token_key:
|
|
60
58
|
"""
|
|
61
59
|
|
|
62
60
|
GRANT_TYPE = "urn:ietf:params:oauth:grant-type:token-exchange"
|
|
@@ -71,7 +69,7 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
71
69
|
]
|
|
72
70
|
|
|
73
71
|
def __init__(self, provider: str, config: PluginConfig) -> None:
|
|
74
|
-
super(
|
|
72
|
+
super().__init__(provider, config)
|
|
75
73
|
for required_key in self.REQUIRED_KEYS:
|
|
76
74
|
if getattr(self.config, required_key, None) is None:
|
|
77
75
|
raise MisconfiguredError(
|
|
@@ -100,12 +98,14 @@ class OIDCTokenExchangeAuth(Authentication):
|
|
|
100
98
|
"audience": self.config.audience,
|
|
101
99
|
}
|
|
102
100
|
logger.debug("Getting target auth token")
|
|
101
|
+
ssl_verify = getattr(self.config, "ssl_verify", True)
|
|
103
102
|
try:
|
|
104
103
|
auth_response = self.subject.session.post(
|
|
105
104
|
self.config.token_uri,
|
|
106
105
|
data=auth_data,
|
|
107
106
|
headers=USER_AGENT,
|
|
108
107
|
timeout=HTTP_REQ_TIMEOUT,
|
|
108
|
+
verify=ssl_verify,
|
|
109
109
|
)
|
|
110
110
|
auth_response.raise_for_status()
|
|
111
111
|
except requests.exceptions.Timeout as exc:
|
eodag/plugins/crunch/base.py
CHANGED
|
@@ -19,6 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
21
21
|
|
|
22
|
+
from eodag.config import PluginConfig
|
|
22
23
|
from eodag.plugins.base import PluginTopic
|
|
23
24
|
|
|
24
25
|
if TYPE_CHECKING:
|
|
@@ -26,10 +27,14 @@ if TYPE_CHECKING:
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class Crunch(PluginTopic):
|
|
29
|
-
"""Base cruncher
|
|
30
|
+
"""Base cruncher
|
|
31
|
+
|
|
32
|
+
:param config: Crunch configuration
|
|
33
|
+
"""
|
|
30
34
|
|
|
31
35
|
def __init__(self, config: Optional[Dict[str, Any]]) -> None:
|
|
32
|
-
self.config =
|
|
36
|
+
self.config = PluginConfig()
|
|
37
|
+
self.config.__dict__ = config if config is not None else {}
|
|
33
38
|
|
|
34
39
|
def proceed(
|
|
35
40
|
self, products: List[EOProduct], **search_params: Any
|
|
@@ -21,7 +21,7 @@ import datetime
|
|
|
21
21
|
import logging
|
|
22
22
|
import time
|
|
23
23
|
from datetime import datetime as dt
|
|
24
|
-
from typing import TYPE_CHECKING, Any,
|
|
24
|
+
from typing import TYPE_CHECKING, Any, List
|
|
25
25
|
|
|
26
26
|
import dateutil.parser
|
|
27
27
|
from dateutil import tz
|
|
@@ -37,16 +37,15 @@ logger = logging.getLogger("eodag.crunch.date")
|
|
|
37
37
|
class FilterDate(Crunch):
|
|
38
38
|
"""FilterDate cruncher: filter products by date
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Allows to filter out products that are older than a start date (optional) or more recent than an end date
|
|
41
|
+
(optional).
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
- `end`: (optional) end sensing time in iso format
|
|
43
|
+
:param config: Crunch configuration, may contain :
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
* ``start`` (``str``): start sensing time in iso format
|
|
46
|
+
* ``end`` (``str``): end sensing time in iso format
|
|
46
47
|
"""
|
|
47
48
|
|
|
48
|
-
config: Dict[str, str]
|
|
49
|
-
|
|
50
49
|
@staticmethod
|
|
51
50
|
def sort_product_by_start_date(product: EOProduct) -> dt:
|
|
52
51
|
"""Get product start date"""
|
|
@@ -63,16 +62,14 @@ class FilterDate(Crunch):
|
|
|
63
62
|
"""Execute crunch: Filter products between start and end dates.
|
|
64
63
|
|
|
65
64
|
:param products: A list of products resulting from a search
|
|
66
|
-
:type products: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
67
65
|
:returns: The filtered products
|
|
68
|
-
:rtype: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
69
66
|
"""
|
|
70
67
|
logger.debug("Start filtering by date")
|
|
71
68
|
if not products:
|
|
72
69
|
return []
|
|
73
70
|
|
|
74
71
|
# filter start date
|
|
75
|
-
filter_start_str = self.config.get("start", None)
|
|
72
|
+
filter_start_str = self.config.__dict__.get("start", None)
|
|
76
73
|
if filter_start_str:
|
|
77
74
|
filter_start = dateutil.parser.parse(filter_start_str)
|
|
78
75
|
if not filter_start.tzinfo:
|
|
@@ -81,7 +78,7 @@ class FilterDate(Crunch):
|
|
|
81
78
|
filter_start = None
|
|
82
79
|
|
|
83
80
|
# filter end date
|
|
84
|
-
filter_end_str = self.config.get("end", None)
|
|
81
|
+
filter_end_str = self.config.__dict__.get("end", None)
|
|
85
82
|
if filter_end_str:
|
|
86
83
|
filter_end = dateutil.parser.parse(filter_end_str)
|
|
87
84
|
if not filter_end.tzinfo:
|
|
@@ -39,7 +39,8 @@ logger = logging.getLogger("eodag.crunch.latest_intersect")
|
|
|
39
39
|
class FilterLatestIntersect(Crunch):
|
|
40
40
|
"""FilterLatestIntersect cruncher
|
|
41
41
|
|
|
42
|
-
Filter latest products (the ones with a the highest start date) that intersect search extent
|
|
42
|
+
Filter latest products (the ones with a the highest start date) that intersect search extent;
|
|
43
|
+
The configuration for this plugin is an empty dict
|
|
43
44
|
"""
|
|
44
45
|
|
|
45
46
|
@staticmethod
|
|
@@ -53,18 +54,15 @@ class FilterLatestIntersect(Crunch):
|
|
|
53
54
|
return dateutil.parser.parse(start_date)
|
|
54
55
|
|
|
55
56
|
def proceed(
|
|
56
|
-
self, products: List[EOProduct], **search_params: Any
|
|
57
|
+
self, products: List[EOProduct], **search_params: Dict[str, Any]
|
|
57
58
|
) -> List[EOProduct]:
|
|
58
59
|
"""Execute crunch:
|
|
59
60
|
Filter latest products (the ones with a the highest start date) that intersect search extent.
|
|
60
61
|
|
|
61
62
|
:param products: A list of products resulting from a search
|
|
62
|
-
:
|
|
63
|
-
|
|
64
|
-
or search `geom` (:class:`shapely.geometry.base.BaseGeometry`) argument will be used
|
|
65
|
-
:type search_params: dict
|
|
63
|
+
:param search_params: Search criteria that must contain ``geometry`` or ``geom`` parameters having value of
|
|
64
|
+
type :class:`shapely.geometry.base.BaseGeometry` or ``Dict[str, Any]``
|
|
66
65
|
:returns: The filtered products
|
|
67
|
-
:rtype: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
68
66
|
"""
|
|
69
67
|
logger.debug("Start filtering for latest products")
|
|
70
68
|
if not products:
|
|
@@ -26,6 +26,7 @@ from eodag.utils.exceptions import ValidationError
|
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
28
|
from eodag.api.product import EOProduct
|
|
29
|
+
|
|
29
30
|
logger = logging.getLogger("eodag.crunch.latest_tpl_name")
|
|
30
31
|
|
|
31
32
|
|
|
@@ -36,9 +37,7 @@ class FilterLatestByName(Crunch):
|
|
|
36
37
|
|
|
37
38
|
:param config: Crunch configuration, must contain :
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
:type config: dict
|
|
40
|
+
* ``name_pattern`` (``str``) (**mandatory**): product name pattern
|
|
42
41
|
"""
|
|
43
42
|
|
|
44
43
|
NAME_PATTERN_CONSTRAINT = re.compile(r"\(\?P<tileid>\\d\{6\}\)")
|
|
@@ -60,9 +59,7 @@ class FilterLatestByName(Crunch):
|
|
|
60
59
|
"""Execute crunch: Filter Search results to get only the latest product, based on the name of the product
|
|
61
60
|
|
|
62
61
|
:param products: A list of products resulting from a search
|
|
63
|
-
:type products: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
64
62
|
:returns: The filtered products
|
|
65
|
-
:rtype: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
66
63
|
"""
|
|
67
64
|
logger.debug("Starting products filtering")
|
|
68
65
|
processed: List[str] = []
|
|
@@ -40,15 +40,12 @@ class FilterOverlap(Crunch):
|
|
|
40
40
|
|
|
41
41
|
Filter products, retaining only those that are overlapping with the search_extent
|
|
42
42
|
|
|
43
|
-
:param config: Crunch configuration
|
|
43
|
+
:param config: Crunch configuration may contain the following parameters which are mutually exclusive:
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
These configuration parameters are mutually exclusive.
|
|
51
|
-
:type config: dict
|
|
45
|
+
* ``minimum_overlap`` (``Union[float, str]``): minimal overlap percentage; default: ``"0"``
|
|
46
|
+
* ``contains`` (``bool``): ``True`` if product geometry contains the search area; default: ``False``
|
|
47
|
+
* ``intersects`` (``bool``): ``True`` if product geometry intersects the search area; default: ``False``
|
|
48
|
+
* ``within`` (``bool``): ``True`` if product geometry is within the search area; default: ``False``
|
|
52
49
|
"""
|
|
53
50
|
|
|
54
51
|
def proceed(
|
|
@@ -57,11 +54,8 @@ class FilterOverlap(Crunch):
|
|
|
57
54
|
"""Execute crunch: Filter products, retaining only those that are overlapping with the search_extent
|
|
58
55
|
|
|
59
56
|
:param products: A list of products resulting from a search
|
|
60
|
-
:type products: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
61
57
|
:param search_params: Search criteria that must contain `geometry`
|
|
62
|
-
:type search_params: dict
|
|
63
58
|
:returns: The filtered products
|
|
64
|
-
:rtype: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
65
59
|
"""
|
|
66
60
|
logger.debug("Start filtering for overlapping products")
|
|
67
61
|
filtered: List[EOProduct] = []
|
|
@@ -73,10 +67,10 @@ class FilterOverlap(Crunch):
|
|
|
73
67
|
"geometry not found in cruncher arguments, filtering disabled."
|
|
74
68
|
)
|
|
75
69
|
return products
|
|
76
|
-
minimum_overlap = float(self.config.get("minimum_overlap", "0"))
|
|
77
|
-
contains = self.config.get("contains", False)
|
|
78
|
-
intersects = self.config.get("intersects", False)
|
|
79
|
-
within = self.config.get("within", False)
|
|
70
|
+
minimum_overlap = float(self.config.__dict__.get("minimum_overlap", "0"))
|
|
71
|
+
contains = self.config.__dict__.get("contains", False)
|
|
72
|
+
intersects = self.config.__dict__.get("intersects", False)
|
|
73
|
+
within = self.config.__dict__.get("within", False)
|
|
80
74
|
|
|
81
75
|
if contains and (within or intersects) or (within and intersects):
|
|
82
76
|
logger.warning(
|
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import logging
|
|
21
21
|
import operator
|
|
22
|
-
from typing import TYPE_CHECKING, Any,
|
|
22
|
+
from typing import TYPE_CHECKING, Any, List
|
|
23
23
|
|
|
24
24
|
from eodag.plugins.crunch.base import Crunch
|
|
25
25
|
|
|
@@ -34,27 +34,22 @@ class FilterProperty(Crunch):
|
|
|
34
34
|
|
|
35
35
|
Filter products, retaining only those whose property match criteria
|
|
36
36
|
|
|
37
|
-
:param config: Crunch configuration,
|
|
37
|
+
:param config: Crunch configuration, must contain :
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
:type config: dict
|
|
39
|
+
* ``<property>`` ``(Any)`` (**mandatory**): property key from ``product.properties``, associated to its filter
|
|
40
|
+
value
|
|
41
|
+
* ``operator`` (``str``): Operator used for filtering (one of ``lt,le,eq,ne,ge,gt``). Default is ``eq``
|
|
43
42
|
"""
|
|
44
43
|
|
|
45
|
-
config: Dict[str, Union[str, Optional[str]]]
|
|
46
|
-
|
|
47
44
|
def proceed(
|
|
48
45
|
self, products: List[EOProduct], **search_params: Any
|
|
49
46
|
) -> List[EOProduct]:
|
|
50
47
|
"""Execute crunch: Filter products, retaining only those that match property filtering
|
|
51
48
|
|
|
52
49
|
:param products: A list of products resulting from a search
|
|
53
|
-
:type products: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
54
50
|
:returns: The filtered products
|
|
55
|
-
:rtype: list(:class:`~eodag.api.product._product.EOProduct`)
|
|
56
51
|
"""
|
|
57
|
-
operator_name = self.config.pop("operator", "eq") or "eq"
|
|
52
|
+
operator_name = self.config.__dict__.pop("operator", "eq") or "eq"
|
|
58
53
|
try:
|
|
59
54
|
operator_method = getattr(operator, operator_name)
|
|
60
55
|
except AttributeError:
|
|
@@ -64,12 +59,12 @@ class FilterProperty(Crunch):
|
|
|
64
59
|
)
|
|
65
60
|
return products
|
|
66
61
|
|
|
67
|
-
if len(self.config.keys()) != 1:
|
|
62
|
+
if len(self.config.__dict__.keys()) != 1:
|
|
68
63
|
logger.warning("One property is needed for filtering, filtering disabled.")
|
|
69
64
|
return products
|
|
70
65
|
|
|
71
|
-
property_key = next(iter(self.config))
|
|
72
|
-
property_value = self.config.get(property_key, None)
|
|
66
|
+
property_key = next(iter(self.config.__dict__))
|
|
67
|
+
property_value = self.config.__dict__.get(property_key, None)
|
|
73
68
|
|
|
74
69
|
logger.debug(
|
|
75
70
|
"Start filtering for products matching operator.%s(product.properties['%s'], %s)",
|