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/rest/types/eodag_search.py
CHANGED
|
@@ -49,10 +49,7 @@ from eodag.rest.utils.cql_evaluate import EodagEvaluator
|
|
|
49
49
|
from eodag.utils import DEFAULT_ITEMS_PER_PAGE
|
|
50
50
|
|
|
51
51
|
if TYPE_CHECKING:
|
|
52
|
-
|
|
53
|
-
from typing import Self
|
|
54
|
-
except ImportError:
|
|
55
|
-
from _typeshed import Self
|
|
52
|
+
from typing_extensions import Self
|
|
56
53
|
|
|
57
54
|
Geometry = Union[
|
|
58
55
|
Dict[str, Any],
|
|
@@ -113,18 +110,11 @@ class EODAGSearch(BaseModel):
|
|
|
113
110
|
illuminationAzimuthAngle: Optional[float] = Field(None, alias="view:sun_azimuth")
|
|
114
111
|
page: Optional[int] = Field(1)
|
|
115
112
|
items_per_page: int = Field(DEFAULT_ITEMS_PER_PAGE, alias="limit")
|
|
116
|
-
|
|
113
|
+
sort_by: Optional[List[Tuple[str, str]]] = Field(None, alias="sortby")
|
|
117
114
|
raise_errors: bool = False
|
|
118
115
|
|
|
119
116
|
_to_eodag_map: Dict[str, str]
|
|
120
117
|
|
|
121
|
-
@model_validator(mode="after")
|
|
122
|
-
def set_raise_errors(self) -> Self:
|
|
123
|
-
"""Set raise_errors to True if provider is set"""
|
|
124
|
-
if self.provider:
|
|
125
|
-
self.raise_errors = True
|
|
126
|
-
return self
|
|
127
|
-
|
|
128
118
|
@model_validator(mode="after")
|
|
129
119
|
def remove_timeFromAscendingNode(self) -> Self: # pylint: disable=invalid-name
|
|
130
120
|
"""TimeFromAscendingNode are just used for translation and not for search"""
|
|
@@ -314,14 +304,14 @@ class EODAGSearch(BaseModel):
|
|
|
314
304
|
return ",".join(v)
|
|
315
305
|
return v
|
|
316
306
|
|
|
317
|
-
@field_validator("
|
|
307
|
+
@field_validator("sort_by", mode="before")
|
|
318
308
|
@classmethod
|
|
319
309
|
def parse_sortby(
|
|
320
310
|
cls,
|
|
321
311
|
sortby_post_params: List[Dict[str, str]],
|
|
322
312
|
) -> List[Tuple[str, str]]:
|
|
323
313
|
"""
|
|
324
|
-
Convert STAC POST sortby to EODAG
|
|
314
|
+
Convert STAC POST sortby to EODAG sort_by
|
|
325
315
|
"""
|
|
326
316
|
special_fields = {
|
|
327
317
|
"start": "startTimeFromAscendingNode",
|
|
@@ -370,9 +360,21 @@ class EODAGSearch(BaseModel):
|
|
|
370
360
|
return cls._to_eodag_map.get(value, value)
|
|
371
361
|
|
|
372
362
|
@classmethod
|
|
373
|
-
def to_stac(
|
|
363
|
+
def to_stac(
|
|
364
|
+
cls,
|
|
365
|
+
field_name: str,
|
|
366
|
+
stac_item_properties: Optional[List[str]] = None,
|
|
367
|
+
provider: Optional[str] = None,
|
|
368
|
+
) -> str:
|
|
374
369
|
"""Get the alias of a field in a Pydantic model"""
|
|
375
370
|
field = cls.model_fields.get(field_name)
|
|
376
371
|
if field is not None and field.alias is not None:
|
|
377
372
|
return field.alias
|
|
373
|
+
if (
|
|
374
|
+
provider
|
|
375
|
+
and ":" not in field_name
|
|
376
|
+
and stac_item_properties
|
|
377
|
+
and field_name not in stac_item_properties
|
|
378
|
+
):
|
|
379
|
+
return f"{provider}:{field_name}"
|
|
378
380
|
return field_name
|
eodag/rest/types/queryables.py
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from typing import TYPE_CHECKING, Any, ClassVar, Dict, List, Optional, Union
|
|
20
|
+
from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Dict, List, Optional, Union
|
|
21
21
|
|
|
22
22
|
from pydantic import (
|
|
23
23
|
BaseModel,
|
|
@@ -32,7 +32,6 @@ from pydantic import (
|
|
|
32
32
|
from eodag.rest.types.eodag_search import EODAGSearch
|
|
33
33
|
from eodag.rest.utils.rfc3339 import str_to_interval
|
|
34
34
|
from eodag.types import python_field_definition_to_json
|
|
35
|
-
from eodag.utils import Annotated
|
|
36
35
|
|
|
37
36
|
if TYPE_CHECKING:
|
|
38
37
|
from pydantic.fields import FieldInfo
|
|
@@ -51,14 +50,16 @@ class QueryablesGetParams(BaseModel):
|
|
|
51
50
|
dumped: Dict[str, Any] = handler(self)
|
|
52
51
|
return {EODAGSearch.to_eodag(k): v for k, v in dumped.items()}
|
|
53
52
|
|
|
54
|
-
|
|
53
|
+
# use [prop-decorator] mypy error code when mypy==1.12 is released
|
|
54
|
+
@computed_field # type: ignore[misc]
|
|
55
55
|
@property
|
|
56
56
|
def start_datetime(self) -> Optional[str]:
|
|
57
57
|
"""Extract start_datetime property from datetime"""
|
|
58
58
|
start = str_to_interval(self.datetime)[0]
|
|
59
59
|
return start.strftime("%Y-%m-%dT%H:%M:%SZ") if start else None
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
# use [prop-decorator] mypy error code when mypy==1.12 is released
|
|
62
|
+
@computed_field # type: ignore[misc]
|
|
62
63
|
@property
|
|
63
64
|
def end_datetime(self) -> Optional[str]:
|
|
64
65
|
"""Extract end_datetime property from datetime"""
|
|
@@ -70,11 +71,8 @@ class StacQueryableProperty(BaseModel):
|
|
|
70
71
|
"""A class representing a queryable property.
|
|
71
72
|
|
|
72
73
|
:param description: The description of the queryables property
|
|
73
|
-
:type description: str
|
|
74
74
|
:param ref: (optional) A reference link to the schema of the property.
|
|
75
|
-
:type ref: str
|
|
76
75
|
:param type: (optional) possible types of the property
|
|
77
|
-
:type type: list[str]
|
|
78
76
|
"""
|
|
79
77
|
|
|
80
78
|
description: str
|
|
@@ -114,19 +112,12 @@ class StacQueryables(BaseModel):
|
|
|
114
112
|
"""A class representing queryable properties for the STAC API.
|
|
115
113
|
|
|
116
114
|
:param json_schema: The URL of the JSON schema.
|
|
117
|
-
:type json_schema: str
|
|
118
115
|
:param q_id: (optional) The identifier of the queryables.
|
|
119
|
-
:type q_id: str
|
|
120
116
|
:param q_type: The type of the object.
|
|
121
|
-
:type q_type: str
|
|
122
117
|
:param title: The title of the queryables.
|
|
123
|
-
:type title: str
|
|
124
118
|
:param description: The description of the queryables
|
|
125
|
-
:type description: str
|
|
126
119
|
:param properties: A dictionary of queryable properties.
|
|
127
|
-
:type properties: dict
|
|
128
120
|
:param additional_properties: Whether additional properties are allowed.
|
|
129
|
-
:type additional_properties: bool
|
|
130
121
|
"""
|
|
131
122
|
|
|
132
123
|
json_schema: str = Field(
|
eodag/rest/types/stac_search.py
CHANGED
|
@@ -16,9 +16,20 @@
|
|
|
16
16
|
# See the License for the specific language governing permissions and
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
"""Model describing a STAC search POST request"""
|
|
19
|
+
|
|
19
20
|
from __future__ import annotations
|
|
20
21
|
|
|
21
|
-
from typing import
|
|
22
|
+
from typing import (
|
|
23
|
+
TYPE_CHECKING,
|
|
24
|
+
Annotated,
|
|
25
|
+
Any,
|
|
26
|
+
Dict,
|
|
27
|
+
List,
|
|
28
|
+
Literal,
|
|
29
|
+
Optional,
|
|
30
|
+
Tuple,
|
|
31
|
+
Union,
|
|
32
|
+
)
|
|
22
33
|
|
|
23
34
|
import geojson
|
|
24
35
|
from pydantic import (
|
|
@@ -42,16 +53,12 @@ from shapely.geometry import (
|
|
|
42
53
|
shape,
|
|
43
54
|
)
|
|
44
55
|
from shapely.geometry.base import GEOMETRY_TYPES, BaseGeometry
|
|
45
|
-
from typing_extensions import Annotated
|
|
46
56
|
|
|
47
57
|
from eodag.rest.utils.rfc3339 import rfc3339_str_to_datetime, str_to_interval
|
|
48
58
|
from eodag.utils.exceptions import ValidationError
|
|
49
59
|
|
|
50
60
|
if TYPE_CHECKING:
|
|
51
|
-
|
|
52
|
-
from typing import Self
|
|
53
|
-
except ImportError:
|
|
54
|
-
from _typeshed import Self
|
|
61
|
+
from typing_extensions import Self
|
|
55
62
|
|
|
56
63
|
NumType = Union[float, int]
|
|
57
64
|
|
|
@@ -74,15 +81,13 @@ Geometry = Union[
|
|
|
74
81
|
Direction = Annotated[Literal["asc", "desc"], StringConstraints(min_length=1)]
|
|
75
82
|
|
|
76
83
|
|
|
77
|
-
class
|
|
84
|
+
class SortBy(BaseModel):
|
|
78
85
|
"""
|
|
79
86
|
A class representing a parameter with which we want to sort results and its sorting order in a
|
|
80
87
|
POST search
|
|
81
88
|
|
|
82
89
|
:param field: The name of the parameter with which we want to sort results
|
|
83
|
-
:type field: str
|
|
84
90
|
:param direction: The sorting order of the parameter
|
|
85
|
-
:type direction: str
|
|
86
91
|
"""
|
|
87
92
|
|
|
88
93
|
__pydantic_config__ = ConfigDict(extra="forbid")
|
|
@@ -120,7 +125,7 @@ class SearchPostRequest(BaseModel):
|
|
|
120
125
|
description="The language used for filtering.",
|
|
121
126
|
validate_default=True,
|
|
122
127
|
)
|
|
123
|
-
sortby: Optional[List[
|
|
128
|
+
sortby: Optional[List[SortBy]] = None
|
|
124
129
|
crunch: Optional[str] = None
|
|
125
130
|
|
|
126
131
|
@field_serializer("intersects")
|
|
@@ -262,16 +267,16 @@ class SearchPostRequest(BaseModel):
|
|
|
262
267
|
|
|
263
268
|
def sortby2list(
|
|
264
269
|
v: Optional[str],
|
|
265
|
-
) -> Optional[List[
|
|
270
|
+
) -> Optional[List[SortBy]]:
|
|
266
271
|
"""
|
|
267
272
|
Convert sortby filter parameter GET syntax to POST syntax
|
|
268
273
|
"""
|
|
269
274
|
if not v:
|
|
270
275
|
return None
|
|
271
|
-
sortby: List[
|
|
276
|
+
sortby: List[SortBy] = []
|
|
272
277
|
for sortby_param in v.split(","):
|
|
273
278
|
sortby_param = sortby_param.strip()
|
|
274
279
|
direction: Direction = "desc" if sortby_param.startswith("-") else "asc"
|
|
275
280
|
field = sortby_param.lstrip("+-")
|
|
276
|
-
sortby.append(
|
|
281
|
+
sortby.append(SortBy(field=field, direction=direction))
|
|
277
282
|
return sortby
|
eodag/rest/utils/rfc3339.py
CHANGED
eodag/types/__init__.py
CHANGED
|
@@ -18,13 +18,25 @@
|
|
|
18
18
|
"""EODAG types"""
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
from typing import
|
|
21
|
+
from typing import (
|
|
22
|
+
Annotated,
|
|
23
|
+
Any,
|
|
24
|
+
Dict,
|
|
25
|
+
List,
|
|
26
|
+
Literal,
|
|
27
|
+
Optional,
|
|
28
|
+
Tuple,
|
|
29
|
+
TypedDict,
|
|
30
|
+
Union,
|
|
31
|
+
get_args,
|
|
32
|
+
get_origin,
|
|
33
|
+
)
|
|
22
34
|
|
|
23
35
|
from annotated_types import Gt, Lt
|
|
24
36
|
from pydantic import Field
|
|
25
37
|
from pydantic.fields import FieldInfo
|
|
26
38
|
|
|
27
|
-
from eodag.utils import
|
|
39
|
+
from eodag.utils import copy_deepcopy
|
|
28
40
|
from eodag.utils.exceptions import ValidationError
|
|
29
41
|
|
|
30
42
|
# Types mapping from JSON Schema and OpenAPI 3.1.0 specifications to Python
|
|
@@ -183,7 +195,7 @@ def python_field_definition_to_json(
|
|
|
183
195
|
"""Get json field definition from python `typing.Annotated`
|
|
184
196
|
|
|
185
197
|
>>> from pydantic import Field
|
|
186
|
-
>>> from
|
|
198
|
+
>>> from typing import Annotated
|
|
187
199
|
>>> python_field_definition_to_json(
|
|
188
200
|
... Annotated[
|
|
189
201
|
... Optional[str],
|
|
@@ -200,7 +212,7 @@ def python_field_definition_to_json(
|
|
|
200
212
|
"%s must be an instance of Annotated" % python_field_definition
|
|
201
213
|
)
|
|
202
214
|
|
|
203
|
-
json_field_definition = dict()
|
|
215
|
+
json_field_definition: Dict[str, Any] = dict()
|
|
204
216
|
|
|
205
217
|
python_field_args = get_args(python_field_definition)
|
|
206
218
|
|
|
@@ -210,6 +222,10 @@ def python_field_definition_to_json(
|
|
|
210
222
|
type_data = python_type_to_json(type(enum_args[0]))
|
|
211
223
|
if isinstance(type_data, str):
|
|
212
224
|
json_field_definition["type"] = type_data
|
|
225
|
+
elif type_data is None:
|
|
226
|
+
json_field_definition["type"] = json_field_definition[
|
|
227
|
+
"min"
|
|
228
|
+
] = json_field_definition["max"] = None
|
|
213
229
|
else:
|
|
214
230
|
json_field_definition["type"] = [row["type"] for row in type_data]
|
|
215
231
|
json_field_definition["min"] = [
|
|
@@ -224,6 +240,10 @@ def python_field_definition_to_json(
|
|
|
224
240
|
field_type = python_type_to_json(python_field_args[0])
|
|
225
241
|
if isinstance(field_type, str):
|
|
226
242
|
json_field_definition["type"] = field_type
|
|
243
|
+
elif field_type is None:
|
|
244
|
+
json_field_definition["type"] = json_field_definition[
|
|
245
|
+
"min"
|
|
246
|
+
] = json_field_definition["max"] = None
|
|
227
247
|
else:
|
|
228
248
|
json_field_definition["type"] = [row["type"] for row in field_type]
|
|
229
249
|
json_field_definition["min"] = [
|
|
@@ -300,9 +320,7 @@ class ProviderSortables(TypedDict):
|
|
|
300
320
|
maximum number of used sortable(s) in a search request with the provider
|
|
301
321
|
|
|
302
322
|
:param sortables: The list of sortable parameter(s) of a provider
|
|
303
|
-
:type sortables: list[str]
|
|
304
323
|
:param max_sort_params: (optional) The allowed maximum number of sortable(s) in a search request with the provider
|
|
305
|
-
:type max_sort_params: int
|
|
306
324
|
"""
|
|
307
325
|
|
|
308
326
|
sortables: List[str]
|
eodag/types/download_args.py
CHANGED
|
@@ -17,15 +17,24 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
from typing import Dict, TypedDict
|
|
20
|
+
from typing import Dict, Optional, TypedDict
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class DownloadConf(TypedDict, total=False):
|
|
24
|
-
"""Download configuration
|
|
24
|
+
"""Download configuration
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
:cvar output_dir: where to store downloaded products, as an absolute file path
|
|
27
|
+
(Default: local temporary directory)
|
|
28
|
+
:cvar output_extension: downloaded file extension
|
|
29
|
+
:cvar extract: whether to extract the downloaded products, only applies to archived products
|
|
30
|
+
:cvar dl_url_params: additional parameters to pass over to the download url as an url parameter
|
|
31
|
+
:cvar delete_archive: whether to delete the downloaded archives
|
|
32
|
+
:cvar asset: regex filter to identify assets to download
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
output_dir: str
|
|
36
|
+
output_extension: str
|
|
28
37
|
extract: bool
|
|
29
38
|
dl_url_params: Dict[str, str]
|
|
30
39
|
delete_archive: bool
|
|
31
|
-
asset: str
|
|
40
|
+
asset: Optional[str]
|
eodag/types/queryables.py
CHANGED
|
@@ -15,12 +15,11 @@
|
|
|
15
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
16
|
# See the License for the specific language governing permissions and
|
|
17
17
|
# limitations under the License.
|
|
18
|
-
from typing import Optional
|
|
18
|
+
from typing import Annotated, Optional
|
|
19
19
|
|
|
20
20
|
from annotated_types import Lt
|
|
21
21
|
from pydantic import BaseModel, Field
|
|
22
22
|
from pydantic.types import PositiveInt
|
|
23
|
-
from typing_extensions import Annotated
|
|
24
23
|
|
|
25
24
|
Percentage = Annotated[PositiveInt, Lt(100)]
|
|
26
25
|
|
eodag/types/search_args.py
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
# limitations under the License.
|
|
18
18
|
import re
|
|
19
19
|
from datetime import datetime
|
|
20
|
-
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
|
20
|
+
from typing import Annotated, Any, Dict, List, Optional, Tuple, Union, cast
|
|
21
21
|
|
|
22
22
|
from annotated_types import MinLen
|
|
23
23
|
from pydantic import BaseModel, ConfigDict, Field, conint, field_validator
|
|
@@ -27,7 +27,7 @@ from shapely.geometry import Polygon, shape
|
|
|
27
27
|
from shapely.geometry.base import GEOMETRY_TYPES, BaseGeometry
|
|
28
28
|
|
|
29
29
|
from eodag.types.bbox import BBox
|
|
30
|
-
from eodag.utils import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE
|
|
30
|
+
from eodag.utils import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE
|
|
31
31
|
from eodag.utils.exceptions import ValidationError
|
|
32
32
|
|
|
33
33
|
NumType = Union[float, int]
|
|
@@ -51,7 +51,7 @@ class SearchArgs(BaseModel):
|
|
|
51
51
|
locations: Optional[Dict[str, str]] = Field(None)
|
|
52
52
|
page: Optional[int] = Field(DEFAULT_PAGE, gt=0) # type: ignore
|
|
53
53
|
items_per_page: Optional[PositiveInt] = Field(DEFAULT_ITEMS_PER_PAGE) # type: ignore
|
|
54
|
-
|
|
54
|
+
sort_by: Optional[SortByList] = Field(None) # type: ignore
|
|
55
55
|
|
|
56
56
|
@field_validator("start", "end", mode="before")
|
|
57
57
|
@classmethod
|
|
@@ -87,18 +87,17 @@ class SearchArgs(BaseModel):
|
|
|
87
87
|
|
|
88
88
|
raise TypeError(f"Invalid geometry type: {type(v)}")
|
|
89
89
|
|
|
90
|
-
@field_validator("
|
|
90
|
+
@field_validator("sort_by", mode="before")
|
|
91
91
|
@classmethod
|
|
92
92
|
def check_sort_by_arg(
|
|
93
|
-
cls,
|
|
93
|
+
cls,
|
|
94
|
+
sort_by_arg: Optional[SortByList], # type: ignore
|
|
94
95
|
) -> Optional[SortByList]: # type: ignore
|
|
95
|
-
"""Check if the
|
|
96
|
+
"""Check if the sort_by argument is correct
|
|
96
97
|
|
|
97
|
-
:param sort_by_arg: The
|
|
98
|
-
:
|
|
99
|
-
:returns: The sortBy argument with sorting order parsed (whitespace(s) are
|
|
98
|
+
:param sort_by_arg: The sort_by argument
|
|
99
|
+
:returns: The sort_by argument with sorting order parsed (whitespace(s) are
|
|
100
100
|
removed and only the 3 first letters in uppercase are kept)
|
|
101
|
-
:rtype: str
|
|
102
101
|
"""
|
|
103
102
|
if sort_by_arg is None:
|
|
104
103
|
return None
|
|
@@ -120,7 +119,7 @@ class SearchArgs(BaseModel):
|
|
|
120
119
|
)
|
|
121
120
|
sort_by_arg[i] = (sort_param, sort_order[:3])
|
|
122
121
|
# remove duplicates
|
|
123
|
-
pruned_sort_by_arg: SortByList = list(
|
|
122
|
+
pruned_sort_by_arg: SortByList = list(dict.fromkeys(sort_by_arg)) # type: ignore
|
|
124
123
|
for i, sort_by_tuple in enumerate(pruned_sort_by_arg):
|
|
125
124
|
for j, sort_by_tuple_tmp in enumerate(pruned_sort_by_arg):
|
|
126
125
|
# since duplicated tuples or dictionnaries have been removed, if two sorting parameters are equal,
|
eodag/types/whoosh.py
CHANGED
|
@@ -56,9 +56,7 @@ class EODAGQueryParser(QueryParser):
|
|
|
56
56
|
EODAG QueryParser initialization
|
|
57
57
|
|
|
58
58
|
:param filters: list of fieldnames to filter on
|
|
59
|
-
:type filters: List[str]
|
|
60
59
|
:param schema: Whoosh Schema
|
|
61
|
-
:type schma: :class:whoosh.fields.Schema
|
|
62
60
|
"""
|
|
63
61
|
super().__init__(
|
|
64
62
|
None,
|