prefect-client 2.19.2__py3-none-any.whl → 3.0.0rc1__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 (239) hide show
  1. prefect/__init__.py +8 -56
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/concurrency/api.py +0 -34
  5. prefect/_internal/concurrency/calls.py +0 -6
  6. prefect/_internal/concurrency/cancellation.py +0 -3
  7. prefect/_internal/concurrency/event_loop.py +0 -20
  8. prefect/_internal/concurrency/inspection.py +3 -3
  9. prefect/_internal/concurrency/threads.py +35 -0
  10. prefect/_internal/concurrency/waiters.py +0 -28
  11. prefect/_internal/pydantic/__init__.py +0 -45
  12. prefect/_internal/pydantic/v1_schema.py +21 -22
  13. prefect/_internal/pydantic/v2_schema.py +0 -2
  14. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  15. prefect/_internal/schemas/bases.py +44 -177
  16. prefect/_internal/schemas/fields.py +1 -43
  17. prefect/_internal/schemas/validators.py +60 -158
  18. prefect/artifacts.py +161 -14
  19. prefect/automations.py +39 -4
  20. prefect/blocks/abstract.py +1 -1
  21. prefect/blocks/core.py +268 -148
  22. prefect/blocks/fields.py +2 -57
  23. prefect/blocks/kubernetes.py +8 -12
  24. prefect/blocks/notifications.py +40 -20
  25. prefect/blocks/system.py +22 -11
  26. prefect/blocks/webhook.py +2 -9
  27. prefect/client/base.py +4 -4
  28. prefect/client/cloud.py +8 -13
  29. prefect/client/orchestration.py +347 -341
  30. prefect/client/schemas/actions.py +92 -86
  31. prefect/client/schemas/filters.py +20 -40
  32. prefect/client/schemas/objects.py +151 -145
  33. prefect/client/schemas/responses.py +16 -24
  34. prefect/client/schemas/schedules.py +47 -35
  35. prefect/client/subscriptions.py +2 -2
  36. prefect/client/utilities.py +5 -2
  37. prefect/concurrency/asyncio.py +3 -1
  38. prefect/concurrency/events.py +1 -1
  39. prefect/concurrency/services.py +6 -3
  40. prefect/context.py +195 -27
  41. prefect/deployments/__init__.py +5 -6
  42. prefect/deployments/base.py +7 -5
  43. prefect/deployments/flow_runs.py +185 -0
  44. prefect/deployments/runner.py +50 -45
  45. prefect/deployments/schedules.py +28 -23
  46. prefect/deployments/steps/__init__.py +0 -1
  47. prefect/deployments/steps/core.py +1 -0
  48. prefect/deployments/steps/pull.py +7 -21
  49. prefect/engine.py +12 -2422
  50. prefect/events/actions.py +17 -23
  51. prefect/events/cli/automations.py +19 -6
  52. prefect/events/clients.py +14 -37
  53. prefect/events/filters.py +14 -18
  54. prefect/events/related.py +2 -2
  55. prefect/events/schemas/__init__.py +0 -5
  56. prefect/events/schemas/automations.py +55 -46
  57. prefect/events/schemas/deployment_triggers.py +7 -197
  58. prefect/events/schemas/events.py +34 -65
  59. prefect/events/schemas/labelling.py +10 -14
  60. prefect/events/utilities.py +2 -3
  61. prefect/events/worker.py +2 -3
  62. prefect/filesystems.py +6 -517
  63. prefect/{new_flow_engine.py → flow_engine.py} +313 -72
  64. prefect/flow_runs.py +377 -5
  65. prefect/flows.py +307 -166
  66. prefect/futures.py +186 -345
  67. prefect/infrastructure/__init__.py +0 -27
  68. prefect/infrastructure/provisioners/__init__.py +5 -3
  69. prefect/infrastructure/provisioners/cloud_run.py +11 -6
  70. prefect/infrastructure/provisioners/container_instance.py +11 -7
  71. prefect/infrastructure/provisioners/ecs.py +6 -4
  72. prefect/infrastructure/provisioners/modal.py +8 -5
  73. prefect/input/actions.py +2 -4
  74. prefect/input/run_input.py +5 -7
  75. prefect/logging/formatters.py +0 -2
  76. prefect/logging/handlers.py +3 -11
  77. prefect/logging/loggers.py +2 -2
  78. prefect/manifests.py +2 -1
  79. prefect/records/__init__.py +1 -0
  80. prefect/records/result_store.py +42 -0
  81. prefect/records/store.py +9 -0
  82. prefect/results.py +43 -39
  83. prefect/runner/runner.py +19 -15
  84. prefect/runner/server.py +6 -10
  85. prefect/runner/storage.py +3 -8
  86. prefect/runner/submit.py +2 -2
  87. prefect/runner/utils.py +2 -2
  88. prefect/serializers.py +24 -35
  89. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  90. prefect/settings.py +70 -133
  91. prefect/states.py +17 -47
  92. prefect/task_engine.py +697 -58
  93. prefect/task_runners.py +269 -301
  94. prefect/task_server.py +53 -34
  95. prefect/tasks.py +327 -337
  96. prefect/transactions.py +220 -0
  97. prefect/types/__init__.py +61 -82
  98. prefect/utilities/asyncutils.py +195 -136
  99. prefect/utilities/callables.py +311 -43
  100. prefect/utilities/collections.py +23 -38
  101. prefect/utilities/dispatch.py +11 -3
  102. prefect/utilities/dockerutils.py +4 -0
  103. prefect/utilities/engine.py +140 -20
  104. prefect/utilities/importtools.py +97 -27
  105. prefect/utilities/pydantic.py +128 -38
  106. prefect/utilities/schema_tools/hydration.py +5 -1
  107. prefect/utilities/templating.py +12 -2
  108. prefect/variables.py +78 -61
  109. prefect/workers/__init__.py +0 -1
  110. prefect/workers/base.py +15 -17
  111. prefect/workers/process.py +3 -8
  112. prefect/workers/server.py +2 -2
  113. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/METADATA +22 -21
  114. prefect_client-3.0.0rc1.dist-info/RECORD +176 -0
  115. prefect/_internal/pydantic/_base_model.py +0 -51
  116. prefect/_internal/pydantic/_compat.py +0 -82
  117. prefect/_internal/pydantic/_flags.py +0 -20
  118. prefect/_internal/pydantic/_types.py +0 -8
  119. prefect/_internal/pydantic/utilities/__init__.py +0 -0
  120. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  121. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  122. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  123. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  124. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  125. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  126. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  127. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  128. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  129. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  130. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  131. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  132. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  133. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  134. prefect/_vendor/__init__.py +0 -0
  135. prefect/_vendor/fastapi/__init__.py +0 -25
  136. prefect/_vendor/fastapi/applications.py +0 -946
  137. prefect/_vendor/fastapi/background.py +0 -3
  138. prefect/_vendor/fastapi/concurrency.py +0 -44
  139. prefect/_vendor/fastapi/datastructures.py +0 -58
  140. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  141. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  142. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  143. prefect/_vendor/fastapi/encoders.py +0 -177
  144. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  145. prefect/_vendor/fastapi/exceptions.py +0 -46
  146. prefect/_vendor/fastapi/logger.py +0 -3
  147. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  148. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  149. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  150. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  151. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  152. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  153. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  154. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  155. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  156. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  157. prefect/_vendor/fastapi/openapi/models.py +0 -480
  158. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  159. prefect/_vendor/fastapi/param_functions.py +0 -340
  160. prefect/_vendor/fastapi/params.py +0 -453
  161. prefect/_vendor/fastapi/requests.py +0 -4
  162. prefect/_vendor/fastapi/responses.py +0 -40
  163. prefect/_vendor/fastapi/routing.py +0 -1331
  164. prefect/_vendor/fastapi/security/__init__.py +0 -15
  165. prefect/_vendor/fastapi/security/api_key.py +0 -98
  166. prefect/_vendor/fastapi/security/base.py +0 -6
  167. prefect/_vendor/fastapi/security/http.py +0 -172
  168. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  169. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  170. prefect/_vendor/fastapi/security/utils.py +0 -10
  171. prefect/_vendor/fastapi/staticfiles.py +0 -1
  172. prefect/_vendor/fastapi/templating.py +0 -3
  173. prefect/_vendor/fastapi/testclient.py +0 -1
  174. prefect/_vendor/fastapi/types.py +0 -3
  175. prefect/_vendor/fastapi/utils.py +0 -235
  176. prefect/_vendor/fastapi/websockets.py +0 -7
  177. prefect/_vendor/starlette/__init__.py +0 -1
  178. prefect/_vendor/starlette/_compat.py +0 -28
  179. prefect/_vendor/starlette/_exception_handler.py +0 -80
  180. prefect/_vendor/starlette/_utils.py +0 -88
  181. prefect/_vendor/starlette/applications.py +0 -261
  182. prefect/_vendor/starlette/authentication.py +0 -159
  183. prefect/_vendor/starlette/background.py +0 -43
  184. prefect/_vendor/starlette/concurrency.py +0 -59
  185. prefect/_vendor/starlette/config.py +0 -151
  186. prefect/_vendor/starlette/convertors.py +0 -87
  187. prefect/_vendor/starlette/datastructures.py +0 -707
  188. prefect/_vendor/starlette/endpoints.py +0 -130
  189. prefect/_vendor/starlette/exceptions.py +0 -60
  190. prefect/_vendor/starlette/formparsers.py +0 -276
  191. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  192. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  193. prefect/_vendor/starlette/middleware/base.py +0 -220
  194. prefect/_vendor/starlette/middleware/cors.py +0 -176
  195. prefect/_vendor/starlette/middleware/errors.py +0 -265
  196. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  197. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  198. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  199. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  200. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  201. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  202. prefect/_vendor/starlette/requests.py +0 -328
  203. prefect/_vendor/starlette/responses.py +0 -347
  204. prefect/_vendor/starlette/routing.py +0 -933
  205. prefect/_vendor/starlette/schemas.py +0 -154
  206. prefect/_vendor/starlette/staticfiles.py +0 -248
  207. prefect/_vendor/starlette/status.py +0 -199
  208. prefect/_vendor/starlette/templating.py +0 -231
  209. prefect/_vendor/starlette/testclient.py +0 -804
  210. prefect/_vendor/starlette/types.py +0 -30
  211. prefect/_vendor/starlette/websockets.py +0 -193
  212. prefect/agent.py +0 -698
  213. prefect/deployments/deployments.py +0 -1042
  214. prefect/deprecated/__init__.py +0 -0
  215. prefect/deprecated/data_documents.py +0 -350
  216. prefect/deprecated/packaging/__init__.py +0 -12
  217. prefect/deprecated/packaging/base.py +0 -96
  218. prefect/deprecated/packaging/docker.py +0 -146
  219. prefect/deprecated/packaging/file.py +0 -92
  220. prefect/deprecated/packaging/orion.py +0 -80
  221. prefect/deprecated/packaging/serializers.py +0 -171
  222. prefect/events/instrument.py +0 -135
  223. prefect/infrastructure/base.py +0 -323
  224. prefect/infrastructure/container.py +0 -818
  225. prefect/infrastructure/kubernetes.py +0 -920
  226. prefect/infrastructure/process.py +0 -289
  227. prefect/new_task_engine.py +0 -423
  228. prefect/pydantic/__init__.py +0 -76
  229. prefect/pydantic/main.py +0 -39
  230. prefect/software/__init__.py +0 -2
  231. prefect/software/base.py +0 -50
  232. prefect/software/conda.py +0 -199
  233. prefect/software/pip.py +0 -122
  234. prefect/software/python.py +0 -52
  235. prefect/workers/block.py +0 -218
  236. prefect_client-2.19.2.dist-info/RECORD +0 -292
  237. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/LICENSE +0 -0
  238. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/WHEEL +0 -0
  239. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/top_level.txt +0 -0
prefect/task_server.py CHANGED
@@ -4,33 +4,30 @@ import os
4
4
  import signal
5
5
  import socket
6
6
  import sys
7
+ from concurrent.futures import ThreadPoolExecutor
7
8
  from contextlib import AsyncExitStack
8
- from functools import partial
9
- from typing import List, Optional, Type
9
+ from contextvars import copy_context
10
+ from typing import List, Optional
10
11
 
11
12
  import anyio
13
+ import anyio.abc
12
14
  from websockets.exceptions import InvalidStatusCode
13
15
 
14
16
  from prefect import Task, get_client
15
17
  from prefect._internal.concurrency.api import create_call, from_sync
16
18
  from prefect.client.schemas.objects import TaskRun
17
19
  from prefect.client.subscriptions import Subscription
18
- from prefect.engine import emit_task_run_state_change_event, propose_state
19
20
  from prefect.exceptions import Abort, PrefectHTTPStatusError
20
21
  from prefect.logging.loggers import get_logger
21
22
  from prefect.results import ResultFactory
22
23
  from prefect.settings import (
23
24
  PREFECT_API_URL,
24
- PREFECT_EXPERIMENTAL_ENABLE_TASK_SCHEDULING,
25
25
  PREFECT_TASK_SCHEDULING_DELETE_FAILED_SUBMISSIONS,
26
26
  )
27
27
  from prefect.states import Pending
28
- from prefect.task_engine import submit_autonomous_task_run_to_engine
29
- from prefect.task_runners import (
30
- BaseTaskRunner,
31
- ConcurrentTaskRunner,
32
- )
28
+ from prefect.task_engine import run_task_async, run_task_sync
33
29
  from prefect.utilities.asyncutils import asyncnullcontext, sync_compatible
30
+ from prefect.utilities.engine import emit_task_run_state_change_event, propose_state
34
31
  from prefect.utilities.processutils import _register_signal
35
32
 
36
33
  logger = get_logger("task_server")
@@ -64,18 +61,17 @@ class TaskServer:
64
61
  Args:
65
62
  - tasks: A list of tasks to serve. These tasks will be submitted to the engine
66
63
  when a scheduled task run is found.
67
- - task_runner: The task runner to use for executing the tasks. Defaults to
68
- `ConcurrentTaskRunner`.
64
+ - limit: The maximum number of tasks that can be run concurrently. Defaults to 10.
65
+ Pass `None` to remove the limit.
69
66
  """
70
67
 
71
68
  def __init__(
72
69
  self,
73
70
  *tasks: Task,
74
- task_runner: Optional[Type[BaseTaskRunner]] = None,
71
+ limit: Optional[int] = 10,
75
72
  ):
76
73
  self.tasks: List[Task] = tasks
77
74
 
78
- self.task_runner: BaseTaskRunner = task_runner or ConcurrentTaskRunner()
79
75
  self.started: bool = False
80
76
  self.stopping: bool = False
81
77
 
@@ -88,6 +84,8 @@ class TaskServer:
88
84
  )
89
85
 
90
86
  self._runs_task_group: anyio.abc.TaskGroup = anyio.create_task_group()
87
+ self._executor = ThreadPoolExecutor()
88
+ self._limiter = anyio.CapacityLimiter(limit) if limit else None
91
89
 
92
90
  @property
93
91
  def _client_id(self) -> str:
@@ -148,8 +146,10 @@ class TaskServer:
148
146
  keys=[task.task_key for task in self.tasks],
149
147
  client_id=self._client_id,
150
148
  ):
149
+ if self._limiter:
150
+ await self._limiter.acquire_on_behalf_of(task_run.id)
151
151
  logger.info(f"Received task run: {task_run.id} - {task_run.name}")
152
- await self._submit_scheduled_task_run(task_run)
152
+ self._runs_task_group.start_soon(self._submit_scheduled_task_run, task_run)
153
153
 
154
154
  async def _submit_scheduled_task_run(self, task_run: TaskRun):
155
155
  logger.debug(
@@ -171,12 +171,17 @@ class TaskServer:
171
171
  # state_details. If there is no parameters_id, then the task was created
172
172
  # without parameters.
173
173
  parameters = {}
174
+ wait_for = []
175
+ run_context = None
174
176
  if should_try_to_read_parameters(task, task_run):
175
177
  parameters_id = task_run.state.state_details.task_parameters_id
176
178
  task.persist_result = True
177
179
  factory = await ResultFactory.from_autonomous_task(task)
178
180
  try:
179
- parameters = await factory.read_parameters(parameters_id)
181
+ run_data = await factory.read_parameters(parameters_id)
182
+ parameters = run_data.get("parameters", {})
183
+ wait_for = run_data.get("wait_for", [])
184
+ run_context = run_data.get("context", None)
180
185
  except Exception as exc:
181
186
  logger.exception(
182
187
  f"Failed to read parameters for task run {task_run.id!r}",
@@ -194,9 +199,11 @@ class TaskServer:
194
199
  )
195
200
 
196
201
  try:
202
+ new_state = Pending()
203
+ new_state.state_details.deferred = True
197
204
  state = await propose_state(
198
205
  client=get_client(), # TODO prove that we cannot use self._client here
199
- state=Pending(),
206
+ state=new_state,
200
207
  task_run_id=task_run.id,
201
208
  )
202
209
  except Abort as exc:
@@ -225,20 +232,38 @@ class TaskServer:
225
232
  validated_state=state,
226
233
  )
227
234
 
228
- self._runs_task_group.start_soon(
229
- partial(
230
- submit_autonomous_task_run_to_engine,
235
+ if task.isasync:
236
+ await run_task_async(
231
237
  task=task,
238
+ task_run_id=task_run.id,
232
239
  task_run=task_run,
233
240
  parameters=parameters,
234
- task_runner=self.task_runner,
235
- client=self._client,
241
+ wait_for=wait_for,
242
+ return_type="state",
243
+ context=run_context,
236
244
  )
237
- )
245
+ else:
246
+ context = copy_context()
247
+ future = self._executor.submit(
248
+ context.run,
249
+ run_task_sync,
250
+ task=task,
251
+ task_run_id=task_run.id,
252
+ task_run=task_run,
253
+ parameters=parameters,
254
+ wait_for=wait_for,
255
+ return_type="state",
256
+ context=run_context,
257
+ )
258
+ await asyncio.wrap_future(future)
259
+ if self._limiter:
260
+ self._limiter.release_on_behalf_of(task_run.id)
238
261
 
239
262
  async def execute_task_run(self, task_run: TaskRun):
240
263
  """Execute a task run in the task server."""
241
264
  async with self if not self.started else asyncnullcontext():
265
+ if self._limiter:
266
+ await self._limiter.acquire_on_behalf_of(task_run.id)
242
267
  await self._submit_scheduled_task_run(task_run)
243
268
 
244
269
  async def __aenter__(self):
@@ -248,8 +273,8 @@ class TaskServer:
248
273
  self._client = get_client()
249
274
 
250
275
  await self._exit_stack.enter_async_context(self._client)
251
- await self._exit_stack.enter_async_context(self.task_runner.start())
252
- await self._runs_task_group.__aenter__()
276
+ await self._exit_stack.enter_async_context(self._runs_task_group)
277
+ self._exit_stack.enter_context(self._executor)
253
278
 
254
279
  self.started = True
255
280
  return self
@@ -257,12 +282,11 @@ class TaskServer:
257
282
  async def __aexit__(self, *exc_info):
258
283
  logger.debug("Stopping task server...")
259
284
  self.started = False
260
- await self._runs_task_group.__aexit__(*exc_info)
261
285
  await self._exit_stack.__aexit__(*exc_info)
262
286
 
263
287
 
264
288
  @sync_compatible
265
- async def serve(*tasks: Task, task_runner: Optional[Type[BaseTaskRunner]] = None):
289
+ async def serve(*tasks: Task, limit: Optional[int] = 10):
266
290
  """Serve the provided tasks so that their runs may be submitted to and executed.
267
291
  in the engine. Tasks do not need to be within a flow run context to be submitted.
268
292
  You must `.submit` the same task object that you pass to `serve`.
@@ -270,8 +294,8 @@ async def serve(*tasks: Task, task_runner: Optional[Type[BaseTaskRunner]] = None
270
294
  Args:
271
295
  - tasks: A list of tasks to serve. When a scheduled task run is found for a
272
296
  given task, the task run will be submitted to the engine for execution.
273
- - task_runner: The task runner to use for executing the tasks. Defaults to
274
- `ConcurrentTaskRunner`.
297
+ - limit: The maximum number of tasks that can be run concurrently. Defaults to 10.
298
+ Pass `None` to remove the limit.
275
299
 
276
300
  Example:
277
301
  ```python
@@ -291,13 +315,8 @@ async def serve(*tasks: Task, task_runner: Optional[Type[BaseTaskRunner]] = None
291
315
  serve(say, yell)
292
316
  ```
293
317
  """
294
- if not PREFECT_EXPERIMENTAL_ENABLE_TASK_SCHEDULING.value():
295
- raise RuntimeError(
296
- "To enable task scheduling, set PREFECT_EXPERIMENTAL_ENABLE_TASK_SCHEDULING"
297
- " to True."
298
- )
318
+ task_server = TaskServer(*tasks, limit=limit)
299
319
 
300
- task_server = TaskServer(*tasks, task_runner=task_runner)
301
320
  try:
302
321
  await task_server.start()
303
322