prefect-client 3.1.4__py3-none-any.whl → 3.1.6__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 (96) hide show
  1. prefect/__init__.py +3 -0
  2. prefect/_internal/compatibility/migration.py +1 -1
  3. prefect/_internal/concurrency/api.py +52 -52
  4. prefect/_internal/concurrency/calls.py +59 -35
  5. prefect/_internal/concurrency/cancellation.py +34 -18
  6. prefect/_internal/concurrency/event_loop.py +7 -6
  7. prefect/_internal/concurrency/threads.py +41 -33
  8. prefect/_internal/concurrency/waiters.py +28 -21
  9. prefect/_internal/pydantic/v1_schema.py +2 -2
  10. prefect/_internal/pydantic/v2_schema.py +10 -9
  11. prefect/_internal/schemas/bases.py +10 -11
  12. prefect/_internal/schemas/validators.py +2 -1
  13. prefect/_version.py +3 -3
  14. prefect/automations.py +53 -47
  15. prefect/blocks/abstract.py +12 -10
  16. prefect/blocks/core.py +4 -2
  17. prefect/cache_policies.py +11 -11
  18. prefect/client/__init__.py +3 -1
  19. prefect/client/base.py +36 -37
  20. prefect/client/cloud.py +26 -19
  21. prefect/client/collections.py +2 -2
  22. prefect/client/orchestration.py +366 -277
  23. prefect/client/schemas/__init__.py +24 -0
  24. prefect/client/schemas/actions.py +132 -120
  25. prefect/client/schemas/filters.py +5 -0
  26. prefect/client/schemas/objects.py +113 -85
  27. prefect/client/schemas/responses.py +21 -18
  28. prefect/client/schemas/schedules.py +136 -93
  29. prefect/client/subscriptions.py +28 -14
  30. prefect/client/utilities.py +32 -36
  31. prefect/concurrency/asyncio.py +6 -9
  32. prefect/concurrency/services.py +3 -0
  33. prefect/concurrency/sync.py +35 -5
  34. prefect/context.py +39 -31
  35. prefect/deployments/flow_runs.py +3 -5
  36. prefect/docker/__init__.py +1 -1
  37. prefect/events/schemas/events.py +25 -20
  38. prefect/events/utilities.py +1 -2
  39. prefect/filesystems.py +3 -3
  40. prefect/flow_engine.py +755 -138
  41. prefect/flow_runs.py +3 -3
  42. prefect/flows.py +214 -170
  43. prefect/logging/configuration.py +1 -1
  44. prefect/logging/highlighters.py +1 -2
  45. prefect/logging/loggers.py +30 -20
  46. prefect/main.py +17 -24
  47. prefect/runner/runner.py +43 -21
  48. prefect/runner/server.py +30 -32
  49. prefect/runner/submit.py +3 -6
  50. prefect/runner/utils.py +6 -6
  51. prefect/runtime/flow_run.py +7 -0
  52. prefect/settings/constants.py +2 -2
  53. prefect/settings/legacy.py +1 -1
  54. prefect/settings/models/server/events.py +10 -0
  55. prefect/settings/sources.py +9 -2
  56. prefect/task_engine.py +72 -19
  57. prefect/task_runners.py +2 -2
  58. prefect/tasks.py +46 -33
  59. prefect/telemetry/bootstrap.py +15 -2
  60. prefect/telemetry/run_telemetry.py +107 -0
  61. prefect/transactions.py +14 -14
  62. prefect/types/__init__.py +20 -3
  63. prefect/utilities/_engine.py +96 -0
  64. prefect/utilities/annotations.py +25 -18
  65. prefect/utilities/asyncutils.py +126 -140
  66. prefect/utilities/callables.py +87 -78
  67. prefect/utilities/collections.py +278 -117
  68. prefect/utilities/compat.py +13 -21
  69. prefect/utilities/context.py +6 -5
  70. prefect/utilities/dispatch.py +23 -12
  71. prefect/utilities/dockerutils.py +33 -32
  72. prefect/utilities/engine.py +126 -239
  73. prefect/utilities/filesystem.py +18 -15
  74. prefect/utilities/hashing.py +10 -11
  75. prefect/utilities/importtools.py +40 -27
  76. prefect/utilities/math.py +9 -5
  77. prefect/utilities/names.py +3 -3
  78. prefect/utilities/processutils.py +121 -57
  79. prefect/utilities/pydantic.py +41 -36
  80. prefect/utilities/render_swagger.py +22 -12
  81. prefect/utilities/schema_tools/__init__.py +2 -1
  82. prefect/utilities/schema_tools/hydration.py +50 -43
  83. prefect/utilities/schema_tools/validation.py +52 -42
  84. prefect/utilities/services.py +13 -12
  85. prefect/utilities/templating.py +45 -45
  86. prefect/utilities/text.py +2 -1
  87. prefect/utilities/timeout.py +4 -4
  88. prefect/utilities/urls.py +9 -4
  89. prefect/utilities/visualization.py +46 -24
  90. prefect/variables.py +9 -8
  91. prefect/workers/base.py +18 -10
  92. {prefect_client-3.1.4.dist-info → prefect_client-3.1.6.dist-info}/METADATA +5 -5
  93. {prefect_client-3.1.4.dist-info → prefect_client-3.1.6.dist-info}/RECORD +96 -94
  94. {prefect_client-3.1.4.dist-info → prefect_client-3.1.6.dist-info}/WHEEL +1 -1
  95. {prefect_client-3.1.4.dist-info → prefect_client-3.1.6.dist-info}/LICENSE +0 -0
  96. {prefect_client-3.1.4.dist-info → prefect_client-3.1.6.dist-info}/top_level.txt +0 -0
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