prefect-client 3.1.5__py3-none-any.whl → 3.1.7__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 (114) hide show
  1. prefect/__init__.py +3 -0
  2. prefect/_experimental/__init__.py +0 -0
  3. prefect/_experimental/lineage.py +181 -0
  4. prefect/_internal/compatibility/async_dispatch.py +38 -9
  5. prefect/_internal/compatibility/migration.py +1 -1
  6. prefect/_internal/concurrency/api.py +52 -52
  7. prefect/_internal/concurrency/calls.py +59 -35
  8. prefect/_internal/concurrency/cancellation.py +34 -18
  9. prefect/_internal/concurrency/event_loop.py +7 -6
  10. prefect/_internal/concurrency/threads.py +41 -33
  11. prefect/_internal/concurrency/waiters.py +28 -21
  12. prefect/_internal/pydantic/v1_schema.py +2 -2
  13. prefect/_internal/pydantic/v2_schema.py +10 -9
  14. prefect/_internal/pydantic/v2_validated_func.py +15 -10
  15. prefect/_internal/retries.py +15 -6
  16. prefect/_internal/schemas/bases.py +11 -8
  17. prefect/_internal/schemas/validators.py +7 -5
  18. prefect/_version.py +3 -3
  19. prefect/automations.py +53 -47
  20. prefect/blocks/abstract.py +12 -10
  21. prefect/blocks/core.py +148 -19
  22. prefect/blocks/system.py +2 -1
  23. prefect/cache_policies.py +11 -11
  24. prefect/client/__init__.py +3 -1
  25. prefect/client/base.py +36 -37
  26. prefect/client/cloud.py +26 -19
  27. prefect/client/collections.py +2 -2
  28. prefect/client/orchestration.py +430 -273
  29. prefect/client/schemas/__init__.py +24 -0
  30. prefect/client/schemas/actions.py +128 -121
  31. prefect/client/schemas/filters.py +1 -1
  32. prefect/client/schemas/objects.py +114 -85
  33. prefect/client/schemas/responses.py +19 -20
  34. prefect/client/schemas/schedules.py +136 -93
  35. prefect/client/subscriptions.py +30 -15
  36. prefect/client/utilities.py +46 -36
  37. prefect/concurrency/asyncio.py +6 -9
  38. prefect/concurrency/sync.py +35 -5
  39. prefect/context.py +40 -32
  40. prefect/deployments/flow_runs.py +6 -8
  41. prefect/deployments/runner.py +14 -14
  42. prefect/deployments/steps/core.py +3 -1
  43. prefect/deployments/steps/pull.py +60 -12
  44. prefect/docker/__init__.py +1 -1
  45. prefect/events/clients.py +55 -4
  46. prefect/events/filters.py +1 -1
  47. prefect/events/related.py +2 -1
  48. prefect/events/schemas/events.py +26 -21
  49. prefect/events/utilities.py +3 -2
  50. prefect/events/worker.py +8 -0
  51. prefect/filesystems.py +3 -3
  52. prefect/flow_engine.py +87 -87
  53. prefect/flow_runs.py +7 -5
  54. prefect/flows.py +218 -176
  55. prefect/logging/configuration.py +1 -1
  56. prefect/logging/highlighters.py +1 -2
  57. prefect/logging/loggers.py +30 -20
  58. prefect/main.py +17 -24
  59. prefect/results.py +43 -22
  60. prefect/runner/runner.py +43 -21
  61. prefect/runner/server.py +30 -32
  62. prefect/runner/storage.py +3 -3
  63. prefect/runner/submit.py +3 -6
  64. prefect/runner/utils.py +6 -6
  65. prefect/runtime/flow_run.py +7 -0
  66. prefect/serializers.py +28 -24
  67. prefect/settings/constants.py +2 -2
  68. prefect/settings/legacy.py +1 -1
  69. prefect/settings/models/experiments.py +5 -0
  70. prefect/settings/models/server/events.py +10 -0
  71. prefect/task_engine.py +87 -26
  72. prefect/task_runners.py +2 -2
  73. prefect/task_worker.py +43 -25
  74. prefect/tasks.py +148 -142
  75. prefect/telemetry/bootstrap.py +15 -2
  76. prefect/telemetry/instrumentation.py +1 -1
  77. prefect/telemetry/processors.py +10 -7
  78. prefect/telemetry/run_telemetry.py +231 -0
  79. prefect/transactions.py +14 -14
  80. prefect/types/__init__.py +5 -5
  81. prefect/utilities/_engine.py +96 -0
  82. prefect/utilities/annotations.py +25 -18
  83. prefect/utilities/asyncutils.py +126 -140
  84. prefect/utilities/callables.py +87 -78
  85. prefect/utilities/collections.py +278 -117
  86. prefect/utilities/compat.py +13 -21
  87. prefect/utilities/context.py +6 -5
  88. prefect/utilities/dispatch.py +23 -12
  89. prefect/utilities/dockerutils.py +33 -32
  90. prefect/utilities/engine.py +126 -239
  91. prefect/utilities/filesystem.py +18 -15
  92. prefect/utilities/hashing.py +10 -11
  93. prefect/utilities/importtools.py +40 -27
  94. prefect/utilities/math.py +9 -5
  95. prefect/utilities/names.py +3 -3
  96. prefect/utilities/processutils.py +121 -57
  97. prefect/utilities/pydantic.py +41 -36
  98. prefect/utilities/render_swagger.py +22 -12
  99. prefect/utilities/schema_tools/__init__.py +2 -1
  100. prefect/utilities/schema_tools/hydration.py +50 -43
  101. prefect/utilities/schema_tools/validation.py +52 -42
  102. prefect/utilities/services.py +13 -12
  103. prefect/utilities/templating.py +45 -45
  104. prefect/utilities/text.py +2 -1
  105. prefect/utilities/timeout.py +4 -4
  106. prefect/utilities/urls.py +9 -4
  107. prefect/utilities/visualization.py +46 -24
  108. prefect/variables.py +136 -27
  109. prefect/workers/base.py +15 -8
  110. {prefect_client-3.1.5.dist-info → prefect_client-3.1.7.dist-info}/METADATA +5 -2
  111. {prefect_client-3.1.5.dist-info → prefect_client-3.1.7.dist-info}/RECORD +114 -110
  112. {prefect_client-3.1.5.dist-info → prefect_client-3.1.7.dist-info}/LICENSE +0 -0
  113. {prefect_client-3.1.5.dist-info → prefect_client-3.1.7.dist-info}/WHEEL +0 -0
  114. {prefect_client-3.1.5.dist-info → prefect_client-3.1.7.dist-info}/top_level.txt +0 -0
prefect/cache_policies.py CHANGED
@@ -75,12 +75,12 @@ class CachePolicy:
75
75
  task_ctx: TaskRunContext,
76
76
  inputs: Dict[str, Any],
77
77
  flow_parameters: Dict[str, Any],
78
- **kwargs,
78
+ **kwargs: Any,
79
79
  ) -> Optional[str]:
80
80
  raise NotImplementedError
81
81
 
82
82
  def __sub__(self, other: str) -> "CachePolicy":
83
- if not isinstance(other, str):
83
+ if not isinstance(other, str): # type: ignore[reportUnnecessaryIsInstance]
84
84
  raise TypeError("Can only subtract strings from key policies.")
85
85
  new = Inputs(exclude=[other])
86
86
  return CompoundCachePolicy(policies=[self, new])
@@ -140,7 +140,7 @@ class CacheKeyFnPolicy(CachePolicy):
140
140
  task_ctx: TaskRunContext,
141
141
  inputs: Dict[str, Any],
142
142
  flow_parameters: Dict[str, Any],
143
- **kwargs,
143
+ **kwargs: Any,
144
144
  ) -> Optional[str]:
145
145
  if self.cache_key_fn:
146
146
  return self.cache_key_fn(task_ctx, inputs)
@@ -162,9 +162,9 @@ class CompoundCachePolicy(CachePolicy):
162
162
  task_ctx: TaskRunContext,
163
163
  inputs: Dict[str, Any],
164
164
  flow_parameters: Dict[str, Any],
165
- **kwargs,
165
+ **kwargs: Any,
166
166
  ) -> Optional[str]:
167
- keys = []
167
+ keys: list[str] = []
168
168
  for policy in self.policies:
169
169
  policy_key = policy.compute_key(
170
170
  task_ctx=task_ctx,
@@ -191,7 +191,7 @@ class _None(CachePolicy):
191
191
  task_ctx: TaskRunContext,
192
192
  inputs: Dict[str, Any],
193
193
  flow_parameters: Dict[str, Any],
194
- **kwargs,
194
+ **kwargs: Any,
195
195
  ) -> Optional[str]:
196
196
  return None
197
197
 
@@ -211,7 +211,7 @@ class TaskSource(CachePolicy):
211
211
  task_ctx: TaskRunContext,
212
212
  inputs: Optional[Dict[str, Any]],
213
213
  flow_parameters: Optional[Dict[str, Any]],
214
- **kwargs,
214
+ **kwargs: Any,
215
215
  ) -> Optional[str]:
216
216
  if not task_ctx:
217
217
  return None
@@ -238,7 +238,7 @@ class FlowParameters(CachePolicy):
238
238
  task_ctx: TaskRunContext,
239
239
  inputs: Dict[str, Any],
240
240
  flow_parameters: Dict[str, Any],
241
- **kwargs,
241
+ **kwargs: Any,
242
242
  ) -> Optional[str]:
243
243
  if not flow_parameters:
244
244
  return None
@@ -257,7 +257,7 @@ class RunId(CachePolicy):
257
257
  task_ctx: TaskRunContext,
258
258
  inputs: Dict[str, Any],
259
259
  flow_parameters: Dict[str, Any],
260
- **kwargs,
260
+ **kwargs: Any,
261
261
  ) -> Optional[str]:
262
262
  if not task_ctx:
263
263
  return None
@@ -280,7 +280,7 @@ class Inputs(CachePolicy):
280
280
  task_ctx: TaskRunContext,
281
281
  inputs: Dict[str, Any],
282
282
  flow_parameters: Dict[str, Any],
283
- **kwargs,
283
+ **kwargs: Any,
284
284
  ) -> Optional[str]:
285
285
  hashed_inputs = {}
286
286
  inputs = inputs or {}
@@ -307,7 +307,7 @@ class Inputs(CachePolicy):
307
307
  raise ValueError(msg) from exc
308
308
 
309
309
  def __sub__(self, other: str) -> "CachePolicy":
310
- if not isinstance(other, str):
310
+ if not isinstance(other, str): # type: ignore[reportUnnecessaryIsInstance]
311
311
  raise TypeError("Can only subtract strings from key policies.")
312
312
  return Inputs(exclude=self.exclude + [other])
313
313
 
@@ -16,6 +16,8 @@ $ python -m asyncio
16
16
  </div>
17
17
  """
18
18
 
19
+ from collections.abc import Callable
20
+ from typing import Any
19
21
  from prefect._internal.compatibility.migration import getattr_migration
20
22
 
21
- __getattr__ = getattr_migration(__name__)
23
+ __getattr__: Callable[[str], Any] = getattr_migration(__name__)
prefect/client/base.py CHANGED
@@ -4,22 +4,11 @@ import threading
4
4
  import time
5
5
  import uuid
6
6
  from collections import defaultdict
7
+ from collections.abc import AsyncGenerator, Awaitable, MutableMapping
7
8
  from contextlib import asynccontextmanager
8
9
  from datetime import datetime, timezone
9
- from typing import (
10
- Any,
11
- AsyncGenerator,
12
- Awaitable,
13
- Callable,
14
- Dict,
15
- MutableMapping,
16
- Optional,
17
- Protocol,
18
- Set,
19
- Tuple,
20
- Type,
21
- runtime_checkable,
22
- )
10
+ from logging import Logger
11
+ from typing import TYPE_CHECKING, Any, Callable, Optional, Protocol, runtime_checkable
23
12
 
24
13
  import anyio
25
14
  import httpx
@@ -46,14 +35,14 @@ from prefect.utilities.math import bounded_poisson_interval, clamped_poisson_int
46
35
 
47
36
  # Datastores for lifespan management, keys should be a tuple of thread and app
48
37
  # identities.
49
- APP_LIFESPANS: Dict[Tuple[int, int], LifespanManager] = {}
50
- APP_LIFESPANS_REF_COUNTS: Dict[Tuple[int, int], int] = {}
38
+ APP_LIFESPANS: dict[tuple[int, int], LifespanManager] = {}
39
+ APP_LIFESPANS_REF_COUNTS: dict[tuple[int, int], int] = {}
51
40
  # Blocks concurrent access to the above dicts per thread. The index should be the thread
52
41
  # identity.
53
- APP_LIFESPANS_LOCKS: Dict[int, anyio.Lock] = defaultdict(anyio.Lock)
42
+ APP_LIFESPANS_LOCKS: dict[int, anyio.Lock] = defaultdict(anyio.Lock)
54
43
 
55
44
 
56
- logger = get_logger("client")
45
+ logger: Logger = get_logger("client")
57
46
 
58
47
 
59
48
  # Define ASGI application types for type checking
@@ -161,7 +150,7 @@ class PrefectResponse(httpx.Response):
161
150
  Provides more informative error messages.
162
151
  """
163
152
 
164
- def raise_for_status(self) -> None:
153
+ def raise_for_status(self) -> Response:
165
154
  """
166
155
  Raise an exception if the response contains an HTTPStatusError.
167
156
 
@@ -174,9 +163,9 @@ class PrefectResponse(httpx.Response):
174
163
  raise PrefectHTTPStatusError.from_httpx_error(exc) from exc.__cause__
175
164
 
176
165
  @classmethod
177
- def from_httpx_response(cls: Type[Self], response: httpx.Response) -> Self:
166
+ def from_httpx_response(cls: type[Self], response: httpx.Response) -> Response:
178
167
  """
179
- Create a `PrefectReponse` from an `httpx.Response`.
168
+ Create a `PrefectResponse` from an `httpx.Response`.
180
169
 
181
170
  By changing the `__class__` attribute of the Response, we change the method
182
171
  resolution order to look for methods defined in PrefectResponse, while leaving
@@ -200,10 +189,10 @@ class PrefectHttpxAsyncClient(httpx.AsyncClient):
200
189
 
201
190
  def __init__(
202
191
  self,
203
- *args,
192
+ *args: Any,
204
193
  enable_csrf_support: bool = False,
205
194
  raise_on_all_errors: bool = True,
206
- **kwargs,
195
+ **kwargs: Any,
207
196
  ):
208
197
  self.enable_csrf_support: bool = enable_csrf_support
209
198
  self.csrf_token: Optional[str] = None
@@ -222,10 +211,10 @@ class PrefectHttpxAsyncClient(httpx.AsyncClient):
222
211
  self,
223
212
  request: Request,
224
213
  send: Callable[[Request], Awaitable[Response]],
225
- send_args: Tuple,
226
- send_kwargs: Dict,
227
- retry_codes: Set[int] = set(),
228
- retry_exceptions: Tuple[Exception, ...] = tuple(),
214
+ send_args: tuple[Any, ...],
215
+ send_kwargs: dict[str, Any],
216
+ retry_codes: set[int] = set(),
217
+ retry_exceptions: tuple[type[Exception], ...] = tuple(),
229
218
  ):
230
219
  """
231
220
  Send a request and retry it if it fails.
@@ -240,6 +229,11 @@ class PrefectHttpxAsyncClient(httpx.AsyncClient):
240
229
  try_count = 0
241
230
  response = None
242
231
 
232
+ if TYPE_CHECKING:
233
+ # older httpx versions type method as str | bytes | Unknown
234
+ # but in reality it is always a string.
235
+ assert isinstance(request.method, str) # type: ignore
236
+
243
237
  is_change_request = request.method.lower() in {"post", "put", "patch", "delete"}
244
238
 
245
239
  if self.enable_csrf_support and is_change_request:
@@ -297,7 +291,7 @@ class PrefectHttpxAsyncClient(httpx.AsyncClient):
297
291
  if exc_info
298
292
  else (
299
293
  "Received response with retryable status code"
300
- f" {response.status_code}. "
294
+ f" {response.status_code if response else 'unknown'}. "
301
295
  )
302
296
  )
303
297
  + f"Another attempt will be made in {retry_seconds}s. "
@@ -314,7 +308,7 @@ class PrefectHttpxAsyncClient(httpx.AsyncClient):
314
308
  # We ran out of retries, return the failed response
315
309
  return response
316
310
 
317
- async def send(self, request: Request, *args, **kwargs) -> Response:
311
+ async def send(self, request: Request, *args: Any, **kwargs: Any) -> Response:
318
312
  """
319
313
  Send a request with automatic retry behavior for the following status codes:
320
314
 
@@ -414,10 +408,10 @@ class PrefectHttpxSyncClient(httpx.Client):
414
408
 
415
409
  def __init__(
416
410
  self,
417
- *args,
411
+ *args: Any,
418
412
  enable_csrf_support: bool = False,
419
413
  raise_on_all_errors: bool = True,
420
- **kwargs,
414
+ **kwargs: Any,
421
415
  ):
422
416
  self.enable_csrf_support: bool = enable_csrf_support
423
417
  self.csrf_token: Optional[str] = None
@@ -436,10 +430,10 @@ class PrefectHttpxSyncClient(httpx.Client):
436
430
  self,
437
431
  request: Request,
438
432
  send: Callable[[Request], Response],
439
- send_args: Tuple,
440
- send_kwargs: Dict,
441
- retry_codes: Set[int] = set(),
442
- retry_exceptions: Tuple[Exception, ...] = tuple(),
433
+ send_args: tuple[Any, ...],
434
+ send_kwargs: dict[str, Any],
435
+ retry_codes: set[int] = set(),
436
+ retry_exceptions: tuple[type[Exception], ...] = tuple(),
443
437
  ):
444
438
  """
445
439
  Send a request and retry it if it fails.
@@ -454,6 +448,11 @@ class PrefectHttpxSyncClient(httpx.Client):
454
448
  try_count = 0
455
449
  response = None
456
450
 
451
+ if TYPE_CHECKING:
452
+ # older httpx versions type method as str | bytes | Unknown
453
+ # but in reality it is always a string.
454
+ assert isinstance(request.method, str) # type: ignore
455
+
457
456
  is_change_request = request.method.lower() in {"post", "put", "patch", "delete"}
458
457
 
459
458
  if self.enable_csrf_support and is_change_request:
@@ -511,7 +510,7 @@ class PrefectHttpxSyncClient(httpx.Client):
511
510
  if exc_info
512
511
  else (
513
512
  "Received response with retryable status code"
514
- f" {response.status_code}. "
513
+ f" {response.status_code if response else 'unknown'}. "
515
514
  )
516
515
  )
517
516
  + f"Another attempt will be made in {retry_seconds}s. "
@@ -528,7 +527,7 @@ class PrefectHttpxSyncClient(httpx.Client):
528
527
  # We ran out of retries, return the failed response
529
528
  return response
530
529
 
531
- def send(self, request: Request, *args, **kwargs) -> Response:
530
+ def send(self, request: Request, *args: Any, **kwargs: Any) -> Response:
532
531
  """
533
532
  Send a request with automatic retry behavior for the following status codes:
534
533
 
prefect/client/cloud.py CHANGED
@@ -1,11 +1,12 @@
1
1
  import re
2
- from typing import Any, Dict, List, Optional, cast
2
+ from typing import Any, NoReturn, Optional, cast
3
3
  from uuid import UUID
4
4
 
5
5
  import anyio
6
6
  import httpx
7
7
  import pydantic
8
8
  from starlette import status
9
+ from typing_extensions import Self
9
10
 
10
11
  import prefect.context
11
12
  import prefect.settings
@@ -30,7 +31,7 @@ PARSE_API_URL_REGEX = re.compile(r"accounts/(.{36})/workspaces/(.{36})")
30
31
  def get_cloud_client(
31
32
  host: Optional[str] = None,
32
33
  api_key: Optional[str] = None,
33
- httpx_settings: Optional[dict] = None,
34
+ httpx_settings: Optional[dict[str, Any]] = None,
34
35
  infer_cloud_url: bool = False,
35
36
  ) -> "CloudClient":
36
37
  """
@@ -45,6 +46,9 @@ def get_cloud_client(
45
46
  configured_url = prefect.settings.PREFECT_API_URL.value()
46
47
  host = re.sub(PARSE_API_URL_REGEX, "", configured_url)
47
48
 
49
+ if host is None:
50
+ raise ValueError("Host was not provided and could not be inferred")
51
+
48
52
  return CloudClient(
49
53
  host=host,
50
54
  api_key=api_key or PREFECT_API_KEY.value(),
@@ -59,11 +63,14 @@ class CloudUnauthorizedError(PrefectException):
59
63
 
60
64
 
61
65
  class CloudClient:
66
+ account_id: Optional[str] = None
67
+ workspace_id: Optional[str] = None
68
+
62
69
  def __init__(
63
70
  self,
64
71
  host: str,
65
72
  api_key: str,
66
- httpx_settings: Optional[Dict[str, Any]] = None,
73
+ httpx_settings: Optional[dict[str, Any]] = None,
67
74
  ) -> None:
68
75
  httpx_settings = httpx_settings or dict()
69
76
  httpx_settings.setdefault("headers", dict())
@@ -76,7 +83,7 @@ class CloudClient:
76
83
  **httpx_settings, enable_csrf_support=False
77
84
  )
78
85
 
79
- api_url = prefect.settings.PREFECT_API_URL.value() or ""
86
+ api_url: str = prefect.settings.PREFECT_API_URL.value() or ""
80
87
  if match := (
81
88
  re.search(PARSE_API_URL_REGEX, host)
82
89
  or re.search(PARSE_API_URL_REGEX, api_url)
@@ -97,7 +104,7 @@ class CloudClient:
97
104
 
98
105
  return f"{self.account_base_url}/workspaces/{self.workspace_id}"
99
106
 
100
- async def api_healthcheck(self):
107
+ async def api_healthcheck(self) -> None:
101
108
  """
102
109
  Attempts to connect to the Cloud API and raises the encountered exception if not
103
110
  successful.
@@ -107,8 +114,8 @@ class CloudClient:
107
114
  with anyio.fail_after(10):
108
115
  await self.read_workspaces()
109
116
 
110
- async def read_workspaces(self) -> List[Workspace]:
111
- workspaces = pydantic.TypeAdapter(List[Workspace]).validate_python(
117
+ async def read_workspaces(self) -> list[Workspace]:
118
+ workspaces = pydantic.TypeAdapter(list[Workspace]).validate_python(
112
119
  await self.get("/me/workspaces")
113
120
  )
114
121
  return workspaces
@@ -121,17 +128,17 @@ class CloudClient:
121
128
  return workspace
122
129
  raise ValueError("Current workspace not found")
123
130
 
124
- async def read_worker_metadata(self) -> Dict[str, Any]:
131
+ async def read_worker_metadata(self) -> dict[str, Any]:
125
132
  response = await self.get(
126
133
  f"{self.workspace_base_url}/collections/work_pool_types"
127
134
  )
128
- return cast(Dict[str, Any], response)
135
+ return cast(dict[str, Any], response)
129
136
 
130
- async def read_account_settings(self) -> Dict[str, Any]:
137
+ async def read_account_settings(self) -> dict[str, Any]:
131
138
  response = await self.get(f"{self.account_base_url}/settings")
132
- return cast(Dict[str, Any], response)
139
+ return cast(dict[str, Any], response)
133
140
 
134
- async def update_account_settings(self, settings: Dict[str, Any]):
141
+ async def update_account_settings(self, settings: dict[str, Any]) -> None:
135
142
  await self.request(
136
143
  "PATCH",
137
144
  f"{self.account_base_url}/settings",
@@ -142,7 +149,7 @@ class CloudClient:
142
149
  response = await self.get(f"{self.account_base_url}/ip_allowlist")
143
150
  return IPAllowlist.model_validate(response)
144
151
 
145
- async def update_account_ip_allowlist(self, updated_allowlist: IPAllowlist):
152
+ async def update_account_ip_allowlist(self, updated_allowlist: IPAllowlist) -> None:
146
153
  await self.request(
147
154
  "PUT",
148
155
  f"{self.account_base_url}/ip_allowlist",
@@ -172,26 +179,26 @@ class CloudClient:
172
179
  json=labels,
173
180
  )
174
181
 
175
- async def __aenter__(self):
182
+ async def __aenter__(self) -> Self:
176
183
  await self._client.__aenter__()
177
184
  return self
178
185
 
179
- async def __aexit__(self, *exc_info):
186
+ async def __aexit__(self, *exc_info: Any) -> None:
180
187
  return await self._client.__aexit__(*exc_info)
181
188
 
182
- def __enter__(self):
189
+ def __enter__(self) -> NoReturn:
183
190
  raise RuntimeError(
184
191
  "The `CloudClient` must be entered with an async context. Use 'async "
185
192
  "with CloudClient(...)' not 'with CloudClient(...)'"
186
193
  )
187
194
 
188
- def __exit__(self, *_):
195
+ def __exit__(self, *_: object) -> NoReturn:
189
196
  assert False, "This should never be called but must be defined for __enter__"
190
197
 
191
- async def get(self, route, **kwargs):
198
+ async def get(self, route: str, **kwargs: Any) -> Any:
192
199
  return await self.request("GET", route, **kwargs)
193
200
 
194
- async def request(self, method, route, **kwargs):
201
+ async def request(self, method: str, route: str, **kwargs: Any) -> Any:
195
202
  try:
196
203
  res = await self._client.request(method, route, **kwargs)
197
204
  res.raise_for_status()
@@ -13,12 +13,12 @@ class CollectionsMetadataClient(Protocol):
13
13
  async def __aenter__(self) -> "CollectionsMetadataClient":
14
14
  ...
15
15
 
16
- async def __aexit__(self, *exc_info) -> Any:
16
+ async def __aexit__(self, *exc_info: Any) -> Any:
17
17
  ...
18
18
 
19
19
 
20
20
  def get_collections_metadata_client(
21
- httpx_settings: Optional[Dict] = None,
21
+ httpx_settings: Optional[Dict[str, Any]] = None,
22
22
  ) -> "CollectionsMetadataClient":
23
23
  """
24
24
  Creates a client that can be used to fetch metadata for