prefect-client 3.1.15__py3-none-any.whl → 3.2.0__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/sla/objects.py +29 -1
- prefect/_internal/compatibility/deprecated.py +4 -4
- prefect/_internal/compatibility/migration.py +1 -1
- prefect/_internal/concurrency/calls.py +1 -2
- prefect/_internal/concurrency/cancellation.py +2 -4
- prefect/_internal/concurrency/threads.py +3 -3
- prefect/_internal/schemas/bases.py +3 -11
- prefect/_internal/schemas/validators.py +36 -60
- prefect/_result_records.py +235 -0
- prefect/_version.py +3 -3
- prefect/agent.py +1 -0
- prefect/automations.py +4 -8
- prefect/blocks/notifications.py +8 -8
- prefect/cache_policies.py +2 -0
- prefect/client/base.py +7 -8
- prefect/client/collections.py +3 -6
- prefect/client/orchestration/__init__.py +15 -263
- prefect/client/orchestration/_deployments/client.py +14 -6
- prefect/client/orchestration/_flow_runs/client.py +10 -6
- prefect/client/orchestration/_work_pools/__init__.py +0 -0
- prefect/client/orchestration/_work_pools/client.py +598 -0
- prefect/client/orchestration/base.py +9 -2
- prefect/client/schemas/actions.py +66 -2
- prefect/client/schemas/objects.py +22 -50
- prefect/client/schemas/schedules.py +7 -18
- prefect/client/types/flexible_schedule_list.py +2 -1
- prefect/context.py +2 -3
- prefect/deployments/flow_runs.py +1 -1
- prefect/deployments/runner.py +119 -43
- prefect/deployments/schedules.py +7 -1
- prefect/engine.py +4 -9
- prefect/events/schemas/automations.py +4 -2
- prefect/events/utilities.py +15 -13
- prefect/exceptions.py +1 -1
- prefect/flow_engine.py +8 -8
- prefect/flow_runs.py +4 -8
- prefect/flows.py +30 -22
- prefect/infrastructure/__init__.py +1 -0
- prefect/infrastructure/base.py +1 -0
- prefect/infrastructure/provisioners/__init__.py +3 -6
- prefect/infrastructure/provisioners/coiled.py +3 -3
- prefect/infrastructure/provisioners/container_instance.py +1 -0
- prefect/infrastructure/provisioners/ecs.py +6 -6
- prefect/infrastructure/provisioners/modal.py +3 -3
- prefect/input/run_input.py +5 -7
- prefect/locking/filesystem.py +4 -3
- prefect/main.py +1 -1
- prefect/results.py +42 -249
- prefect/runner/runner.py +9 -4
- prefect/runner/server.py +5 -5
- prefect/runner/storage.py +12 -10
- prefect/runner/submit.py +2 -4
- prefect/schedules.py +231 -0
- prefect/serializers.py +5 -5
- prefect/settings/__init__.py +2 -1
- prefect/settings/base.py +3 -3
- prefect/settings/models/root.py +4 -0
- prefect/settings/models/server/services.py +50 -9
- prefect/settings/sources.py +4 -4
- prefect/states.py +42 -11
- prefect/task_engine.py +10 -10
- prefect/task_runners.py +11 -22
- prefect/task_worker.py +9 -9
- prefect/tasks.py +22 -41
- prefect/telemetry/bootstrap.py +4 -6
- prefect/telemetry/services.py +2 -4
- prefect/types/__init__.py +2 -1
- prefect/types/_datetime.py +28 -1
- prefect/utilities/_engine.py +0 -1
- prefect/utilities/asyncutils.py +4 -8
- prefect/utilities/collections.py +13 -22
- prefect/utilities/dispatch.py +2 -4
- prefect/utilities/dockerutils.py +6 -6
- prefect/utilities/importtools.py +1 -68
- prefect/utilities/names.py +1 -1
- prefect/utilities/processutils.py +3 -6
- prefect/utilities/pydantic.py +4 -6
- prefect/utilities/schema_tools/hydration.py +6 -5
- prefect/utilities/templating.py +16 -10
- prefect/utilities/visualization.py +2 -4
- prefect/workers/base.py +3 -3
- prefect/workers/block.py +1 -0
- prefect/workers/cloud.py +1 -0
- prefect/workers/process.py +1 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/METADATA +1 -1
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/RECORD +89 -85
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,598 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import warnings
|
4
|
+
from datetime import datetime
|
5
|
+
from typing import TYPE_CHECKING, Any
|
6
|
+
|
7
|
+
from httpx import HTTPStatusError
|
8
|
+
|
9
|
+
from prefect.client.base import ServerType
|
10
|
+
from prefect.client.orchestration.base import BaseAsyncClient, BaseClient
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from uuid import UUID
|
14
|
+
|
15
|
+
from prefect.client.schemas.actions import (
|
16
|
+
WorkPoolCreate,
|
17
|
+
WorkPoolUpdate,
|
18
|
+
)
|
19
|
+
from prefect.client.schemas.filters import (
|
20
|
+
WorkerFilter,
|
21
|
+
WorkPoolFilter,
|
22
|
+
)
|
23
|
+
from prefect.client.schemas.objects import (
|
24
|
+
Worker,
|
25
|
+
WorkerMetadata,
|
26
|
+
WorkPool,
|
27
|
+
)
|
28
|
+
from prefect.client.schemas.responses import WorkerFlowRunResponse
|
29
|
+
|
30
|
+
from prefect.exceptions import ObjectAlreadyExists, ObjectNotFound
|
31
|
+
|
32
|
+
|
33
|
+
class WorkPoolClient(BaseClient):
|
34
|
+
def send_worker_heartbeat(
|
35
|
+
self,
|
36
|
+
work_pool_name: str,
|
37
|
+
worker_name: str,
|
38
|
+
heartbeat_interval_seconds: float | None = None,
|
39
|
+
get_worker_id: bool = False,
|
40
|
+
worker_metadata: "WorkerMetadata | None" = None,
|
41
|
+
) -> "UUID | None":
|
42
|
+
"""
|
43
|
+
Sends a worker heartbeat for a given work pool.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
work_pool_name: The name of the work pool to heartbeat against.
|
47
|
+
worker_name: The name of the worker sending the heartbeat.
|
48
|
+
return_id: Whether to return the worker ID. Note: will return `None` if the connected server does not support returning worker IDs, even if `return_id` is `True`.
|
49
|
+
worker_metadata: Metadata about the worker to send to the server.
|
50
|
+
"""
|
51
|
+
from uuid import UUID
|
52
|
+
|
53
|
+
params: dict[str, Any] = {
|
54
|
+
"name": worker_name,
|
55
|
+
"heartbeat_interval_seconds": heartbeat_interval_seconds,
|
56
|
+
}
|
57
|
+
if worker_metadata:
|
58
|
+
params["metadata"] = worker_metadata.model_dump(mode="json")
|
59
|
+
if get_worker_id:
|
60
|
+
params["return_id"] = get_worker_id
|
61
|
+
|
62
|
+
resp = self.request(
|
63
|
+
"POST",
|
64
|
+
"/work_pools/{work_pool_name}/workers/heartbeat",
|
65
|
+
path_params={"work_pool_name": work_pool_name},
|
66
|
+
json=params,
|
67
|
+
)
|
68
|
+
from prefect.settings import get_current_settings
|
69
|
+
|
70
|
+
if (
|
71
|
+
(
|
72
|
+
self.server_type == ServerType.CLOUD
|
73
|
+
or get_current_settings().testing.test_mode
|
74
|
+
)
|
75
|
+
and get_worker_id
|
76
|
+
and resp.status_code == 200
|
77
|
+
):
|
78
|
+
return UUID(resp.text)
|
79
|
+
else:
|
80
|
+
return None
|
81
|
+
|
82
|
+
def read_workers_for_work_pool(
|
83
|
+
self,
|
84
|
+
work_pool_name: str,
|
85
|
+
worker_filter: "WorkerFilter | None" = None,
|
86
|
+
offset: int | None = None,
|
87
|
+
limit: int | None = None,
|
88
|
+
) -> list["Worker"]:
|
89
|
+
"""
|
90
|
+
Reads workers for a given work pool.
|
91
|
+
|
92
|
+
Args:
|
93
|
+
work_pool_name: The name of the work pool for which to get
|
94
|
+
member workers.
|
95
|
+
worker_filter: Criteria by which to filter workers.
|
96
|
+
limit: Limit for the worker query.
|
97
|
+
offset: Limit for the worker query.
|
98
|
+
"""
|
99
|
+
from prefect.client.schemas.objects import Worker
|
100
|
+
|
101
|
+
response = self.request(
|
102
|
+
"POST",
|
103
|
+
"/work_pools/{work_pool_name}/workers/filter",
|
104
|
+
path_params={"work_pool_name": work_pool_name},
|
105
|
+
json={
|
106
|
+
"workers": (
|
107
|
+
worker_filter.model_dump(mode="json", exclude_unset=True)
|
108
|
+
if worker_filter
|
109
|
+
else None
|
110
|
+
),
|
111
|
+
"offset": offset,
|
112
|
+
"limit": limit,
|
113
|
+
},
|
114
|
+
)
|
115
|
+
|
116
|
+
return Worker.model_validate_list(response.json())
|
117
|
+
|
118
|
+
def read_work_pool(self, work_pool_name: str) -> "WorkPool":
|
119
|
+
"""
|
120
|
+
Reads information for a given work pool
|
121
|
+
|
122
|
+
Args:
|
123
|
+
work_pool_name: The name of the work pool to for which to get
|
124
|
+
information.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
Information about the requested work pool.
|
128
|
+
"""
|
129
|
+
from prefect.client.schemas.objects import WorkPool
|
130
|
+
|
131
|
+
try:
|
132
|
+
response = self.request(
|
133
|
+
"GET",
|
134
|
+
"/work_pools/{name}",
|
135
|
+
path_params={"name": work_pool_name},
|
136
|
+
)
|
137
|
+
return WorkPool.model_validate(response.json())
|
138
|
+
except HTTPStatusError as e:
|
139
|
+
if e.response.status_code == 404:
|
140
|
+
raise ObjectNotFound(http_exc=e) from e
|
141
|
+
else:
|
142
|
+
raise
|
143
|
+
|
144
|
+
def read_work_pools(
|
145
|
+
self,
|
146
|
+
limit: int | None = None,
|
147
|
+
offset: int = 0,
|
148
|
+
work_pool_filter: "WorkPoolFilter | None" = None,
|
149
|
+
) -> list["WorkPool"]:
|
150
|
+
"""
|
151
|
+
Reads work pools.
|
152
|
+
|
153
|
+
Args:
|
154
|
+
limit: Limit for the work pool query.
|
155
|
+
offset: Offset for the work pool query.
|
156
|
+
work_pool_filter: Criteria by which to filter work pools.
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
A list of work pools.
|
160
|
+
"""
|
161
|
+
from prefect.client.schemas.objects import WorkPool
|
162
|
+
|
163
|
+
body: dict[str, Any] = {
|
164
|
+
"limit": limit,
|
165
|
+
"offset": offset,
|
166
|
+
"work_pools": (
|
167
|
+
work_pool_filter.model_dump(mode="json") if work_pool_filter else None
|
168
|
+
),
|
169
|
+
}
|
170
|
+
response = self.request("POST", "/work_pools/filter", json=body)
|
171
|
+
return WorkPool.model_validate_list(response.json())
|
172
|
+
|
173
|
+
def create_work_pool(
|
174
|
+
self,
|
175
|
+
work_pool: "WorkPoolCreate",
|
176
|
+
overwrite: bool = False,
|
177
|
+
) -> "WorkPool":
|
178
|
+
"""
|
179
|
+
Creates a work pool with the provided configuration.
|
180
|
+
|
181
|
+
Args:
|
182
|
+
work_pool: Desired configuration for the new work pool.
|
183
|
+
|
184
|
+
Returns:
|
185
|
+
Information about the newly created work pool.
|
186
|
+
"""
|
187
|
+
from prefect.client.schemas.actions import WorkPoolUpdate
|
188
|
+
from prefect.client.schemas.objects import WorkPool
|
189
|
+
|
190
|
+
try:
|
191
|
+
response = self.request(
|
192
|
+
"POST",
|
193
|
+
"/work_pools/",
|
194
|
+
json=work_pool.model_dump(mode="json", exclude_unset=True),
|
195
|
+
)
|
196
|
+
except HTTPStatusError as e:
|
197
|
+
if e.response.status_code == 409:
|
198
|
+
if overwrite:
|
199
|
+
existing_work_pool = self.read_work_pool(
|
200
|
+
work_pool_name=work_pool.name
|
201
|
+
)
|
202
|
+
if existing_work_pool.type != work_pool.type:
|
203
|
+
warnings.warn(
|
204
|
+
"Overwriting work pool type is not supported. Ignoring provided type.",
|
205
|
+
category=UserWarning,
|
206
|
+
)
|
207
|
+
self.update_work_pool(
|
208
|
+
work_pool_name=work_pool.name,
|
209
|
+
work_pool=WorkPoolUpdate.model_validate(
|
210
|
+
work_pool.model_dump(exclude={"name", "type"})
|
211
|
+
),
|
212
|
+
)
|
213
|
+
response = self.request(
|
214
|
+
"GET",
|
215
|
+
"/work_pools/{name}",
|
216
|
+
path_params={"name": work_pool.name},
|
217
|
+
)
|
218
|
+
else:
|
219
|
+
raise ObjectAlreadyExists(http_exc=e) from e
|
220
|
+
else:
|
221
|
+
raise
|
222
|
+
|
223
|
+
return WorkPool.model_validate(response.json())
|
224
|
+
|
225
|
+
def update_work_pool(
|
226
|
+
self,
|
227
|
+
work_pool_name: str,
|
228
|
+
work_pool: "WorkPoolUpdate",
|
229
|
+
) -> None:
|
230
|
+
"""
|
231
|
+
Updates a work pool.
|
232
|
+
|
233
|
+
Args:
|
234
|
+
work_pool_name: Name of the work pool to update.
|
235
|
+
work_pool: Fields to update in the work pool.
|
236
|
+
"""
|
237
|
+
try:
|
238
|
+
self.request(
|
239
|
+
"PATCH",
|
240
|
+
"/work_pools/{name}",
|
241
|
+
path_params={"name": work_pool_name},
|
242
|
+
json=work_pool.model_dump(mode="json", exclude_unset=True),
|
243
|
+
)
|
244
|
+
except HTTPStatusError as e:
|
245
|
+
if e.response.status_code == 404:
|
246
|
+
raise ObjectNotFound(http_exc=e) from e
|
247
|
+
else:
|
248
|
+
raise
|
249
|
+
|
250
|
+
def delete_work_pool(
|
251
|
+
self,
|
252
|
+
work_pool_name: str,
|
253
|
+
) -> None:
|
254
|
+
"""
|
255
|
+
Deletes a work pool.
|
256
|
+
|
257
|
+
Args:
|
258
|
+
work_pool_name: Name of the work pool to delete.
|
259
|
+
"""
|
260
|
+
try:
|
261
|
+
self.request(
|
262
|
+
"DELETE",
|
263
|
+
"/work_pools/{name}",
|
264
|
+
path_params={"name": work_pool_name},
|
265
|
+
)
|
266
|
+
except HTTPStatusError as e:
|
267
|
+
if e.response.status_code == 404:
|
268
|
+
raise ObjectNotFound(http_exc=e) from e
|
269
|
+
else:
|
270
|
+
raise
|
271
|
+
|
272
|
+
def get_scheduled_flow_runs_for_work_pool(
|
273
|
+
self,
|
274
|
+
work_pool_name: str,
|
275
|
+
work_queue_names: list[str] | None = None,
|
276
|
+
scheduled_before: datetime | None = None,
|
277
|
+
) -> list["WorkerFlowRunResponse"]:
|
278
|
+
"""
|
279
|
+
Retrieves scheduled flow runs for the provided set of work pool queues.
|
280
|
+
|
281
|
+
Args:
|
282
|
+
work_pool_name: The name of the work pool that the work pool
|
283
|
+
queues are associated with.
|
284
|
+
work_queue_names: The names of the work pool queues from which
|
285
|
+
to get scheduled flow runs.
|
286
|
+
scheduled_before: Datetime used to filter returned flow runs. Flow runs
|
287
|
+
scheduled for after the given datetime string will not be returned.
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
A list of worker flow run responses containing information about the
|
291
|
+
retrieved flow runs.
|
292
|
+
"""
|
293
|
+
from prefect.client.schemas.responses import WorkerFlowRunResponse
|
294
|
+
|
295
|
+
body: dict[str, Any] = {}
|
296
|
+
if work_queue_names is not None:
|
297
|
+
body["work_queue_names"] = list(work_queue_names)
|
298
|
+
if scheduled_before:
|
299
|
+
body["scheduled_before"] = str(scheduled_before)
|
300
|
+
|
301
|
+
try:
|
302
|
+
response = self.request(
|
303
|
+
"POST",
|
304
|
+
"/work_pools/{name}/get_scheduled_flow_runs",
|
305
|
+
path_params={"name": work_pool_name},
|
306
|
+
json=body,
|
307
|
+
)
|
308
|
+
except HTTPStatusError as e:
|
309
|
+
if e.response.status_code == 404:
|
310
|
+
raise ObjectNotFound(http_exc=e) from e
|
311
|
+
else:
|
312
|
+
raise
|
313
|
+
|
314
|
+
return WorkerFlowRunResponse.model_validate_list(response.json())
|
315
|
+
|
316
|
+
|
317
|
+
class WorkPoolAsyncClient(BaseAsyncClient):
|
318
|
+
async def send_worker_heartbeat(
|
319
|
+
self,
|
320
|
+
work_pool_name: str,
|
321
|
+
worker_name: str,
|
322
|
+
heartbeat_interval_seconds: float | None = None,
|
323
|
+
get_worker_id: bool = False,
|
324
|
+
worker_metadata: "WorkerMetadata | None" = None,
|
325
|
+
) -> "UUID | None":
|
326
|
+
"""
|
327
|
+
Sends a worker heartbeat for a given work pool.
|
328
|
+
|
329
|
+
Args:
|
330
|
+
work_pool_name: The name of the work pool to heartbeat against.
|
331
|
+
worker_name: The name of the worker sending the heartbeat.
|
332
|
+
return_id: Whether to return the worker ID. Note: will return `None` if the connected server does not support returning worker IDs, even if `return_id` is `True`.
|
333
|
+
worker_metadata: Metadata about the worker to send to the server.
|
334
|
+
"""
|
335
|
+
from uuid import UUID
|
336
|
+
|
337
|
+
params: dict[str, Any] = {
|
338
|
+
"name": worker_name,
|
339
|
+
"heartbeat_interval_seconds": heartbeat_interval_seconds,
|
340
|
+
}
|
341
|
+
if worker_metadata:
|
342
|
+
params["metadata"] = worker_metadata.model_dump(mode="json")
|
343
|
+
if get_worker_id:
|
344
|
+
params["return_id"] = get_worker_id
|
345
|
+
|
346
|
+
resp = await self.request(
|
347
|
+
"POST",
|
348
|
+
"/work_pools/{work_pool_name}/workers/heartbeat",
|
349
|
+
path_params={"work_pool_name": work_pool_name},
|
350
|
+
json=params,
|
351
|
+
)
|
352
|
+
from prefect.settings import get_current_settings
|
353
|
+
|
354
|
+
if (
|
355
|
+
(
|
356
|
+
self.server_type == ServerType.CLOUD
|
357
|
+
or get_current_settings().testing.test_mode
|
358
|
+
)
|
359
|
+
and get_worker_id
|
360
|
+
and resp.status_code == 200
|
361
|
+
):
|
362
|
+
return UUID(resp.text)
|
363
|
+
else:
|
364
|
+
return None
|
365
|
+
|
366
|
+
async def read_workers_for_work_pool(
|
367
|
+
self,
|
368
|
+
work_pool_name: str,
|
369
|
+
worker_filter: "WorkerFilter | None" = None,
|
370
|
+
offset: int | None = None,
|
371
|
+
limit: int | None = None,
|
372
|
+
) -> list["Worker"]:
|
373
|
+
"""
|
374
|
+
Reads workers for a given work pool.
|
375
|
+
|
376
|
+
Args:
|
377
|
+
work_pool_name: The name of the work pool for which to get
|
378
|
+
member workers.
|
379
|
+
worker_filter: Criteria by which to filter workers.
|
380
|
+
limit: Limit for the worker query.
|
381
|
+
offset: Limit for the worker query.
|
382
|
+
"""
|
383
|
+
from prefect.client.schemas.objects import Worker
|
384
|
+
|
385
|
+
response = await self.request(
|
386
|
+
"POST",
|
387
|
+
"/work_pools/{work_pool_name}/workers/filter",
|
388
|
+
path_params={"work_pool_name": work_pool_name},
|
389
|
+
json={
|
390
|
+
"workers": (
|
391
|
+
worker_filter.model_dump(mode="json", exclude_unset=True)
|
392
|
+
if worker_filter
|
393
|
+
else None
|
394
|
+
),
|
395
|
+
"offset": offset,
|
396
|
+
"limit": limit,
|
397
|
+
},
|
398
|
+
)
|
399
|
+
|
400
|
+
return Worker.model_validate_list(response.json())
|
401
|
+
|
402
|
+
async def read_work_pool(self, work_pool_name: str) -> "WorkPool":
|
403
|
+
"""
|
404
|
+
Reads information for a given work pool
|
405
|
+
|
406
|
+
Args:
|
407
|
+
work_pool_name: The name of the work pool to for which to get
|
408
|
+
information.
|
409
|
+
|
410
|
+
Returns:
|
411
|
+
Information about the requested work pool.
|
412
|
+
"""
|
413
|
+
from prefect.client.schemas.objects import WorkPool
|
414
|
+
|
415
|
+
try:
|
416
|
+
response = await self.request(
|
417
|
+
"GET",
|
418
|
+
"/work_pools/{name}",
|
419
|
+
path_params={"name": work_pool_name},
|
420
|
+
)
|
421
|
+
return WorkPool.model_validate(response.json())
|
422
|
+
except HTTPStatusError as e:
|
423
|
+
if e.response.status_code == 404:
|
424
|
+
raise ObjectNotFound(http_exc=e) from e
|
425
|
+
else:
|
426
|
+
raise
|
427
|
+
|
428
|
+
async def read_work_pools(
|
429
|
+
self,
|
430
|
+
limit: int | None = None,
|
431
|
+
offset: int = 0,
|
432
|
+
work_pool_filter: "WorkPoolFilter | None" = None,
|
433
|
+
) -> list["WorkPool"]:
|
434
|
+
"""
|
435
|
+
Reads work pools.
|
436
|
+
|
437
|
+
Args:
|
438
|
+
limit: Limit for the work pool query.
|
439
|
+
offset: Offset for the work pool query.
|
440
|
+
work_pool_filter: Criteria by which to filter work pools.
|
441
|
+
|
442
|
+
Returns:
|
443
|
+
A list of work pools.
|
444
|
+
"""
|
445
|
+
from prefect.client.schemas.objects import WorkPool
|
446
|
+
|
447
|
+
body: dict[str, Any] = {
|
448
|
+
"limit": limit,
|
449
|
+
"offset": offset,
|
450
|
+
"work_pools": (
|
451
|
+
work_pool_filter.model_dump(mode="json") if work_pool_filter else None
|
452
|
+
),
|
453
|
+
}
|
454
|
+
response = await self.request("POST", "/work_pools/filter", json=body)
|
455
|
+
return WorkPool.model_validate_list(response.json())
|
456
|
+
|
457
|
+
async def create_work_pool(
|
458
|
+
self,
|
459
|
+
work_pool: "WorkPoolCreate",
|
460
|
+
overwrite: bool = False,
|
461
|
+
) -> "WorkPool":
|
462
|
+
"""
|
463
|
+
Creates a work pool with the provided configuration.
|
464
|
+
|
465
|
+
Args:
|
466
|
+
work_pool: Desired configuration for the new work pool.
|
467
|
+
|
468
|
+
Returns:
|
469
|
+
Information about the newly created work pool.
|
470
|
+
"""
|
471
|
+
from prefect.client.schemas.actions import WorkPoolUpdate
|
472
|
+
from prefect.client.schemas.objects import WorkPool
|
473
|
+
|
474
|
+
try:
|
475
|
+
response = await self.request(
|
476
|
+
"POST",
|
477
|
+
"/work_pools/",
|
478
|
+
json=work_pool.model_dump(mode="json", exclude_unset=True),
|
479
|
+
)
|
480
|
+
except HTTPStatusError as e:
|
481
|
+
if e.response.status_code == 409:
|
482
|
+
if overwrite:
|
483
|
+
existing_work_pool = await self.read_work_pool(
|
484
|
+
work_pool_name=work_pool.name
|
485
|
+
)
|
486
|
+
if existing_work_pool.type != work_pool.type:
|
487
|
+
warnings.warn(
|
488
|
+
"Overwriting work pool type is not supported. Ignoring provided type.",
|
489
|
+
category=UserWarning,
|
490
|
+
)
|
491
|
+
await self.update_work_pool(
|
492
|
+
work_pool_name=work_pool.name,
|
493
|
+
work_pool=WorkPoolUpdate.model_validate(
|
494
|
+
work_pool.model_dump(exclude={"name", "type"})
|
495
|
+
),
|
496
|
+
)
|
497
|
+
response = await self.request(
|
498
|
+
"GET",
|
499
|
+
"/work_pools/{name}",
|
500
|
+
path_params={"name": work_pool.name},
|
501
|
+
)
|
502
|
+
else:
|
503
|
+
raise ObjectAlreadyExists(http_exc=e) from e
|
504
|
+
else:
|
505
|
+
raise
|
506
|
+
|
507
|
+
return WorkPool.model_validate(response.json())
|
508
|
+
|
509
|
+
async def update_work_pool(
|
510
|
+
self,
|
511
|
+
work_pool_name: str,
|
512
|
+
work_pool: "WorkPoolUpdate",
|
513
|
+
) -> None:
|
514
|
+
"""
|
515
|
+
Updates a work pool.
|
516
|
+
|
517
|
+
Args:
|
518
|
+
work_pool_name: Name of the work pool to update.
|
519
|
+
work_pool: Fields to update in the work pool.
|
520
|
+
"""
|
521
|
+
try:
|
522
|
+
await self.request(
|
523
|
+
"PATCH",
|
524
|
+
"/work_pools/{name}",
|
525
|
+
path_params={"name": work_pool_name},
|
526
|
+
json=work_pool.model_dump(mode="json", exclude_unset=True),
|
527
|
+
)
|
528
|
+
except HTTPStatusError as e:
|
529
|
+
if e.response.status_code == 404:
|
530
|
+
raise ObjectNotFound(http_exc=e) from e
|
531
|
+
else:
|
532
|
+
raise
|
533
|
+
|
534
|
+
async def delete_work_pool(
|
535
|
+
self,
|
536
|
+
work_pool_name: str,
|
537
|
+
) -> None:
|
538
|
+
"""
|
539
|
+
Deletes a work pool.
|
540
|
+
|
541
|
+
Args:
|
542
|
+
work_pool_name: Name of the work pool to delete.
|
543
|
+
"""
|
544
|
+
try:
|
545
|
+
await self.request(
|
546
|
+
"DELETE",
|
547
|
+
"/work_pools/{name}",
|
548
|
+
path_params={"name": work_pool_name},
|
549
|
+
)
|
550
|
+
except HTTPStatusError as e:
|
551
|
+
if e.response.status_code == 404:
|
552
|
+
raise ObjectNotFound(http_exc=e) from e
|
553
|
+
else:
|
554
|
+
raise
|
555
|
+
|
556
|
+
async def get_scheduled_flow_runs_for_work_pool(
|
557
|
+
self,
|
558
|
+
work_pool_name: str,
|
559
|
+
work_queue_names: list[str] | None = None,
|
560
|
+
scheduled_before: datetime | None = None,
|
561
|
+
) -> list["WorkerFlowRunResponse"]:
|
562
|
+
"""
|
563
|
+
Retrieves scheduled flow runs for the provided set of work pool queues.
|
564
|
+
|
565
|
+
Args:
|
566
|
+
work_pool_name: The name of the work pool that the work pool
|
567
|
+
queues are associated with.
|
568
|
+
work_queue_names: The names of the work pool queues from which
|
569
|
+
to get scheduled flow runs.
|
570
|
+
scheduled_before: Datetime used to filter returned flow runs. Flow runs
|
571
|
+
scheduled for after the given datetime string will not be returned.
|
572
|
+
|
573
|
+
Returns:
|
574
|
+
A list of worker flow run responses containing information about the
|
575
|
+
retrieved flow runs.
|
576
|
+
"""
|
577
|
+
from prefect.client.schemas.responses import WorkerFlowRunResponse
|
578
|
+
|
579
|
+
body: dict[str, Any] = {}
|
580
|
+
if work_queue_names is not None:
|
581
|
+
body["work_queue_names"] = list(work_queue_names)
|
582
|
+
if scheduled_before:
|
583
|
+
body["scheduled_before"] = str(scheduled_before)
|
584
|
+
|
585
|
+
try:
|
586
|
+
response = await self.request(
|
587
|
+
"POST",
|
588
|
+
"/work_pools/{name}/get_scheduled_flow_runs",
|
589
|
+
path_params={"name": work_pool_name},
|
590
|
+
json=body,
|
591
|
+
)
|
592
|
+
except HTTPStatusError as e:
|
593
|
+
if e.response.status_code == 404:
|
594
|
+
raise ObjectNotFound(http_exc=e) from e
|
595
|
+
else:
|
596
|
+
raise
|
597
|
+
|
598
|
+
return WorkerFlowRunResponse.model_validate_list(response.json())
|
@@ -7,12 +7,15 @@ from typing_extensions import TypeAlias
|
|
7
7
|
if TYPE_CHECKING:
|
8
8
|
from httpx import AsyncClient, Client, Response
|
9
9
|
|
10
|
+
from prefect.client.base import ServerType
|
10
11
|
from prefect.client.orchestration.routes import ServerRoutes
|
11
12
|
|
12
13
|
HTTP_METHODS: TypeAlias = Literal["GET", "POST", "PUT", "DELETE", "PATCH"]
|
13
14
|
|
14
15
|
|
15
16
|
class BaseClient:
|
17
|
+
server_type: "ServerType"
|
18
|
+
|
16
19
|
def __init__(self, client: "Client"):
|
17
20
|
self._client = client
|
18
21
|
|
@@ -26,10 +29,13 @@ class BaseClient:
|
|
26
29
|
) -> "Response":
|
27
30
|
if path_params:
|
28
31
|
path = path.format(**path_params) # type: ignore
|
29
|
-
|
32
|
+
request = self._client.build_request(method, path, params=params, **kwargs)
|
33
|
+
return self._client.send(request)
|
30
34
|
|
31
35
|
|
32
36
|
class BaseAsyncClient:
|
37
|
+
server_type: "ServerType"
|
38
|
+
|
33
39
|
def __init__(self, client: "AsyncClient"):
|
34
40
|
self._client = client
|
35
41
|
|
@@ -43,4 +49,5 @@ class BaseAsyncClient:
|
|
43
49
|
) -> "Response":
|
44
50
|
if path_params:
|
45
51
|
path = path.format(**path_params) # type: ignore
|
46
|
-
|
52
|
+
request = self._client.build_request(method, path, params=params, **kwargs)
|
53
|
+
return await self._client.send(request)
|