eodag 3.0.0b3__py3-none-any.whl → 3.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eodag/api/core.py +347 -247
- eodag/api/product/_assets.py +44 -15
- eodag/api/product/_product.py +58 -47
- eodag/api/product/drivers/__init__.py +81 -4
- eodag/api/product/drivers/base.py +65 -4
- eodag/api/product/drivers/generic.py +65 -0
- eodag/api/product/drivers/sentinel1.py +97 -0
- eodag/api/product/drivers/sentinel2.py +95 -0
- eodag/api/product/metadata_mapping.py +129 -93
- eodag/api/search_result.py +28 -12
- eodag/cli.py +61 -24
- eodag/config.py +457 -167
- eodag/plugins/apis/base.py +10 -4
- eodag/plugins/apis/ecmwf.py +53 -23
- eodag/plugins/apis/usgs.py +41 -17
- eodag/plugins/authentication/aws_auth.py +30 -18
- eodag/plugins/authentication/base.py +14 -3
- eodag/plugins/authentication/generic.py +14 -3
- eodag/plugins/authentication/header.py +14 -6
- eodag/plugins/authentication/keycloak.py +44 -25
- eodag/plugins/authentication/oauth.py +18 -4
- eodag/plugins/authentication/openid_connect.py +192 -171
- eodag/plugins/authentication/qsauth.py +12 -4
- eodag/plugins/authentication/sas_auth.py +22 -5
- eodag/plugins/authentication/token.py +95 -17
- eodag/plugins/authentication/token_exchange.py +19 -19
- eodag/plugins/base.py +4 -4
- eodag/plugins/crunch/base.py +8 -5
- eodag/plugins/crunch/filter_date.py +9 -6
- eodag/plugins/crunch/filter_latest_intersect.py +9 -8
- eodag/plugins/crunch/filter_latest_tpl_name.py +8 -8
- eodag/plugins/crunch/filter_overlap.py +9 -11
- eodag/plugins/crunch/filter_property.py +10 -10
- eodag/plugins/download/aws.py +181 -105
- eodag/plugins/download/base.py +49 -67
- eodag/plugins/download/creodias_s3.py +40 -2
- eodag/plugins/download/http.py +247 -223
- eodag/plugins/download/s3rest.py +29 -28
- eodag/plugins/manager.py +176 -41
- eodag/plugins/search/__init__.py +6 -5
- eodag/plugins/search/base.py +123 -60
- eodag/plugins/search/build_search_result.py +1046 -355
- eodag/plugins/search/cop_marine.py +132 -39
- eodag/plugins/search/creodias_s3.py +19 -68
- eodag/plugins/search/csw.py +48 -8
- eodag/plugins/search/data_request_search.py +124 -23
- eodag/plugins/search/qssearch.py +531 -310
- eodag/plugins/search/stac_list_assets.py +85 -0
- eodag/plugins/search/static_stac_search.py +23 -24
- eodag/resources/ext_product_types.json +1 -1
- eodag/resources/product_types.yml +1295 -355
- eodag/resources/providers.yml +1819 -3010
- eodag/resources/stac.yml +3 -163
- eodag/resources/stac_api.yml +2 -2
- eodag/resources/user_conf_template.yml +115 -99
- eodag/rest/cache.py +2 -2
- eodag/rest/config.py +3 -4
- eodag/rest/constants.py +0 -1
- eodag/rest/core.py +157 -117
- eodag/rest/errors.py +181 -0
- eodag/rest/server.py +57 -339
- eodag/rest/stac.py +133 -581
- eodag/rest/types/collections_search.py +3 -3
- eodag/rest/types/eodag_search.py +41 -30
- eodag/rest/types/queryables.py +42 -32
- eodag/rest/types/stac_search.py +15 -16
- eodag/rest/utils/__init__.py +14 -21
- eodag/rest/utils/cql_evaluate.py +6 -6
- eodag/rest/utils/rfc3339.py +2 -2
- eodag/types/__init__.py +153 -32
- eodag/types/bbox.py +2 -2
- eodag/types/download_args.py +4 -4
- eodag/types/queryables.py +183 -73
- eodag/types/search_args.py +6 -6
- eodag/types/whoosh.py +127 -3
- eodag/utils/__init__.py +228 -106
- eodag/utils/exceptions.py +47 -26
- eodag/utils/import_system.py +2 -2
- eodag/utils/logging.py +37 -77
- eodag/utils/repr.py +65 -6
- eodag/utils/requests.py +13 -15
- eodag/utils/rest.py +2 -2
- eodag/utils/s3.py +231 -0
- eodag/utils/stac_reader.py +11 -11
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/METADATA +81 -81
- eodag-3.1.0.dist-info/RECORD +113 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/WHEEL +1 -1
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/entry_points.txt +5 -2
- eodag/resources/constraints/climate-dt.json +0 -13
- eodag/resources/constraints/extremes-dt.json +0 -8
- eodag/utils/constraints.py +0 -244
- eodag-3.0.0b3.dist-info/RECORD +0 -110
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/LICENSE +0 -0
- {eodag-3.0.0b3.dist-info → eodag-3.1.0.dist-info}/top_level.txt +0 -0
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
|
|
20
|
+
from typing import Annotated, Any, Optional, Union, cast
|
|
21
21
|
|
|
22
22
|
from annotated_types import MinLen
|
|
23
23
|
from pydantic import BaseModel, ConfigDict, Field, conint, field_validator
|
|
@@ -27,14 +27,14 @@ 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]
|
|
34
|
-
GeomArgs = Union[
|
|
34
|
+
GeomArgs = Union[list[NumType], tuple[NumType], dict[str, NumType], str, BaseGeometry]
|
|
35
35
|
|
|
36
36
|
PositiveInt = conint(gt=0)
|
|
37
|
-
SortByList = Annotated[
|
|
37
|
+
SortByList = Annotated[list[tuple[str, str]], MinLen(1)]
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class SearchArgs(BaseModel):
|
|
@@ -48,7 +48,7 @@ class SearchArgs(BaseModel):
|
|
|
48
48
|
start: Optional[str] = Field(None)
|
|
49
49
|
end: Optional[str] = Field(None)
|
|
50
50
|
geom: Optional[BaseGeometry] = Field(None)
|
|
51
|
-
locations: Optional[
|
|
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
|
|
@@ -119,7 +119,7 @@ class SearchArgs(BaseModel):
|
|
|
119
119
|
)
|
|
120
120
|
sort_by_arg[i] = (sort_param, sort_order[:3])
|
|
121
121
|
# remove duplicates
|
|
122
|
-
pruned_sort_by_arg: SortByList = list(
|
|
122
|
+
pruned_sort_by_arg: SortByList = list(dict.fromkeys(sort_by_arg)) # type: ignore
|
|
123
123
|
for i, sort_by_tuple in enumerate(pruned_sort_by_arg):
|
|
124
124
|
for j, sort_by_tuple_tmp in enumerate(pruned_sort_by_arg):
|
|
125
125
|
# since duplicated tuples or dictionnaries have been removed, if two sorting parameters are equal,
|
eodag/types/whoosh.py
CHANGED
|
@@ -15,13 +15,14 @@
|
|
|
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 List
|
|
19
|
-
|
|
20
18
|
from whoosh.fields import Schema
|
|
19
|
+
from whoosh.index import _DEF_INDEX_NAME, FileIndex
|
|
21
20
|
from whoosh.matching import NullMatcher
|
|
22
21
|
from whoosh.qparser import OrGroup, QueryParser, plugins
|
|
23
22
|
from whoosh.query.positional import Phrase
|
|
24
23
|
from whoosh.query.qcore import QueryError
|
|
24
|
+
from whoosh.util.text import utf8encode
|
|
25
|
+
from whoosh.writing import SegmentWriter
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
class RobustPhrase(Phrase):
|
|
@@ -49,7 +50,7 @@ class EODAGQueryParser(QueryParser):
|
|
|
49
50
|
|
|
50
51
|
def __init__(
|
|
51
52
|
self,
|
|
52
|
-
filters:
|
|
53
|
+
filters: list[str],
|
|
53
54
|
schema: Schema,
|
|
54
55
|
):
|
|
55
56
|
"""
|
|
@@ -77,3 +78,126 @@ class EODAGQueryParser(QueryParser):
|
|
|
77
78
|
phraseclass=RobustPhrase,
|
|
78
79
|
group=OrGroup,
|
|
79
80
|
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class CleanSegmentWriter(SegmentWriter):
|
|
84
|
+
"""Override to clean up writer for failed document add when exceptions were absorbed
|
|
85
|
+
cf: https://github.com/whoosh-community/whoosh/pull/543
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def add_document(self, **fields):
|
|
89
|
+
"""Add document"""
|
|
90
|
+
self._check_state()
|
|
91
|
+
perdocwriter = self.perdocwriter
|
|
92
|
+
schema = self.schema
|
|
93
|
+
docnum = self.docnum
|
|
94
|
+
add_post = self.pool.add
|
|
95
|
+
|
|
96
|
+
docboost = self._doc_boost(fields)
|
|
97
|
+
fieldnames = sorted(
|
|
98
|
+
[name for name in fields.keys() if not name.startswith("_")]
|
|
99
|
+
)
|
|
100
|
+
self._check_fields(schema, fieldnames)
|
|
101
|
+
|
|
102
|
+
perdocwriter.start_doc(docnum)
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
for fieldname in fieldnames:
|
|
106
|
+
value = fields.get(fieldname)
|
|
107
|
+
if value is None:
|
|
108
|
+
continue
|
|
109
|
+
field = schema[fieldname]
|
|
110
|
+
|
|
111
|
+
length = 0
|
|
112
|
+
if field.indexed:
|
|
113
|
+
# TODO: Method for adding progressive field values, ie
|
|
114
|
+
# setting start_pos/start_char?
|
|
115
|
+
fieldboost = self._field_boost(fields, fieldname, docboost)
|
|
116
|
+
# Ask the field to return a list of (text, weight, vbytes)
|
|
117
|
+
# tuples
|
|
118
|
+
items = field.index(value)
|
|
119
|
+
# Only store the length if the field is marked scorable
|
|
120
|
+
scorable = field.scorable
|
|
121
|
+
# Add the terms to the pool
|
|
122
|
+
for tbytes, freq, weight, vbytes in items:
|
|
123
|
+
weight *= fieldboost
|
|
124
|
+
if scorable:
|
|
125
|
+
length += freq
|
|
126
|
+
add_post((fieldname, tbytes, docnum, weight, vbytes))
|
|
127
|
+
|
|
128
|
+
if field.separate_spelling():
|
|
129
|
+
spellfield = field.spelling_fieldname(fieldname)
|
|
130
|
+
for word in field.spellable_words(value):
|
|
131
|
+
word = utf8encode(word)[0]
|
|
132
|
+
add_post((spellfield, word, 0, 1, vbytes))
|
|
133
|
+
|
|
134
|
+
vformat = field.vector
|
|
135
|
+
if vformat:
|
|
136
|
+
analyzer = field.analyzer
|
|
137
|
+
# Call the format's word_values method to get posting values
|
|
138
|
+
vitems = vformat.word_values(value, analyzer, mode="index")
|
|
139
|
+
# Remove unused frequency field from the tuple
|
|
140
|
+
vitems = sorted(
|
|
141
|
+
(text, weight, vbytes) for text, _, weight, vbytes in vitems
|
|
142
|
+
)
|
|
143
|
+
perdocwriter.add_vector_items(fieldname, field, vitems)
|
|
144
|
+
|
|
145
|
+
# Allow a custom value for stored field/column
|
|
146
|
+
customval = fields.get("_stored_%s" % fieldname, value)
|
|
147
|
+
|
|
148
|
+
# Add the stored value and length for this field to the per-
|
|
149
|
+
# document writer
|
|
150
|
+
sv = customval if field.stored else None
|
|
151
|
+
perdocwriter.add_field(fieldname, field, sv, length)
|
|
152
|
+
|
|
153
|
+
column = field.column_type
|
|
154
|
+
if column and customval is not None:
|
|
155
|
+
cv = field.to_column_value(customval)
|
|
156
|
+
perdocwriter.add_column_value(fieldname, column, cv)
|
|
157
|
+
except Exception as ex:
|
|
158
|
+
# cancel doc
|
|
159
|
+
perdocwriter._doccount -= 1
|
|
160
|
+
perdocwriter._indoc = False
|
|
161
|
+
raise ex
|
|
162
|
+
|
|
163
|
+
perdocwriter.finish_doc()
|
|
164
|
+
self._added = True
|
|
165
|
+
self.docnum += 1
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class CleanFileIndex(FileIndex):
|
|
169
|
+
"""Override to call CleanSegmentWriter"""
|
|
170
|
+
|
|
171
|
+
def writer(self, procs=1, **kwargs):
|
|
172
|
+
"""file index writer"""
|
|
173
|
+
if procs > 1:
|
|
174
|
+
from whoosh.multiproc import MpWriter
|
|
175
|
+
|
|
176
|
+
return MpWriter(self, procs=procs, **kwargs)
|
|
177
|
+
else:
|
|
178
|
+
return CleanSegmentWriter(self, **kwargs)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def create_in(dirname, schema, indexname=None):
|
|
182
|
+
"""
|
|
183
|
+
Override to call the CleanFileIndex.
|
|
184
|
+
|
|
185
|
+
Convenience function to create an index in a directory. Takes care of
|
|
186
|
+
creating a FileStorage object for you.
|
|
187
|
+
|
|
188
|
+
:param dirname: the path string of the directory in which to create the
|
|
189
|
+
index.
|
|
190
|
+
:param schema: a :class:`whoosh.fields.Schema` object describing the
|
|
191
|
+
index's fields.
|
|
192
|
+
:param indexname: the name of the index to create; you only need to specify
|
|
193
|
+
this if you are creating multiple indexes within the same storage
|
|
194
|
+
object.
|
|
195
|
+
:returns: :class:`Index`
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
from whoosh.filedb.filestore import FileStorage
|
|
199
|
+
|
|
200
|
+
if not indexname:
|
|
201
|
+
indexname = _DEF_INDEX_NAME
|
|
202
|
+
storage = FileStorage(dirname)
|
|
203
|
+
return CleanFileIndex.create(storage, schema, indexname)
|