prefect-client 3.1.10__py3-none-any.whl → 3.1.12__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.
- prefect/_experimental/lineage.py +7 -8
- prefect/_experimental/sla/__init__.py +0 -0
- prefect/_experimental/sla/client.py +66 -0
- prefect/_experimental/sla/objects.py +53 -0
- prefect/_internal/_logging.py +15 -3
- prefect/_internal/compatibility/async_dispatch.py +22 -16
- prefect/_internal/compatibility/deprecated.py +42 -18
- prefect/_internal/compatibility/migration.py +2 -2
- prefect/_internal/concurrency/inspection.py +12 -14
- prefect/_internal/concurrency/primitives.py +2 -2
- prefect/_internal/concurrency/services.py +154 -80
- prefect/_internal/concurrency/waiters.py +13 -9
- prefect/_internal/pydantic/annotations/pendulum.py +7 -7
- prefect/_internal/pytz.py +4 -3
- prefect/_internal/retries.py +10 -5
- prefect/_internal/schemas/bases.py +19 -10
- prefect/_internal/schemas/validators.py +227 -388
- prefect/_version.py +3 -3
- prefect/automations.py +236 -30
- prefect/blocks/__init__.py +3 -3
- prefect/blocks/abstract.py +53 -30
- prefect/blocks/core.py +183 -84
- prefect/blocks/notifications.py +133 -73
- prefect/blocks/redis.py +13 -9
- prefect/blocks/system.py +24 -11
- prefect/blocks/webhook.py +7 -5
- prefect/cache_policies.py +3 -2
- prefect/client/orchestration/__init__.py +1957 -0
- prefect/client/orchestration/_artifacts/__init__.py +0 -0
- prefect/client/orchestration/_artifacts/client.py +239 -0
- prefect/client/orchestration/_automations/__init__.py +0 -0
- prefect/client/orchestration/_automations/client.py +329 -0
- prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
- prefect/client/orchestration/_blocks_documents/client.py +334 -0
- prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
- prefect/client/orchestration/_blocks_schemas/client.py +200 -0
- prefect/client/orchestration/_blocks_types/__init__.py +0 -0
- prefect/client/orchestration/_blocks_types/client.py +380 -0
- prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- prefect/client/orchestration/_concurrency_limits/client.py +762 -0
- prefect/client/orchestration/_deployments/__init__.py +0 -0
- prefect/client/orchestration/_deployments/client.py +1128 -0
- prefect/client/orchestration/_flow_runs/__init__.py +0 -0
- prefect/client/orchestration/_flow_runs/client.py +903 -0
- prefect/client/orchestration/_flows/__init__.py +0 -0
- prefect/client/orchestration/_flows/client.py +343 -0
- prefect/client/orchestration/_logs/__init__.py +0 -0
- prefect/client/orchestration/_logs/client.py +97 -0
- prefect/client/orchestration/_variables/__init__.py +0 -0
- prefect/client/orchestration/_variables/client.py +157 -0
- prefect/client/orchestration/base.py +46 -0
- prefect/client/orchestration/routes.py +145 -0
- prefect/client/schemas/__init__.py +68 -28
- prefect/client/schemas/actions.py +2 -2
- prefect/client/schemas/filters.py +5 -0
- prefect/client/schemas/objects.py +8 -15
- prefect/client/schemas/schedules.py +22 -10
- prefect/concurrency/_asyncio.py +87 -0
- prefect/concurrency/{events.py → _events.py} +10 -10
- prefect/concurrency/asyncio.py +20 -104
- prefect/concurrency/context.py +6 -4
- prefect/concurrency/services.py +26 -74
- prefect/concurrency/sync.py +23 -44
- prefect/concurrency/v1/_asyncio.py +63 -0
- prefect/concurrency/v1/{events.py → _events.py} +13 -15
- prefect/concurrency/v1/asyncio.py +27 -80
- prefect/concurrency/v1/context.py +6 -4
- prefect/concurrency/v1/services.py +33 -79
- prefect/concurrency/v1/sync.py +18 -37
- prefect/context.py +66 -45
- prefect/deployments/base.py +10 -144
- prefect/deployments/flow_runs.py +12 -2
- prefect/deployments/runner.py +53 -4
- prefect/deployments/steps/pull.py +13 -0
- prefect/engine.py +17 -4
- prefect/events/clients.py +7 -1
- prefect/events/schemas/events.py +3 -2
- prefect/filesystems.py +6 -2
- prefect/flow_engine.py +101 -85
- prefect/flows.py +10 -1
- prefect/input/run_input.py +2 -1
- prefect/logging/logging.yml +1 -1
- prefect/main.py +1 -3
- prefect/results.py +2 -307
- prefect/runner/runner.py +4 -2
- prefect/runner/storage.py +87 -21
- prefect/serializers.py +32 -25
- prefect/settings/legacy.py +4 -4
- prefect/settings/models/api.py +3 -3
- prefect/settings/models/cli.py +3 -3
- prefect/settings/models/client.py +5 -3
- prefect/settings/models/cloud.py +8 -3
- prefect/settings/models/deployments.py +3 -3
- prefect/settings/models/experiments.py +4 -7
- prefect/settings/models/flows.py +3 -3
- prefect/settings/models/internal.py +4 -2
- prefect/settings/models/logging.py +4 -3
- prefect/settings/models/results.py +3 -3
- prefect/settings/models/root.py +3 -2
- prefect/settings/models/runner.py +4 -4
- prefect/settings/models/server/api.py +3 -3
- prefect/settings/models/server/database.py +11 -4
- prefect/settings/models/server/deployments.py +6 -2
- prefect/settings/models/server/ephemeral.py +4 -2
- prefect/settings/models/server/events.py +3 -2
- prefect/settings/models/server/flow_run_graph.py +6 -2
- prefect/settings/models/server/root.py +3 -3
- prefect/settings/models/server/services.py +26 -11
- prefect/settings/models/server/tasks.py +6 -3
- prefect/settings/models/server/ui.py +3 -3
- prefect/settings/models/tasks.py +5 -5
- prefect/settings/models/testing.py +3 -3
- prefect/settings/models/worker.py +5 -3
- prefect/settings/profiles.py +15 -2
- prefect/states.py +61 -45
- prefect/task_engine.py +54 -75
- prefect/task_runners.py +56 -55
- prefect/task_worker.py +2 -2
- prefect/tasks.py +90 -36
- prefect/telemetry/bootstrap.py +10 -9
- prefect/telemetry/run_telemetry.py +13 -8
- prefect/telemetry/services.py +4 -0
- prefect/transactions.py +4 -15
- prefect/utilities/_git.py +34 -0
- prefect/utilities/asyncutils.py +1 -1
- prefect/utilities/engine.py +3 -19
- prefect/utilities/generics.py +18 -0
- prefect/utilities/templating.py +25 -1
- prefect/workers/base.py +6 -3
- prefect/workers/process.py +1 -1
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/METADATA +2 -2
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/RECORD +135 -109
- prefect/client/orchestration.py +0 -4523
- prefect/records/__init__.py +0 -1
- prefect/records/base.py +0 -235
- prefect/records/filesystem.py +0 -213
- prefect/records/memory.py +0 -184
- prefect/records/result_store.py +0 -70
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,903 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Iterable
|
4
|
+
from typing import TYPE_CHECKING, Any
|
5
|
+
|
6
|
+
import httpx
|
7
|
+
from typing_extensions import TypeVar
|
8
|
+
|
9
|
+
from prefect.client.orchestration.base import BaseAsyncClient, BaseClient
|
10
|
+
from prefect.exceptions import ObjectNotFound
|
11
|
+
|
12
|
+
T = TypeVar("T")
|
13
|
+
R = TypeVar("R", infer_variance=True)
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from uuid import UUID
|
17
|
+
|
18
|
+
from prefect.client.schemas import FlowRun, OrchestrationResult
|
19
|
+
from prefect.client.schemas.filters import (
|
20
|
+
DeploymentFilter,
|
21
|
+
FlowFilter,
|
22
|
+
FlowRunFilter,
|
23
|
+
TaskRunFilter,
|
24
|
+
WorkPoolFilter,
|
25
|
+
WorkQueueFilter,
|
26
|
+
)
|
27
|
+
from prefect.client.schemas.objects import (
|
28
|
+
FlowRunInput,
|
29
|
+
FlowRunPolicy,
|
30
|
+
)
|
31
|
+
from prefect.client.schemas.sorting import (
|
32
|
+
FlowRunSort,
|
33
|
+
)
|
34
|
+
from prefect.flows import Flow as FlowObject
|
35
|
+
from prefect.states import State
|
36
|
+
from prefect.types import KeyValueLabelsField
|
37
|
+
|
38
|
+
|
39
|
+
class FlowRunClient(BaseClient):
|
40
|
+
def create_flow_run(
|
41
|
+
self,
|
42
|
+
flow: "FlowObject[Any, R]",
|
43
|
+
name: str | None = None,
|
44
|
+
parameters: dict[str, Any] | None = None,
|
45
|
+
context: dict[str, Any] | None = None,
|
46
|
+
tags: "Iterable[str] | None" = None,
|
47
|
+
parent_task_run_id: "UUID | None" = None,
|
48
|
+
state: "State[R] | None" = None,
|
49
|
+
) -> "FlowRun":
|
50
|
+
"""
|
51
|
+
Create a flow run for a flow.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
flow: The flow model to create the flow run for
|
55
|
+
name: An optional name for the flow run
|
56
|
+
parameters: Parameter overrides for this flow run.
|
57
|
+
context: Optional run context data
|
58
|
+
tags: a list of tags to apply to this flow run
|
59
|
+
parent_task_run_id: if a subflow run is being created, the placeholder task
|
60
|
+
run identifier in the parent flow
|
61
|
+
state: The initial state for the run. If not provided, defaults to
|
62
|
+
`Scheduled` for now. Should always be a `Scheduled` type.
|
63
|
+
|
64
|
+
Raises:
|
65
|
+
httpx.RequestError: if the Prefect API does not successfully create a run for any reason
|
66
|
+
|
67
|
+
Returns:
|
68
|
+
The flow run model
|
69
|
+
"""
|
70
|
+
from prefect.client.schemas.actions import FlowCreate, FlowRunCreate
|
71
|
+
from prefect.client.schemas.objects import Flow, FlowRun, FlowRunPolicy
|
72
|
+
from prefect.states import Pending
|
73
|
+
|
74
|
+
parameters = parameters or {}
|
75
|
+
context = context or {}
|
76
|
+
|
77
|
+
if state is None:
|
78
|
+
state = Pending()
|
79
|
+
|
80
|
+
# Retrieve the flow id
|
81
|
+
|
82
|
+
flow_data = FlowCreate(name=flow.name)
|
83
|
+
response = self.request(
|
84
|
+
"POST", "/flows/", json=flow_data.model_dump(mode="json")
|
85
|
+
)
|
86
|
+
flow_id = Flow.model_validate(response.json()).id
|
87
|
+
|
88
|
+
flow_run_create = FlowRunCreate(
|
89
|
+
flow_id=flow_id,
|
90
|
+
flow_version=flow.version,
|
91
|
+
name=name,
|
92
|
+
parameters=parameters,
|
93
|
+
context=context,
|
94
|
+
tags=list(tags or []),
|
95
|
+
parent_task_run_id=parent_task_run_id,
|
96
|
+
state=state.to_state_create(),
|
97
|
+
empirical_policy=FlowRunPolicy(
|
98
|
+
retries=flow.retries,
|
99
|
+
retry_delay=int(flow.retry_delay_seconds or 0),
|
100
|
+
),
|
101
|
+
)
|
102
|
+
|
103
|
+
flow_run_create_json = flow_run_create.model_dump(mode="json")
|
104
|
+
response = self.request("POST", "/flow_runs/", json=flow_run_create_json)
|
105
|
+
|
106
|
+
flow_run = FlowRun.model_validate(response.json())
|
107
|
+
|
108
|
+
# Restore the parameters to the local objects to retain expectations about
|
109
|
+
# Python objects
|
110
|
+
flow_run.parameters = parameters
|
111
|
+
|
112
|
+
return flow_run
|
113
|
+
|
114
|
+
def update_flow_run(
|
115
|
+
self,
|
116
|
+
flow_run_id: "UUID",
|
117
|
+
flow_version: str | None = None,
|
118
|
+
parameters: dict[str, Any] | None = None,
|
119
|
+
name: str | None = None,
|
120
|
+
tags: "Iterable[str] | None" = None,
|
121
|
+
empirical_policy: "FlowRunPolicy | None" = None,
|
122
|
+
infrastructure_pid: str | None = None,
|
123
|
+
job_variables: dict[str, Any] | None = None,
|
124
|
+
) -> httpx.Response:
|
125
|
+
"""
|
126
|
+
Update a flow run's details.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
flow_run_id: The identifier for the flow run to update.
|
130
|
+
flow_version: A new version string for the flow run.
|
131
|
+
parameters: A dictionary of parameter values for the flow run. This will not
|
132
|
+
be merged with any existing parameters.
|
133
|
+
name: A new name for the flow run.
|
134
|
+
empirical_policy: A new flow run orchestration policy. This will not be
|
135
|
+
merged with any existing policy.
|
136
|
+
tags: An iterable of new tags for the flow run. These will not be merged with
|
137
|
+
any existing tags.
|
138
|
+
infrastructure_pid: The id of flow run as returned by an
|
139
|
+
infrastructure block.
|
140
|
+
|
141
|
+
Returns:
|
142
|
+
an `httpx.Response` object from the PATCH request
|
143
|
+
"""
|
144
|
+
params: dict[str, Any] = {}
|
145
|
+
if flow_version is not None:
|
146
|
+
params["flow_version"] = flow_version
|
147
|
+
if parameters is not None:
|
148
|
+
params["parameters"] = parameters
|
149
|
+
if name is not None:
|
150
|
+
params["name"] = name
|
151
|
+
if tags is not None:
|
152
|
+
params["tags"] = tags
|
153
|
+
if empirical_policy is not None:
|
154
|
+
params["empirical_policy"] = empirical_policy
|
155
|
+
if infrastructure_pid:
|
156
|
+
params["infrastructure_pid"] = infrastructure_pid
|
157
|
+
if job_variables is not None:
|
158
|
+
params["job_variables"] = job_variables
|
159
|
+
|
160
|
+
from prefect.client.schemas.actions import FlowRunUpdate
|
161
|
+
|
162
|
+
flow_run_data = FlowRunUpdate(**params)
|
163
|
+
|
164
|
+
return self.request(
|
165
|
+
"PATCH",
|
166
|
+
"/flow_runs/{id}",
|
167
|
+
path_params={"id": flow_run_id},
|
168
|
+
json=flow_run_data.model_dump(mode="json", exclude_unset=True),
|
169
|
+
)
|
170
|
+
|
171
|
+
def delete_flow_run(
|
172
|
+
self,
|
173
|
+
flow_run_id: "UUID",
|
174
|
+
) -> None:
|
175
|
+
"""
|
176
|
+
Delete a flow run by UUID.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
flow_run_id: The flow run UUID of interest.
|
180
|
+
Raises:
|
181
|
+
ObjectNotFound: If request returns 404
|
182
|
+
httpx.RequestError: If requests fails
|
183
|
+
"""
|
184
|
+
try:
|
185
|
+
self.request("DELETE", "/flow_runs/{id}", path_params={"id": flow_run_id})
|
186
|
+
except httpx.HTTPStatusError as e:
|
187
|
+
if e.response.status_code == 404:
|
188
|
+
raise ObjectNotFound(http_exc=e) from e
|
189
|
+
else:
|
190
|
+
raise
|
191
|
+
|
192
|
+
def read_flow_run(self, flow_run_id: "UUID") -> "FlowRun":
|
193
|
+
"""
|
194
|
+
Query the Prefect API for a flow run by id.
|
195
|
+
|
196
|
+
Args:
|
197
|
+
flow_run_id: the flow run ID of interest
|
198
|
+
|
199
|
+
Returns:
|
200
|
+
a Flow Run model representation of the flow run
|
201
|
+
"""
|
202
|
+
try:
|
203
|
+
response = self.request(
|
204
|
+
"GET", "/flow_runs/{id}", path_params={"id": flow_run_id}
|
205
|
+
)
|
206
|
+
except httpx.HTTPStatusError as e:
|
207
|
+
if e.response.status_code == 404:
|
208
|
+
raise ObjectNotFound(http_exc=e) from e
|
209
|
+
else:
|
210
|
+
raise
|
211
|
+
from prefect.client.schemas.objects import FlowRun
|
212
|
+
|
213
|
+
return FlowRun.model_validate(response.json())
|
214
|
+
|
215
|
+
def resume_flow_run(
|
216
|
+
self, flow_run_id: "UUID", run_input: dict[str, Any] | None = None
|
217
|
+
) -> "OrchestrationResult[Any]":
|
218
|
+
"""
|
219
|
+
Resumes a paused flow run.
|
220
|
+
|
221
|
+
Args:
|
222
|
+
flow_run_id: the flow run ID of interest
|
223
|
+
run_input: the input to resume the flow run with
|
224
|
+
|
225
|
+
Returns:
|
226
|
+
an OrchestrationResult model representation of state orchestration output
|
227
|
+
"""
|
228
|
+
try:
|
229
|
+
response = self.request(
|
230
|
+
"POST",
|
231
|
+
"/flow_runs/{id}/resume",
|
232
|
+
path_params={"id": flow_run_id},
|
233
|
+
json={"run_input": run_input},
|
234
|
+
)
|
235
|
+
except httpx.HTTPStatusError:
|
236
|
+
raise
|
237
|
+
from prefect.client.schemas import OrchestrationResult
|
238
|
+
|
239
|
+
result: OrchestrationResult[Any] = OrchestrationResult.model_validate(
|
240
|
+
response.json()
|
241
|
+
)
|
242
|
+
return result
|
243
|
+
|
244
|
+
def read_flow_runs(
|
245
|
+
self,
|
246
|
+
*,
|
247
|
+
flow_filter: "FlowFilter | None" = None,
|
248
|
+
flow_run_filter: "FlowRunFilter | None" = None,
|
249
|
+
task_run_filter: "TaskRunFilter | None" = None,
|
250
|
+
deployment_filter: "DeploymentFilter | None" = None,
|
251
|
+
work_pool_filter: "WorkPoolFilter | None" = None,
|
252
|
+
work_queue_filter: "WorkQueueFilter | None" = None,
|
253
|
+
sort: "FlowRunSort | None" = None,
|
254
|
+
limit: int | None = None,
|
255
|
+
offset: int = 0,
|
256
|
+
) -> "list[FlowRun]":
|
257
|
+
"""
|
258
|
+
Query the Prefect API for flow runs. Only flow runs matching all criteria will
|
259
|
+
be returned.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
flow_filter: filter criteria for flows
|
263
|
+
flow_run_filter: filter criteria for flow runs
|
264
|
+
task_run_filter: filter criteria for task runs
|
265
|
+
deployment_filter: filter criteria for deployments
|
266
|
+
work_pool_filter: filter criteria for work pools
|
267
|
+
work_queue_filter: filter criteria for work pool queues
|
268
|
+
sort: sort criteria for the flow runs
|
269
|
+
limit: limit for the flow run query
|
270
|
+
offset: offset for the flow run query
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
a list of Flow Run model representations
|
274
|
+
of the flow runs
|
275
|
+
"""
|
276
|
+
body: dict[str, Any] = {
|
277
|
+
"flows": flow_filter.model_dump(mode="json") if flow_filter else None,
|
278
|
+
"flow_runs": (
|
279
|
+
flow_run_filter.model_dump(mode="json", exclude_unset=True)
|
280
|
+
if flow_run_filter
|
281
|
+
else None
|
282
|
+
),
|
283
|
+
"task_runs": (
|
284
|
+
task_run_filter.model_dump(mode="json") if task_run_filter else None
|
285
|
+
),
|
286
|
+
"deployments": (
|
287
|
+
deployment_filter.model_dump(mode="json") if deployment_filter else None
|
288
|
+
),
|
289
|
+
"work_pools": (
|
290
|
+
work_pool_filter.model_dump(mode="json") if work_pool_filter else None
|
291
|
+
),
|
292
|
+
"work_pool_queues": (
|
293
|
+
work_queue_filter.model_dump(mode="json") if work_queue_filter else None
|
294
|
+
),
|
295
|
+
"sort": sort,
|
296
|
+
"limit": limit,
|
297
|
+
"offset": offset,
|
298
|
+
}
|
299
|
+
|
300
|
+
response = self.request("POST", "/flow_runs/filter", json=body)
|
301
|
+
from prefect.client.schemas.objects import FlowRun
|
302
|
+
|
303
|
+
return FlowRun.model_validate_list(response.json())
|
304
|
+
|
305
|
+
def set_flow_run_state(
|
306
|
+
self,
|
307
|
+
flow_run_id: "UUID | str",
|
308
|
+
state: "State[T]",
|
309
|
+
force: bool = False,
|
310
|
+
) -> "OrchestrationResult[T]":
|
311
|
+
"""
|
312
|
+
Set the state of a flow run.
|
313
|
+
|
314
|
+
Args:
|
315
|
+
flow_run_id: the id of the flow run
|
316
|
+
state: the state to set
|
317
|
+
force: if True, disregard orchestration logic when setting the state,
|
318
|
+
forcing the Prefect API to accept the state
|
319
|
+
|
320
|
+
Returns:
|
321
|
+
an OrchestrationResult model representation of state orchestration output
|
322
|
+
"""
|
323
|
+
from uuid import UUID, uuid4
|
324
|
+
|
325
|
+
flow_run_id = (
|
326
|
+
flow_run_id if isinstance(flow_run_id, UUID) else UUID(flow_run_id)
|
327
|
+
)
|
328
|
+
state_create = state.to_state_create()
|
329
|
+
state_create.state_details.flow_run_id = flow_run_id
|
330
|
+
state_create.state_details.transition_id = uuid4()
|
331
|
+
try:
|
332
|
+
response = self.request(
|
333
|
+
"POST",
|
334
|
+
"/flow_runs/{id}/set_state",
|
335
|
+
path_params={"id": flow_run_id},
|
336
|
+
json=dict(
|
337
|
+
state=state_create.model_dump(mode="json", serialize_as_any=True),
|
338
|
+
force=force,
|
339
|
+
),
|
340
|
+
)
|
341
|
+
except httpx.HTTPStatusError as e:
|
342
|
+
if e.response.status_code == 404:
|
343
|
+
raise ObjectNotFound(http_exc=e) from e
|
344
|
+
else:
|
345
|
+
raise
|
346
|
+
from prefect.client.schemas import OrchestrationResult
|
347
|
+
|
348
|
+
result: OrchestrationResult[T] = OrchestrationResult.model_validate(
|
349
|
+
response.json()
|
350
|
+
)
|
351
|
+
return result
|
352
|
+
|
353
|
+
def read_flow_run_states(self, flow_run_id: "UUID") -> "list[State]":
|
354
|
+
"""
|
355
|
+
Query for the states of a flow run
|
356
|
+
|
357
|
+
Args:
|
358
|
+
flow_run_id: the id of the flow run
|
359
|
+
|
360
|
+
Returns:
|
361
|
+
a list of State model representations
|
362
|
+
of the flow run states
|
363
|
+
"""
|
364
|
+
response = self.request(
|
365
|
+
"GET", "/flow_run_states/", params=dict(flow_run_id=str(flow_run_id))
|
366
|
+
)
|
367
|
+
from prefect.states import State
|
368
|
+
|
369
|
+
return State.model_validate_list(response.json())
|
370
|
+
|
371
|
+
def set_flow_run_name(self, flow_run_id: "UUID", name: str) -> httpx.Response:
|
372
|
+
from prefect.client.schemas.actions import FlowRunUpdate
|
373
|
+
|
374
|
+
flow_run_data = FlowRunUpdate(name=name)
|
375
|
+
return self.request(
|
376
|
+
"PATCH",
|
377
|
+
"/flow_runs/{id}",
|
378
|
+
path_params={"id": flow_run_id},
|
379
|
+
json=flow_run_data.model_dump(mode="json", exclude_unset=True),
|
380
|
+
)
|
381
|
+
|
382
|
+
def create_flow_run_input(
|
383
|
+
self, flow_run_id: "UUID", key: str, value: str, sender: str | None = None
|
384
|
+
) -> None:
|
385
|
+
"""
|
386
|
+
Creates a flow run input.
|
387
|
+
|
388
|
+
Args:
|
389
|
+
flow_run_id: The flow run id.
|
390
|
+
key: The input key.
|
391
|
+
value: The input value.
|
392
|
+
sender: The sender of the input.
|
393
|
+
"""
|
394
|
+
|
395
|
+
# Initialize the input to ensure that the key is valid.
|
396
|
+
FlowRunInput(flow_run_id=flow_run_id, key=key, value=value)
|
397
|
+
|
398
|
+
response = self.request(
|
399
|
+
"POST",
|
400
|
+
"/flow_runs/{id}/input",
|
401
|
+
path_params={"id": flow_run_id},
|
402
|
+
json={"key": key, "value": value, "sender": sender},
|
403
|
+
)
|
404
|
+
response.raise_for_status()
|
405
|
+
|
406
|
+
def filter_flow_run_input(
|
407
|
+
self, flow_run_id: "UUID", key_prefix: str, limit: int, exclude_keys: "set[str]"
|
408
|
+
) -> "list[FlowRunInput]":
|
409
|
+
response = self.request(
|
410
|
+
"POST",
|
411
|
+
"/flow_runs/{id}/input/filter",
|
412
|
+
path_params={"id": flow_run_id},
|
413
|
+
json={
|
414
|
+
"prefix": key_prefix,
|
415
|
+
"limit": limit,
|
416
|
+
"exclude_keys": list(exclude_keys),
|
417
|
+
},
|
418
|
+
)
|
419
|
+
response.raise_for_status()
|
420
|
+
from prefect.client.schemas.objects import FlowRunInput
|
421
|
+
|
422
|
+
return FlowRunInput.model_validate_list(response.json())
|
423
|
+
|
424
|
+
def read_flow_run_input(self, flow_run_id: "UUID", key: str) -> str:
|
425
|
+
"""
|
426
|
+
Reads a flow run input.
|
427
|
+
|
428
|
+
Args:
|
429
|
+
flow_run_id: The flow run id.
|
430
|
+
key: The input key.
|
431
|
+
"""
|
432
|
+
response = self.request(
|
433
|
+
"GET",
|
434
|
+
"/flow_runs/{id}/input/{key}",
|
435
|
+
path_params={"id": flow_run_id, "key": key},
|
436
|
+
)
|
437
|
+
response.raise_for_status()
|
438
|
+
return response.content.decode()
|
439
|
+
|
440
|
+
def delete_flow_run_input(self, flow_run_id: "UUID", key: str) -> None:
|
441
|
+
"""
|
442
|
+
Deletes a flow run input.
|
443
|
+
|
444
|
+
Args:
|
445
|
+
flow_run_id: The flow run id.
|
446
|
+
key: The input key.
|
447
|
+
"""
|
448
|
+
response = self.request(
|
449
|
+
"DELETE",
|
450
|
+
"/flow_runs/{id}/input/{key}",
|
451
|
+
path_params={"id": flow_run_id, "key": key},
|
452
|
+
)
|
453
|
+
response.raise_for_status()
|
454
|
+
|
455
|
+
def update_flow_run_labels(
|
456
|
+
self, flow_run_id: "UUID", labels: "KeyValueLabelsField"
|
457
|
+
) -> None:
|
458
|
+
"""
|
459
|
+
Updates the labels of a flow run.
|
460
|
+
"""
|
461
|
+
|
462
|
+
response = self.request(
|
463
|
+
"PATCH",
|
464
|
+
"/flow_runs/{id}/labels",
|
465
|
+
path_params={"id": flow_run_id},
|
466
|
+
json=labels,
|
467
|
+
)
|
468
|
+
response.raise_for_status()
|
469
|
+
|
470
|
+
|
471
|
+
class FlowRunAsyncClient(BaseAsyncClient):
|
472
|
+
async def create_flow_run(
|
473
|
+
self,
|
474
|
+
flow: "FlowObject[Any, R]",
|
475
|
+
name: str | None = None,
|
476
|
+
parameters: dict[str, Any] | None = None,
|
477
|
+
context: dict[str, Any] | None = None,
|
478
|
+
tags: "Iterable[str] | None" = None,
|
479
|
+
parent_task_run_id: "UUID | None" = None,
|
480
|
+
state: "State[R] | None" = None,
|
481
|
+
) -> "FlowRun":
|
482
|
+
"""
|
483
|
+
Create a flow run for a flow.
|
484
|
+
|
485
|
+
Args:
|
486
|
+
flow: The flow model to create the flow run for
|
487
|
+
name: An optional name for the flow run
|
488
|
+
parameters: Parameter overrides for this flow run.
|
489
|
+
context: Optional run context data
|
490
|
+
tags: a list of tags to apply to this flow run
|
491
|
+
parent_task_run_id: if a subflow run is being created, the placeholder task
|
492
|
+
run identifier in the parent flow
|
493
|
+
state: The initial state for the run. If not provided, defaults to
|
494
|
+
`Scheduled` for now. Should always be a `Scheduled` type.
|
495
|
+
|
496
|
+
Raises:
|
497
|
+
httpx.RequestError: if the Prefect API does not successfully create a run for any reason
|
498
|
+
|
499
|
+
Returns:
|
500
|
+
The flow run model
|
501
|
+
"""
|
502
|
+
from prefect.client.schemas.actions import FlowCreate, FlowRunCreate
|
503
|
+
from prefect.client.schemas.objects import Flow, FlowRun, FlowRunPolicy
|
504
|
+
from prefect.states import Pending
|
505
|
+
|
506
|
+
parameters = parameters or {}
|
507
|
+
context = context or {}
|
508
|
+
|
509
|
+
if state is None:
|
510
|
+
state = Pending()
|
511
|
+
|
512
|
+
# Retrieve the flow id
|
513
|
+
|
514
|
+
flow_data = FlowCreate(name=flow.name)
|
515
|
+
response = await self.request(
|
516
|
+
"POST", "/flows/", json=flow_data.model_dump(mode="json")
|
517
|
+
)
|
518
|
+
flow_id = Flow.model_validate(response.json()).id
|
519
|
+
|
520
|
+
flow_run_create = FlowRunCreate(
|
521
|
+
flow_id=flow_id,
|
522
|
+
flow_version=flow.version,
|
523
|
+
name=name,
|
524
|
+
parameters=parameters,
|
525
|
+
context=context,
|
526
|
+
tags=list(tags or []),
|
527
|
+
parent_task_run_id=parent_task_run_id,
|
528
|
+
state=state.to_state_create(),
|
529
|
+
empirical_policy=FlowRunPolicy(
|
530
|
+
retries=flow.retries,
|
531
|
+
retry_delay=int(flow.retry_delay_seconds or 0),
|
532
|
+
),
|
533
|
+
)
|
534
|
+
|
535
|
+
flow_run_create_json = flow_run_create.model_dump(mode="json")
|
536
|
+
response = await self.request("POST", "/flow_runs/", json=flow_run_create_json)
|
537
|
+
|
538
|
+
flow_run = FlowRun.model_validate(response.json())
|
539
|
+
|
540
|
+
# Restore the parameters to the local objects to retain expectations about
|
541
|
+
# Python objects
|
542
|
+
flow_run.parameters = parameters
|
543
|
+
|
544
|
+
return flow_run
|
545
|
+
|
546
|
+
async def update_flow_run(
|
547
|
+
self,
|
548
|
+
flow_run_id: "UUID",
|
549
|
+
flow_version: str | None = None,
|
550
|
+
parameters: dict[str, Any] | None = None,
|
551
|
+
name: str | None = None,
|
552
|
+
tags: "Iterable[str] | None" = None,
|
553
|
+
empirical_policy: "FlowRunPolicy | None" = None,
|
554
|
+
infrastructure_pid: str | None = None,
|
555
|
+
job_variables: dict[str, Any] | None = None,
|
556
|
+
) -> httpx.Response:
|
557
|
+
"""
|
558
|
+
Update a flow run's details.
|
559
|
+
|
560
|
+
Args:
|
561
|
+
flow_run_id: The identifier for the flow run to update.
|
562
|
+
flow_version: A new version string for the flow run.
|
563
|
+
parameters: A dictionary of parameter values for the flow run. This will not
|
564
|
+
be merged with any existing parameters.
|
565
|
+
name: A new name for the flow run.
|
566
|
+
empirical_policy: A new flow run orchestration policy. This will not be
|
567
|
+
merged with any existing policy.
|
568
|
+
tags: An iterable of new tags for the flow run. These will not be merged with
|
569
|
+
any existing tags.
|
570
|
+
infrastructure_pid: The id of flow run as returned by an
|
571
|
+
infrastructure block.
|
572
|
+
|
573
|
+
Returns:
|
574
|
+
an `httpx.Response` object from the PATCH request
|
575
|
+
"""
|
576
|
+
params: dict[str, Any] = {}
|
577
|
+
if flow_version is not None:
|
578
|
+
params["flow_version"] = flow_version
|
579
|
+
if parameters is not None:
|
580
|
+
params["parameters"] = parameters
|
581
|
+
if name is not None:
|
582
|
+
params["name"] = name
|
583
|
+
if tags is not None:
|
584
|
+
params["tags"] = tags
|
585
|
+
if empirical_policy is not None:
|
586
|
+
params["empirical_policy"] = empirical_policy
|
587
|
+
if infrastructure_pid:
|
588
|
+
params["infrastructure_pid"] = infrastructure_pid
|
589
|
+
if job_variables is not None:
|
590
|
+
params["job_variables"] = job_variables
|
591
|
+
from prefect.client.schemas.actions import FlowRunUpdate
|
592
|
+
|
593
|
+
flow_run_data = FlowRunUpdate(**params)
|
594
|
+
|
595
|
+
return await self.request(
|
596
|
+
"PATCH",
|
597
|
+
"/flow_runs/{id}",
|
598
|
+
path_params={"id": flow_run_id},
|
599
|
+
json=flow_run_data.model_dump(mode="json", exclude_unset=True),
|
600
|
+
)
|
601
|
+
|
602
|
+
async def delete_flow_run(
|
603
|
+
self,
|
604
|
+
flow_run_id: "UUID",
|
605
|
+
) -> None:
|
606
|
+
"""
|
607
|
+
Delete a flow run by UUID.
|
608
|
+
|
609
|
+
Args:
|
610
|
+
flow_run_id: The flow run UUID of interest.
|
611
|
+
Raises:
|
612
|
+
ObjectNotFound: If request returns 404
|
613
|
+
httpx.RequestError: If requests fails
|
614
|
+
"""
|
615
|
+
try:
|
616
|
+
await self.request(
|
617
|
+
"DELETE", "/flow_runs/{id}", path_params={"id": flow_run_id}
|
618
|
+
)
|
619
|
+
except httpx.HTTPStatusError as e:
|
620
|
+
if e.response.status_code == 404:
|
621
|
+
raise ObjectNotFound(http_exc=e) from e
|
622
|
+
else:
|
623
|
+
raise
|
624
|
+
|
625
|
+
async def read_flow_run(self, flow_run_id: "UUID") -> "FlowRun":
|
626
|
+
"""
|
627
|
+
Query the Prefect API for a flow run by id.
|
628
|
+
|
629
|
+
Args:
|
630
|
+
flow_run_id: the flow run ID of interest
|
631
|
+
|
632
|
+
Returns:
|
633
|
+
a Flow Run model representation of the flow run
|
634
|
+
"""
|
635
|
+
try:
|
636
|
+
response = await self.request(
|
637
|
+
"GET", "/flow_runs/{id}", path_params={"id": flow_run_id}
|
638
|
+
)
|
639
|
+
except httpx.HTTPStatusError as e:
|
640
|
+
if e.response.status_code == 404:
|
641
|
+
raise ObjectNotFound(http_exc=e) from e
|
642
|
+
else:
|
643
|
+
raise
|
644
|
+
from prefect.client.schemas.objects import FlowRun
|
645
|
+
|
646
|
+
return FlowRun.model_validate(response.json())
|
647
|
+
|
648
|
+
async def resume_flow_run(
|
649
|
+
self, flow_run_id: "UUID", run_input: dict[str, Any] | None = None
|
650
|
+
) -> "OrchestrationResult[Any]":
|
651
|
+
"""
|
652
|
+
Resumes a paused flow run.
|
653
|
+
|
654
|
+
Args:
|
655
|
+
flow_run_id: the flow run ID of interest
|
656
|
+
run_input: the input to resume the flow run with
|
657
|
+
|
658
|
+
Returns:
|
659
|
+
an OrchestrationResult model representation of state orchestration output
|
660
|
+
"""
|
661
|
+
try:
|
662
|
+
response = await self.request(
|
663
|
+
"POST",
|
664
|
+
"/flow_runs/{id}/resume",
|
665
|
+
path_params={"id": flow_run_id},
|
666
|
+
json={"run_input": run_input},
|
667
|
+
)
|
668
|
+
except httpx.HTTPStatusError:
|
669
|
+
raise
|
670
|
+
from prefect.client.schemas import OrchestrationResult
|
671
|
+
|
672
|
+
result: OrchestrationResult[Any] = OrchestrationResult.model_validate(
|
673
|
+
response.json()
|
674
|
+
)
|
675
|
+
return result
|
676
|
+
|
677
|
+
async def read_flow_runs(
|
678
|
+
self,
|
679
|
+
*,
|
680
|
+
flow_filter: "FlowFilter | None" = None,
|
681
|
+
flow_run_filter: "FlowRunFilter | None" = None,
|
682
|
+
task_run_filter: "TaskRunFilter | None" = None,
|
683
|
+
deployment_filter: "DeploymentFilter | None" = None,
|
684
|
+
work_pool_filter: "WorkPoolFilter | None" = None,
|
685
|
+
work_queue_filter: "WorkQueueFilter | None" = None,
|
686
|
+
sort: "FlowRunSort | None" = None,
|
687
|
+
limit: int | None = None,
|
688
|
+
offset: int = 0,
|
689
|
+
) -> "list[FlowRun]":
|
690
|
+
"""
|
691
|
+
Query the Prefect API for flow runs. Only flow runs matching all criteria will
|
692
|
+
be returned.
|
693
|
+
|
694
|
+
Args:
|
695
|
+
flow_filter: filter criteria for flows
|
696
|
+
flow_run_filter: filter criteria for flow runs
|
697
|
+
task_run_filter: filter criteria for task runs
|
698
|
+
deployment_filter: filter criteria for deployments
|
699
|
+
work_pool_filter: filter criteria for work pools
|
700
|
+
work_queue_filter: filter criteria for work pool queues
|
701
|
+
sort: sort criteria for the flow runs
|
702
|
+
limit: limit for the flow run query
|
703
|
+
offset: offset for the flow run query
|
704
|
+
|
705
|
+
Returns:
|
706
|
+
a list of Flow Run model representations
|
707
|
+
of the flow runs
|
708
|
+
"""
|
709
|
+
body: dict[str, Any] = {
|
710
|
+
"flows": flow_filter.model_dump(mode="json") if flow_filter else None,
|
711
|
+
"flow_runs": (
|
712
|
+
flow_run_filter.model_dump(mode="json", exclude_unset=True)
|
713
|
+
if flow_run_filter
|
714
|
+
else None
|
715
|
+
),
|
716
|
+
"task_runs": (
|
717
|
+
task_run_filter.model_dump(mode="json") if task_run_filter else None
|
718
|
+
),
|
719
|
+
"deployments": (
|
720
|
+
deployment_filter.model_dump(mode="json") if deployment_filter else None
|
721
|
+
),
|
722
|
+
"work_pools": (
|
723
|
+
work_pool_filter.model_dump(mode="json") if work_pool_filter else None
|
724
|
+
),
|
725
|
+
"work_pool_queues": (
|
726
|
+
work_queue_filter.model_dump(mode="json") if work_queue_filter else None
|
727
|
+
),
|
728
|
+
"sort": sort,
|
729
|
+
"limit": limit,
|
730
|
+
"offset": offset,
|
731
|
+
}
|
732
|
+
|
733
|
+
response = await self.request("POST", "/flow_runs/filter", json=body)
|
734
|
+
from prefect.client.schemas.objects import FlowRun
|
735
|
+
|
736
|
+
return FlowRun.model_validate_list(response.json())
|
737
|
+
|
738
|
+
async def set_flow_run_state(
|
739
|
+
self,
|
740
|
+
flow_run_id: "UUID | str",
|
741
|
+
state: "State[T]",
|
742
|
+
force: bool = False,
|
743
|
+
) -> "OrchestrationResult[T]":
|
744
|
+
"""
|
745
|
+
Set the state of a flow run.
|
746
|
+
|
747
|
+
Args:
|
748
|
+
flow_run_id: the id of the flow run
|
749
|
+
state: the state to set
|
750
|
+
force: if True, disregard orchestration logic when setting the state,
|
751
|
+
forcing the Prefect API to accept the state
|
752
|
+
|
753
|
+
Returns:
|
754
|
+
an OrchestrationResult model representation of state orchestration output
|
755
|
+
"""
|
756
|
+
from uuid import UUID, uuid4
|
757
|
+
|
758
|
+
flow_run_id = (
|
759
|
+
flow_run_id if isinstance(flow_run_id, UUID) else UUID(flow_run_id)
|
760
|
+
)
|
761
|
+
state_create = state.to_state_create()
|
762
|
+
state_create.state_details.flow_run_id = flow_run_id
|
763
|
+
state_create.state_details.transition_id = uuid4()
|
764
|
+
try:
|
765
|
+
response = await self.request(
|
766
|
+
"POST",
|
767
|
+
"/flow_runs/{id}/set_state",
|
768
|
+
path_params={"id": flow_run_id},
|
769
|
+
json=dict(
|
770
|
+
state=state_create.model_dump(mode="json", serialize_as_any=True),
|
771
|
+
force=force,
|
772
|
+
),
|
773
|
+
)
|
774
|
+
except httpx.HTTPStatusError as e:
|
775
|
+
if e.response.status_code == 404:
|
776
|
+
raise ObjectNotFound(http_exc=e) from e
|
777
|
+
else:
|
778
|
+
raise
|
779
|
+
from prefect.client.schemas import OrchestrationResult
|
780
|
+
|
781
|
+
result: OrchestrationResult[T] = OrchestrationResult.model_validate(
|
782
|
+
response.json()
|
783
|
+
)
|
784
|
+
return result
|
785
|
+
|
786
|
+
async def read_flow_run_states(self, flow_run_id: "UUID") -> "list[State]":
|
787
|
+
"""
|
788
|
+
Query for the states of a flow run
|
789
|
+
|
790
|
+
Args:
|
791
|
+
flow_run_id: the id of the flow run
|
792
|
+
|
793
|
+
Returns:
|
794
|
+
a list of State model representations
|
795
|
+
of the flow run states
|
796
|
+
"""
|
797
|
+
response = await self.request(
|
798
|
+
"GET", "/flow_run_states/", params=dict(flow_run_id=str(flow_run_id))
|
799
|
+
)
|
800
|
+
from prefect.states import State
|
801
|
+
|
802
|
+
return State.model_validate_list(response.json())
|
803
|
+
|
804
|
+
async def set_flow_run_name(self, flow_run_id: "UUID", name: str) -> httpx.Response:
|
805
|
+
from prefect.client.schemas.actions import FlowRunUpdate
|
806
|
+
|
807
|
+
flow_run_data = FlowRunUpdate(name=name)
|
808
|
+
return await self.request(
|
809
|
+
"PATCH",
|
810
|
+
"/flow_runs/{id}",
|
811
|
+
path_params={"id": flow_run_id},
|
812
|
+
json=flow_run_data.model_dump(mode="json", exclude_unset=True),
|
813
|
+
)
|
814
|
+
|
815
|
+
async def create_flow_run_input(
|
816
|
+
self, flow_run_id: "UUID", key: str, value: str, sender: str | None = None
|
817
|
+
) -> None:
|
818
|
+
"""
|
819
|
+
Creates a flow run input.
|
820
|
+
|
821
|
+
Args:
|
822
|
+
flow_run_id: The flow run id.
|
823
|
+
key: The input key.
|
824
|
+
value: The input value.
|
825
|
+
sender: The sender of the input.
|
826
|
+
"""
|
827
|
+
|
828
|
+
# Initialize the input to ensure that the key is valid.
|
829
|
+
from prefect.client.schemas.objects import FlowRunInput
|
830
|
+
|
831
|
+
FlowRunInput(flow_run_id=flow_run_id, key=key, value=value)
|
832
|
+
|
833
|
+
response = await self.request(
|
834
|
+
"POST",
|
835
|
+
"/flow_runs/{id}/input",
|
836
|
+
path_params={"id": flow_run_id},
|
837
|
+
json={"key": key, "value": value, "sender": sender},
|
838
|
+
)
|
839
|
+
response.raise_for_status()
|
840
|
+
|
841
|
+
async def filter_flow_run_input(
|
842
|
+
self, flow_run_id: "UUID", key_prefix: str, limit: int, exclude_keys: "set[str]"
|
843
|
+
) -> "list[FlowRunInput]":
|
844
|
+
response = await self.request(
|
845
|
+
"POST",
|
846
|
+
"/flow_runs/{id}/input/filter",
|
847
|
+
path_params={"id": flow_run_id},
|
848
|
+
json={
|
849
|
+
"prefix": key_prefix,
|
850
|
+
"limit": limit,
|
851
|
+
"exclude_keys": list(exclude_keys),
|
852
|
+
},
|
853
|
+
)
|
854
|
+
response.raise_for_status()
|
855
|
+
from prefect.client.schemas.objects import FlowRunInput
|
856
|
+
|
857
|
+
return FlowRunInput.model_validate_list(response.json())
|
858
|
+
|
859
|
+
async def read_flow_run_input(self, flow_run_id: "UUID", key: str) -> str:
|
860
|
+
"""
|
861
|
+
Reads a flow run input.
|
862
|
+
|
863
|
+
Args:
|
864
|
+
flow_run_id: The flow run id.
|
865
|
+
key: The input key.
|
866
|
+
"""
|
867
|
+
response = await self.request(
|
868
|
+
"GET",
|
869
|
+
"/flow_runs/{id}/input/{key}",
|
870
|
+
path_params={"id": flow_run_id, "key": key},
|
871
|
+
)
|
872
|
+
response.raise_for_status()
|
873
|
+
return response.content.decode()
|
874
|
+
|
875
|
+
async def delete_flow_run_input(self, flow_run_id: "UUID", key: str) -> None:
|
876
|
+
"""
|
877
|
+
Deletes a flow run input.
|
878
|
+
|
879
|
+
Args:
|
880
|
+
flow_run_id: The flow run id.
|
881
|
+
key: The input key.
|
882
|
+
"""
|
883
|
+
response = await self.request(
|
884
|
+
"DELETE",
|
885
|
+
"/flow_runs/{id}/input/{key}",
|
886
|
+
path_params={"id": flow_run_id, "key": key},
|
887
|
+
)
|
888
|
+
response.raise_for_status()
|
889
|
+
|
890
|
+
async def update_flow_run_labels(
|
891
|
+
self, flow_run_id: "UUID", labels: "KeyValueLabelsField"
|
892
|
+
) -> None:
|
893
|
+
"""
|
894
|
+
Updates the labels of a flow run.
|
895
|
+
"""
|
896
|
+
|
897
|
+
response = await self.request(
|
898
|
+
"PATCH",
|
899
|
+
"/flow_runs/{id}/labels",
|
900
|
+
path_params={"id": flow_run_id},
|
901
|
+
json=labels,
|
902
|
+
)
|
903
|
+
response.raise_for_status()
|