eodag 3.1.0b1__py3-none-any.whl → 3.1.0b2__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.
Files changed (85) hide show
  1. eodag/api/core.py +59 -52
  2. eodag/api/product/_assets.py +5 -5
  3. eodag/api/product/_product.py +27 -12
  4. eodag/api/product/drivers/__init__.py +81 -4
  5. eodag/api/product/drivers/base.py +65 -4
  6. eodag/api/product/drivers/generic.py +65 -0
  7. eodag/api/product/drivers/sentinel1.py +97 -0
  8. eodag/api/product/drivers/sentinel2.py +95 -0
  9. eodag/api/product/metadata_mapping.py +62 -74
  10. eodag/api/search_result.py +13 -23
  11. eodag/cli.py +4 -4
  12. eodag/config.py +66 -69
  13. eodag/plugins/apis/base.py +1 -1
  14. eodag/plugins/apis/ecmwf.py +10 -9
  15. eodag/plugins/apis/usgs.py +11 -10
  16. eodag/plugins/authentication/aws_auth.py +16 -13
  17. eodag/plugins/authentication/base.py +5 -3
  18. eodag/plugins/authentication/header.py +3 -3
  19. eodag/plugins/authentication/keycloak.py +4 -4
  20. eodag/plugins/authentication/oauth.py +7 -3
  21. eodag/plugins/authentication/openid_connect.py +14 -14
  22. eodag/plugins/authentication/sas_auth.py +4 -4
  23. eodag/plugins/authentication/token.py +7 -7
  24. eodag/plugins/authentication/token_exchange.py +1 -1
  25. eodag/plugins/base.py +4 -4
  26. eodag/plugins/crunch/base.py +4 -4
  27. eodag/plugins/crunch/filter_date.py +4 -4
  28. eodag/plugins/crunch/filter_latest_intersect.py +6 -6
  29. eodag/plugins/crunch/filter_latest_tpl_name.py +7 -7
  30. eodag/plugins/crunch/filter_overlap.py +4 -4
  31. eodag/plugins/crunch/filter_property.py +4 -4
  32. eodag/plugins/download/aws.py +47 -66
  33. eodag/plugins/download/base.py +8 -17
  34. eodag/plugins/download/creodias_s3.py +2 -2
  35. eodag/plugins/download/http.py +30 -32
  36. eodag/plugins/download/s3rest.py +5 -4
  37. eodag/plugins/manager.py +10 -20
  38. eodag/plugins/search/__init__.py +6 -5
  39. eodag/plugins/search/base.py +35 -40
  40. eodag/plugins/search/build_search_result.py +69 -68
  41. eodag/plugins/search/cop_marine.py +22 -12
  42. eodag/plugins/search/creodias_s3.py +8 -78
  43. eodag/plugins/search/csw.py +11 -11
  44. eodag/plugins/search/data_request_search.py +16 -15
  45. eodag/plugins/search/qssearch.py +56 -52
  46. eodag/plugins/search/stac_list_assets.py +85 -0
  47. eodag/plugins/search/static_stac_search.py +3 -3
  48. eodag/resources/ext_product_types.json +1 -1
  49. eodag/resources/product_types.yml +288 -288
  50. eodag/resources/providers.yml +146 -6
  51. eodag/resources/stac_api.yml +2 -2
  52. eodag/resources/user_conf_template.yml +11 -0
  53. eodag/rest/cache.py +2 -2
  54. eodag/rest/config.py +3 -3
  55. eodag/rest/core.py +24 -24
  56. eodag/rest/errors.py +5 -5
  57. eodag/rest/server.py +3 -11
  58. eodag/rest/stac.py +40 -38
  59. eodag/rest/types/collections_search.py +3 -3
  60. eodag/rest/types/eodag_search.py +23 -23
  61. eodag/rest/types/queryables.py +13 -13
  62. eodag/rest/types/stac_search.py +15 -25
  63. eodag/rest/utils/__init__.py +11 -21
  64. eodag/rest/utils/cql_evaluate.py +6 -6
  65. eodag/rest/utils/rfc3339.py +2 -2
  66. eodag/types/__init__.py +24 -18
  67. eodag/types/bbox.py +2 -2
  68. eodag/types/download_args.py +2 -2
  69. eodag/types/queryables.py +5 -2
  70. eodag/types/search_args.py +4 -4
  71. eodag/types/whoosh.py +1 -3
  72. eodag/utils/__init__.py +81 -40
  73. eodag/utils/exceptions.py +2 -2
  74. eodag/utils/import_system.py +2 -2
  75. eodag/utils/requests.py +2 -2
  76. eodag/utils/rest.py +2 -2
  77. eodag/utils/s3.py +208 -0
  78. eodag/utils/stac_reader.py +10 -10
  79. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/METADATA +5 -4
  80. eodag-3.1.0b2.dist-info/RECORD +113 -0
  81. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/entry_points.txt +1 -0
  82. eodag-3.1.0b1.dist-info/RECORD +0 -108
  83. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/LICENSE +0 -0
  84. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/WHEEL +0 -0
  85. {eodag-3.1.0b1.dist-info → eodag-3.1.0b2.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,7 @@ from __future__ import annotations
20
20
  import logging
21
21
  import os
22
22
  import os.path
23
- from typing import TYPE_CHECKING, Dict, List, Optional, Union
23
+ from typing import TYPE_CHECKING, Optional, Union
24
24
  from xml.dom import minidom
25
25
  from xml.parsers.expat import ExpatError
26
26
 
@@ -54,6 +54,7 @@ from eodag.utils.exceptions import (
54
54
  if TYPE_CHECKING:
55
55
  from eodag.api.product import EOProduct
56
56
  from eodag.config import PluginConfig
57
+ from eodag.types import S3SessionKwargs
57
58
  from eodag.types.download_args import DownloadConf
58
59
  from eodag.utils import Unpack
59
60
 
@@ -78,7 +79,7 @@ class S3RestDownload(Download):
78
79
  * :attr:`~eodag.config.PluginConfig.order_enabled` (``bool``): whether order is enabled
79
80
  or not if product is `OFFLINE`
80
81
  * :attr:`~eodag.config.PluginConfig.order_method` (``str``) HTTP request method, ``GET`` (default) or ``POST``
81
- * :attr:`~eodag.config.PluginConfig.order_headers` (``[Dict[str, str]]``): order request headers
82
+ * :attr:`~eodag.config.PluginConfig.order_headers` (``[dict[str, str]]``): order request headers
82
83
  * :attr:`~eodag.config.PluginConfig.order_on_response` (:class:`~eodag.config.PluginConfig.OrderOnResponse`):
83
84
  a typed dictionary containing the key :attr:`~eodag.config.PluginConfig.OrderOnResponse.metadata_mapping`
84
85
  which can be used to add new product properties based on the data in response to the order request
@@ -93,7 +94,7 @@ class S3RestDownload(Download):
93
94
  def download(
94
95
  self,
95
96
  product: EOProduct,
96
- auth: Optional[Union[AuthBase, Dict[str, str]]] = None,
97
+ auth: Optional[Union[AuthBase, S3SessionKwargs]] = None,
97
98
  progress_callback: Optional[ProgressCallback] = None,
98
99
  wait: float = DEFAULT_DOWNLOAD_WAIT,
99
100
  timeout: float = DEFAULT_DOWNLOAD_TIMEOUT,
@@ -270,7 +271,7 @@ class S3RestDownload(Download):
270
271
  os.remove(record_filename)
271
272
 
272
273
  # total size for progress_callback
273
- size_list: List[int] = [
274
+ size_list: list[int] = [
274
275
  int(node.firstChild.nodeValue) # type: ignore[attr-defined]
275
276
  for node in xmldoc.getElementsByTagName("Size")
276
277
  if node.firstChild is not None
eodag/plugins/manager.py CHANGED
@@ -21,18 +21,7 @@ import logging
21
21
  import re
22
22
  from operator import attrgetter
23
23
  from pathlib import Path
24
- from typing import (
25
- TYPE_CHECKING,
26
- Any,
27
- Dict,
28
- Iterator,
29
- List,
30
- Optional,
31
- Tuple,
32
- Type,
33
- Union,
34
- cast,
35
- )
24
+ from typing import TYPE_CHECKING, Any, Iterator, Optional, Union, cast
36
25
 
37
26
  import pkg_resources
38
27
 
@@ -61,6 +50,7 @@ if TYPE_CHECKING:
61
50
  from eodag.api.product import EOProduct
62
51
  from eodag.config import PluginConfig, ProviderConfig
63
52
  from eodag.plugins.base import PluginTopic
53
+ from eodag.types import S3SessionKwargs
64
54
 
65
55
 
66
56
  logger = logging.getLogger("eodag.plugins.manager")
@@ -84,11 +74,11 @@ class PluginManager:
84
74
 
85
75
  supported_topics = set(PLUGINS_TOPICS_KEYS)
86
76
 
87
- product_type_to_provider_config_map: Dict[str, List[ProviderConfig]]
77
+ product_type_to_provider_config_map: dict[str, list[ProviderConfig]]
88
78
 
89
- skipped_plugins: List[str]
79
+ skipped_plugins: list[str]
90
80
 
91
- def __init__(self, providers_config: Dict[str, ProviderConfig]) -> None:
81
+ def __init__(self, providers_config: dict[str, ProviderConfig]) -> None:
92
82
  self.skipped_plugins = []
93
83
  self.providers_config = providers_config
94
84
  # Load all the plugins. This will make all plugin classes of a particular
@@ -144,14 +134,14 @@ class PluginManager:
144
134
  self.rebuild()
145
135
 
146
136
  def rebuild(
147
- self, providers_config: Optional[Dict[str, ProviderConfig]] = None
137
+ self, providers_config: Optional[dict[str, ProviderConfig]] = None
148
138
  ) -> None:
149
139
  """(Re)Build plugin manager mapping and cache"""
150
140
  if providers_config is not None:
151
141
  self.providers_config = providers_config
152
142
 
153
143
  self.build_product_type_to_provider_config_map()
154
- self._built_plugins_cache: Dict[Tuple[str, str, str], Any] = {}
144
+ self._built_plugins_cache: dict[tuple[str, str, str], Any] = {}
155
145
 
156
146
  def build_product_type_to_provider_config_map(self) -> None:
157
147
  """Build mapping conf between product types and providers"""
@@ -211,7 +201,7 @@ class PluginManager:
211
201
  )
212
202
  return plugin
213
203
 
214
- configs: Optional[List[ProviderConfig]]
204
+ configs: Optional[list[ProviderConfig]]
215
205
  if product_type:
216
206
  configs = self.product_type_to_provider_config_map.get(product_type)
217
207
  if not configs:
@@ -378,7 +368,7 @@ class PluginManager:
378
368
  provider: str,
379
369
  matching_url: Optional[str] = None,
380
370
  matching_conf: Optional[PluginConfig] = None,
381
- ) -> Optional[Union[AuthBase, Dict[str, str]]]:
371
+ ) -> Optional[Union[AuthBase, S3SessionKwargs]]:
382
372
  """Authenticate and return the authenticated object for the first matching
383
373
  authentication plugin
384
374
 
@@ -447,7 +437,7 @@ class PluginManager:
447
437
  self,
448
438
  provider: str,
449
439
  plugin_conf: PluginConfig,
450
- topic_class: Type[PluginTopic],
440
+ topic_class: type[PluginTopic],
451
441
  ) -> Union[Api, Search, Download, Authentication, Crunch]:
452
442
  """Build the plugin of the given topic with the given plugin configuration and
453
443
  registered as the given provider
@@ -24,11 +24,12 @@ from typing import TYPE_CHECKING
24
24
  from eodag.utils import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE
25
25
 
26
26
  if TYPE_CHECKING:
27
- from typing import Any, Dict, List, Optional, Union
27
+ from typing import Any, Optional, Union
28
28
 
29
29
  from requests.auth import AuthBase
30
30
 
31
31
  from eodag.plugins.authentication.base import Authentication
32
+ from eodag.types import S3SessionKwargs
32
33
 
33
34
 
34
35
  @dataclass
@@ -38,7 +39,7 @@ class PreparedSearch:
38
39
  product_type: Optional[str] = None
39
40
  page: Optional[int] = DEFAULT_PAGE
40
41
  items_per_page: Optional[int] = DEFAULT_ITEMS_PER_PAGE
41
- auth: Optional[Union[AuthBase, Dict[str, str]]] = None
42
+ auth: Optional[Union[AuthBase, S3SessionKwargs]] = None
42
43
  auth_plugin: Optional[Authentication] = None
43
44
  count: bool = True
44
45
  url: Optional[str] = None
@@ -46,9 +47,9 @@ class PreparedSearch:
46
47
  exception_message: Optional[str] = None
47
48
 
48
49
  need_count: bool = field(init=False, repr=False)
49
- query_params: Dict[str, Any] = field(init=False, repr=False)
50
+ query_params: dict[str, Any] = field(init=False, repr=False)
50
51
  query_string: str = field(init=False, repr=False)
51
- search_urls: List[str] = field(init=False, repr=False)
52
- product_type_def_params: Dict[str, Any] = field(init=False, repr=False)
52
+ search_urls: list[str] = field(init=False, repr=False)
53
+ product_type_def_params: dict[str, Any] = field(init=False, repr=False)
53
54
  total_items_nb: int = field(init=False, repr=False)
54
55
  sort_by_qs: str = field(init=False, repr=False)
@@ -43,12 +43,13 @@ from eodag.utils import (
43
43
  from eodag.utils.exceptions import ValidationError
44
44
 
45
45
  if TYPE_CHECKING:
46
- from typing import Any, Dict, List, Optional, Tuple, Union
46
+ from typing import Any, Optional, Union
47
47
 
48
48
  from requests.auth import AuthBase
49
49
 
50
50
  from eodag.api.product import EOProduct
51
51
  from eodag.config import PluginConfig
52
+ from eodag.types import S3SessionKwargs
52
53
 
53
54
  logger = logging.getLogger("eodag.search.base")
54
55
 
@@ -60,9 +61,9 @@ class Search(PluginTopic):
60
61
  :param config: An EODAG plugin configuration
61
62
  """
62
63
 
63
- auth: Union[AuthBase, Dict[str, str]]
64
+ auth: Union[AuthBase, S3SessionKwargs]
64
65
  next_page_url: Optional[str]
65
- next_page_query_obj: Optional[Dict[str, Any]]
66
+ next_page_query_obj: Optional[dict[str, Any]]
66
67
  total_items_nb: int
67
68
  need_count: bool
68
69
  _request: Any # needed by deprecated load_stac_items
@@ -71,7 +72,7 @@ class Search(PluginTopic):
71
72
  super(Search, self).__init__(provider, config)
72
73
  # Prepare the metadata mapping
73
74
  # Do a shallow copy, the structure is flat enough for this to be sufficient
74
- metas: Dict[str, Any] = DEFAULT_METADATA_MAPPING.copy()
75
+ metas: dict[str, Any] = DEFAULT_METADATA_MAPPING.copy()
75
76
  # Update the defaults with the mapping value. This will add any new key
76
77
  # added by the provider mapping that is not in the default metadata
77
78
  if self.config.metadata_mapping:
@@ -90,7 +91,7 @@ class Search(PluginTopic):
90
91
  self,
91
92
  prep: PreparedSearch = PreparedSearch(),
92
93
  **kwargs: Any,
93
- ) -> Tuple[List[EOProduct], Optional[int]]:
94
+ ) -> tuple[list[EOProduct], Optional[int]]:
94
95
  """Implementation of how the products must be searched goes here.
95
96
 
96
97
  This method must return a tuple with (1) a list of :class:`~eodag.api.product._product.EOProduct` instances
@@ -99,13 +100,13 @@ class Search(PluginTopic):
99
100
  """
100
101
  raise NotImplementedError("A Search plugin must implement a method named query")
101
102
 
102
- def discover_product_types(self, **kwargs: Any) -> Optional[Dict[str, Any]]:
103
+ def discover_product_types(self, **kwargs: Any) -> Optional[dict[str, Any]]:
103
104
  """Fetch product types list from provider using `discover_product_types` conf"""
104
105
  return None
105
106
 
106
107
  def discover_queryables(
107
108
  self, **kwargs: Any
108
- ) -> Optional[Dict[str, Annotated[Any, FieldInfo]]]:
109
+ ) -> Optional[dict[str, Annotated[Any, FieldInfo]]]:
109
110
  """Fetch queryables list from provider using :attr:`~eodag.config.PluginConfig.discover_queryables` conf
110
111
 
111
112
  :param kwargs: additional filters for queryables (``productType`` and other search
@@ -118,7 +119,7 @@ class Search(PluginTopic):
118
119
 
119
120
  def _get_defaults_as_queryables(
120
121
  self, product_type: str
121
- ) -> Dict[str, Annotated[Any, FieldInfo]]:
122
+ ) -> dict[str, Annotated[Any, FieldInfo]]:
122
123
  """
123
124
  Return given product type default settings as queryables
124
125
 
@@ -128,7 +129,7 @@ class Search(PluginTopic):
128
129
  defaults = deepcopy(self.config.products.get(product_type, {}))
129
130
  defaults.pop("metadata_mapping", None)
130
131
 
131
- queryables: Dict[str, Annotated[Any, FieldInfo]] = {}
132
+ queryables: dict[str, Annotated[Any, FieldInfo]] = {}
132
133
  for parameter, value in defaults.items():
133
134
  queryables[parameter] = Annotated[type(value), Field(default=value)]
134
135
  return queryables
@@ -150,7 +151,7 @@ class Search(PluginTopic):
150
151
 
151
152
  def get_product_type_def_params(
152
153
  self, product_type: str, **kwargs: Any
153
- ) -> Dict[str, Any]:
154
+ ) -> dict[str, Any]:
154
155
  """Get the provider product type definition parameters and specific settings
155
156
 
156
157
  :param product_type: the desired product type
@@ -200,7 +201,7 @@ class Search(PluginTopic):
200
201
 
201
202
  def get_metadata_mapping(
202
203
  self, product_type: Optional[str] = None
203
- ) -> Dict[str, Union[str, List[str]]]:
204
+ ) -> dict[str, Union[str, list[str]]]:
204
205
  """Get the plugin metadata mapping configuration (product type specific if exists)
205
206
 
206
207
  :param product_type: the desired product type
@@ -212,7 +213,7 @@ class Search(PluginTopic):
212
213
  )
213
214
  return self.config.metadata_mapping
214
215
 
215
- def get_sort_by_arg(self, kwargs: Dict[str, Any]) -> Optional[SortByList]:
216
+ def get_sort_by_arg(self, kwargs: dict[str, Any]) -> Optional[SortByList]:
216
217
  """Extract the ``sort_by`` argument from the kwargs or the provider default sort configuration
217
218
 
218
219
  :param kwargs: Search arguments
@@ -233,7 +234,7 @@ class Search(PluginTopic):
233
234
 
234
235
  def build_sort_by(
235
236
  self, sort_by_arg: SortByList
236
- ) -> Tuple[str, Dict[str, List[Dict[str, str]]]]:
237
+ ) -> tuple[str, dict[str, list[dict[str, str]]]]:
237
238
  """Build the sorting part of the query string or body by transforming
238
239
  the ``sort_by`` argument into a provider-specific string or dictionary
239
240
 
@@ -247,9 +248,9 @@ class Search(PluginTopic):
247
248
  sort_by_arg = list(dict.fromkeys(sort_by_arg))
248
249
 
249
250
  sort_by_qs: str = ""
250
- sort_by_qp: Dict[str, Any] = {}
251
+ sort_by_qp: dict[str, Any] = {}
251
252
 
252
- provider_sort_by_tuples_used: List[Tuple[str, str]] = []
253
+ provider_sort_by_tuples_used: list[tuple[str, str]] = []
253
254
  for eodag_sort_by_tuple in sort_by_arg:
254
255
  eodag_sort_param = eodag_sort_by_tuple[0]
255
256
  provider_sort_param = self.config.sort["sort_param_mapping"].get(
@@ -282,7 +283,7 @@ class Search(PluginTopic):
282
283
  if eodag_sort_order == "ASC"
283
284
  else self.config.sort["sort_order_mapping"]["descending"]
284
285
  )
285
- provider_sort_by_tuple: Tuple[str, str] = (
286
+ provider_sort_by_tuple: tuple[str, str] = (
286
287
  provider_sort_param,
287
288
  provider_sort_order,
288
289
  )
@@ -315,7 +316,7 @@ class Search(PluginTopic):
315
316
  sort_order=provider_sort_by_tuple[1],
316
317
  )
317
318
  try:
318
- parsed_sort_by_tpl_dict: Dict[str, Any] = orjson.loads(
319
+ parsed_sort_by_tpl_dict: dict[str, Any] = orjson.loads(
319
320
  parsed_sort_by_tpl
320
321
  )
321
322
  sort_by_qp = update_nested_dict(
@@ -326,23 +327,25 @@ class Search(PluginTopic):
326
327
  return (sort_by_qs, sort_by_qp)
327
328
 
328
329
  def _get_product_type_queryables(
329
- self, product_type: Optional[str], alias: Optional[str], filters: Dict[str, Any]
330
- ) -> Dict[str, Annotated[Any, FieldInfo]]:
331
- default_values: Dict[str, Any] = deepcopy(
330
+ self, product_type: Optional[str], alias: Optional[str], filters: dict[str, Any]
331
+ ) -> QueryablesDict:
332
+ default_values: dict[str, Any] = deepcopy(
332
333
  getattr(self.config, "products", {}).get(product_type, {})
333
334
  )
334
335
  default_values.pop("metadata_mapping", None)
335
336
  try:
336
337
  filters["productType"] = product_type
337
- return self.discover_queryables(**{**default_values, **filters}) or {}
338
+ queryables = self.discover_queryables(**{**default_values, **filters}) or {}
338
339
  except NotImplementedError:
339
- return self.queryables_from_metadata_mapping(product_type, alias)
340
+ queryables = self.queryables_from_metadata_mapping(product_type, alias)
341
+
342
+ return QueryablesDict(**queryables)
340
343
 
341
344
  def list_queryables(
342
345
  self,
343
- filters: Dict[str, Any],
344
- available_product_types: List[Any],
345
- product_type_configs: Dict[str, Dict[str, Any]],
346
+ filters: dict[str, Any],
347
+ available_product_types: list[Any],
348
+ product_type_configs: dict[str, dict[str, Any]],
346
349
  product_type: Optional[str] = None,
347
350
  alias: Optional[str] = None,
348
351
  ) -> QueryablesDict:
@@ -369,19 +372,11 @@ class Search(PluginTopic):
369
372
  if product_type:
370
373
  self.config.product_type_config = product_type_configs[product_type]
371
374
  queryables = self._get_product_type_queryables(product_type, alias, filters)
372
- if getattr(self.config, "discover_queryables", {}).get(
373
- "constraints_url", ""
374
- ):
375
- additional_properties = False
376
- else:
377
- additional_properties = True
378
- return QueryablesDict(
379
- additional_properties=additional_properties,
380
- additional_information=additional_info,
381
- **queryables,
382
- )
375
+ queryables.additional_information = additional_info
376
+
377
+ return queryables
383
378
  else:
384
- all_queryables: Dict[str, Any] = {}
379
+ all_queryables: dict[str, Any] = {}
385
380
  for pt in available_product_types:
386
381
  self.config.product_type_config = product_type_configs[pt]
387
382
  pt_queryables = self._get_product_type_queryables(pt, None, filters)
@@ -399,18 +394,18 @@ class Search(PluginTopic):
399
394
 
400
395
  def queryables_from_metadata_mapping(
401
396
  self, product_type: Optional[str] = None, alias: Optional[str] = None
402
- ) -> Dict[str, Annotated[Any, FieldInfo]]:
397
+ ) -> dict[str, Annotated[Any, FieldInfo]]:
403
398
  """
404
399
  Extract queryable parameters from product type metadata mapping.
405
400
  :param product_type: product type id (optional)
406
401
  :param alias: (optional) alias of the product type
407
402
  :returns: dict of annotated queryables
408
403
  """
409
- metadata_mapping: Dict[str, Any] = deepcopy(
404
+ metadata_mapping: dict[str, Any] = deepcopy(
410
405
  self.get_metadata_mapping(product_type)
411
406
  )
412
407
 
413
- queryables: Dict[str, Annotated[Any, FieldInfo]] = {}
408
+ queryables: dict[str, Annotated[Any, FieldInfo]] = {}
414
409
 
415
410
  for param in list(metadata_mapping.keys()):
416
411
  if NOT_MAPPED in metadata_mapping[param] or not isinstance(