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.
Files changed (89) hide show
  1. prefect/_experimental/sla/objects.py +29 -1
  2. prefect/_internal/compatibility/deprecated.py +4 -4
  3. prefect/_internal/compatibility/migration.py +1 -1
  4. prefect/_internal/concurrency/calls.py +1 -2
  5. prefect/_internal/concurrency/cancellation.py +2 -4
  6. prefect/_internal/concurrency/threads.py +3 -3
  7. prefect/_internal/schemas/bases.py +3 -11
  8. prefect/_internal/schemas/validators.py +36 -60
  9. prefect/_result_records.py +235 -0
  10. prefect/_version.py +3 -3
  11. prefect/agent.py +1 -0
  12. prefect/automations.py +4 -8
  13. prefect/blocks/notifications.py +8 -8
  14. prefect/cache_policies.py +2 -0
  15. prefect/client/base.py +7 -8
  16. prefect/client/collections.py +3 -6
  17. prefect/client/orchestration/__init__.py +15 -263
  18. prefect/client/orchestration/_deployments/client.py +14 -6
  19. prefect/client/orchestration/_flow_runs/client.py +10 -6
  20. prefect/client/orchestration/_work_pools/__init__.py +0 -0
  21. prefect/client/orchestration/_work_pools/client.py +598 -0
  22. prefect/client/orchestration/base.py +9 -2
  23. prefect/client/schemas/actions.py +66 -2
  24. prefect/client/schemas/objects.py +22 -50
  25. prefect/client/schemas/schedules.py +7 -18
  26. prefect/client/types/flexible_schedule_list.py +2 -1
  27. prefect/context.py +2 -3
  28. prefect/deployments/flow_runs.py +1 -1
  29. prefect/deployments/runner.py +119 -43
  30. prefect/deployments/schedules.py +7 -1
  31. prefect/engine.py +4 -9
  32. prefect/events/schemas/automations.py +4 -2
  33. prefect/events/utilities.py +15 -13
  34. prefect/exceptions.py +1 -1
  35. prefect/flow_engine.py +8 -8
  36. prefect/flow_runs.py +4 -8
  37. prefect/flows.py +30 -22
  38. prefect/infrastructure/__init__.py +1 -0
  39. prefect/infrastructure/base.py +1 -0
  40. prefect/infrastructure/provisioners/__init__.py +3 -6
  41. prefect/infrastructure/provisioners/coiled.py +3 -3
  42. prefect/infrastructure/provisioners/container_instance.py +1 -0
  43. prefect/infrastructure/provisioners/ecs.py +6 -6
  44. prefect/infrastructure/provisioners/modal.py +3 -3
  45. prefect/input/run_input.py +5 -7
  46. prefect/locking/filesystem.py +4 -3
  47. prefect/main.py +1 -1
  48. prefect/results.py +42 -249
  49. prefect/runner/runner.py +9 -4
  50. prefect/runner/server.py +5 -5
  51. prefect/runner/storage.py +12 -10
  52. prefect/runner/submit.py +2 -4
  53. prefect/schedules.py +231 -0
  54. prefect/serializers.py +5 -5
  55. prefect/settings/__init__.py +2 -1
  56. prefect/settings/base.py +3 -3
  57. prefect/settings/models/root.py +4 -0
  58. prefect/settings/models/server/services.py +50 -9
  59. prefect/settings/sources.py +4 -4
  60. prefect/states.py +42 -11
  61. prefect/task_engine.py +10 -10
  62. prefect/task_runners.py +11 -22
  63. prefect/task_worker.py +9 -9
  64. prefect/tasks.py +22 -41
  65. prefect/telemetry/bootstrap.py +4 -6
  66. prefect/telemetry/services.py +2 -4
  67. prefect/types/__init__.py +2 -1
  68. prefect/types/_datetime.py +28 -1
  69. prefect/utilities/_engine.py +0 -1
  70. prefect/utilities/asyncutils.py +4 -8
  71. prefect/utilities/collections.py +13 -22
  72. prefect/utilities/dispatch.py +2 -4
  73. prefect/utilities/dockerutils.py +6 -6
  74. prefect/utilities/importtools.py +1 -68
  75. prefect/utilities/names.py +1 -1
  76. prefect/utilities/processutils.py +3 -6
  77. prefect/utilities/pydantic.py +4 -6
  78. prefect/utilities/schema_tools/hydration.py +6 -5
  79. prefect/utilities/templating.py +16 -10
  80. prefect/utilities/visualization.py +2 -4
  81. prefect/workers/base.py +3 -3
  82. prefect/workers/block.py +1 -0
  83. prefect/workers/cloud.py +1 -0
  84. prefect/workers/process.py +1 -0
  85. {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/METADATA +1 -1
  86. {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/RECORD +89 -85
  87. {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/LICENSE +0 -0
  88. {prefect_client-3.1.15.dist-info → prefect_client-3.2.0.dist-info}/WHEEL +0 -0
  89. {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
- return self._client.request(method, path, params=params, **kwargs)
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
- return await self._client.request(method, path, params=params, **kwargs)
52
+ request = self._client.build_request(method, path, params=params, **kwargs)
53
+ return await self._client.send(request)