prefect-client 3.1.11__py3-none-any.whl → 3.1.13__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 (133) hide show
  1. prefect/_experimental/sla/__init__.py +0 -0
  2. prefect/_experimental/sla/client.py +92 -0
  3. prefect/_experimental/sla/objects.py +61 -0
  4. prefect/_internal/concurrency/services.py +2 -2
  5. prefect/_internal/concurrency/threads.py +6 -0
  6. prefect/_internal/retries.py +6 -3
  7. prefect/_internal/schemas/validators.py +6 -4
  8. prefect/_version.py +3 -3
  9. prefect/artifacts.py +4 -1
  10. prefect/automations.py +236 -30
  11. prefect/blocks/__init__.py +3 -3
  12. prefect/blocks/abstract.py +57 -31
  13. prefect/blocks/core.py +181 -82
  14. prefect/blocks/notifications.py +134 -73
  15. prefect/blocks/redis.py +13 -9
  16. prefect/blocks/system.py +24 -11
  17. prefect/blocks/webhook.py +7 -5
  18. prefect/cache_policies.py +23 -22
  19. prefect/client/orchestration/__init__.py +103 -2006
  20. prefect/client/orchestration/_automations/__init__.py +0 -0
  21. prefect/client/orchestration/_automations/client.py +329 -0
  22. prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
  23. prefect/client/orchestration/_blocks_documents/client.py +334 -0
  24. prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
  25. prefect/client/orchestration/_blocks_schemas/client.py +200 -0
  26. prefect/client/orchestration/_blocks_types/__init__.py +0 -0
  27. prefect/client/orchestration/_blocks_types/client.py +380 -0
  28. prefect/client/orchestration/_deployments/__init__.py +0 -0
  29. prefect/client/orchestration/_deployments/client.py +1128 -0
  30. prefect/client/orchestration/_flow_runs/__init__.py +0 -0
  31. prefect/client/orchestration/_flow_runs/client.py +903 -0
  32. prefect/client/orchestration/_flows/__init__.py +0 -0
  33. prefect/client/orchestration/_flows/client.py +343 -0
  34. prefect/client/orchestration/_logs/client.py +16 -14
  35. prefect/client/schemas/__init__.py +68 -28
  36. prefect/client/schemas/objects.py +5 -5
  37. prefect/client/utilities.py +3 -3
  38. prefect/context.py +15 -1
  39. prefect/deployments/base.py +13 -4
  40. prefect/deployments/flow_runs.py +5 -1
  41. prefect/deployments/runner.py +37 -1
  42. prefect/deployments/steps/core.py +1 -1
  43. prefect/deployments/steps/pull.py +8 -3
  44. prefect/deployments/steps/utility.py +2 -2
  45. prefect/docker/docker_image.py +13 -9
  46. prefect/engine.py +33 -11
  47. prefect/events/cli/automations.py +4 -4
  48. prefect/events/clients.py +17 -14
  49. prefect/events/schemas/automations.py +12 -8
  50. prefect/events/schemas/events.py +5 -1
  51. prefect/events/worker.py +1 -1
  52. prefect/filesystems.py +7 -3
  53. prefect/flow_engine.py +64 -47
  54. prefect/flows.py +128 -74
  55. prefect/futures.py +14 -7
  56. prefect/infrastructure/provisioners/__init__.py +2 -0
  57. prefect/infrastructure/provisioners/cloud_run.py +4 -4
  58. prefect/infrastructure/provisioners/coiled.py +249 -0
  59. prefect/infrastructure/provisioners/container_instance.py +4 -3
  60. prefect/infrastructure/provisioners/ecs.py +55 -43
  61. prefect/infrastructure/provisioners/modal.py +5 -4
  62. prefect/input/actions.py +5 -1
  63. prefect/input/run_input.py +157 -43
  64. prefect/logging/configuration.py +3 -3
  65. prefect/logging/filters.py +2 -2
  66. prefect/logging/formatters.py +15 -11
  67. prefect/logging/handlers.py +24 -14
  68. prefect/logging/highlighters.py +5 -5
  69. prefect/logging/loggers.py +28 -18
  70. prefect/logging/logging.yml +1 -1
  71. prefect/main.py +3 -1
  72. prefect/results.py +166 -86
  73. prefect/runner/runner.py +38 -29
  74. prefect/runner/server.py +3 -1
  75. prefect/runner/storage.py +18 -18
  76. prefect/runner/submit.py +19 -12
  77. prefect/runtime/deployment.py +15 -8
  78. prefect/runtime/flow_run.py +19 -6
  79. prefect/runtime/task_run.py +7 -3
  80. prefect/settings/base.py +17 -7
  81. prefect/settings/legacy.py +4 -4
  82. prefect/settings/models/api.py +4 -3
  83. prefect/settings/models/cli.py +4 -3
  84. prefect/settings/models/client.py +7 -4
  85. prefect/settings/models/cloud.py +9 -3
  86. prefect/settings/models/deployments.py +4 -3
  87. prefect/settings/models/experiments.py +4 -8
  88. prefect/settings/models/flows.py +4 -3
  89. prefect/settings/models/internal.py +4 -3
  90. prefect/settings/models/logging.py +8 -6
  91. prefect/settings/models/results.py +4 -3
  92. prefect/settings/models/root.py +11 -16
  93. prefect/settings/models/runner.py +8 -5
  94. prefect/settings/models/server/api.py +6 -3
  95. prefect/settings/models/server/database.py +120 -25
  96. prefect/settings/models/server/deployments.py +4 -3
  97. prefect/settings/models/server/ephemeral.py +7 -4
  98. prefect/settings/models/server/events.py +6 -3
  99. prefect/settings/models/server/flow_run_graph.py +4 -3
  100. prefect/settings/models/server/root.py +4 -3
  101. prefect/settings/models/server/services.py +15 -12
  102. prefect/settings/models/server/tasks.py +7 -4
  103. prefect/settings/models/server/ui.py +4 -3
  104. prefect/settings/models/tasks.py +10 -5
  105. prefect/settings/models/testing.py +4 -3
  106. prefect/settings/models/worker.py +7 -4
  107. prefect/settings/profiles.py +13 -12
  108. prefect/settings/sources.py +20 -19
  109. prefect/states.py +74 -51
  110. prefect/task_engine.py +43 -33
  111. prefect/task_runners.py +85 -72
  112. prefect/task_runs.py +20 -11
  113. prefect/task_worker.py +14 -9
  114. prefect/tasks.py +36 -28
  115. prefect/telemetry/bootstrap.py +13 -9
  116. prefect/telemetry/run_telemetry.py +15 -13
  117. prefect/telemetry/services.py +4 -0
  118. prefect/transactions.py +3 -3
  119. prefect/types/__init__.py +3 -1
  120. prefect/utilities/_deprecated.py +38 -0
  121. prefect/utilities/engine.py +11 -4
  122. prefect/utilities/filesystem.py +2 -2
  123. prefect/utilities/generics.py +1 -1
  124. prefect/utilities/pydantic.py +21 -36
  125. prefect/utilities/templating.py +25 -1
  126. prefect/workers/base.py +58 -33
  127. prefect/workers/process.py +20 -15
  128. prefect/workers/server.py +4 -5
  129. {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/METADATA +3 -3
  130. {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/RECORD +133 -114
  131. {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/LICENSE +0 -0
  132. {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/WHEEL +0 -0
  133. {prefect_client-3.1.11.dist-info → prefect_client-3.1.13.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ from collections.abc import Iterable
7
7
  from contextlib import AsyncExitStack
8
8
  from logging import Logger
9
9
  from typing import TYPE_CHECKING, Any, Literal, NoReturn, Optional, Union, overload
10
- from uuid import UUID, uuid4
10
+ from uuid import UUID
11
11
 
12
12
  import certifi
13
13
  import httpcore
@@ -40,31 +40,49 @@ from prefect.client.orchestration._variables.client import (
40
40
  VariableAsyncClient,
41
41
  )
42
42
 
43
+ from prefect.client.orchestration._deployments.client import (
44
+ DeploymentClient,
45
+ DeploymentAsyncClient,
46
+ )
47
+ from prefect.client.orchestration._automations.client import (
48
+ AutomationClient,
49
+ AutomationAsyncClient,
50
+ )
51
+ from prefect._experimental.sla.client import SlaClient, SlaAsyncClient
52
+
53
+ from prefect.client.orchestration._flows.client import (
54
+ FlowClient,
55
+ FlowAsyncClient,
56
+ )
57
+ from prefect.client.orchestration._flow_runs.client import (
58
+ FlowRunClient,
59
+ FlowRunAsyncClient,
60
+ )
61
+
62
+ from prefect.client.orchestration._blocks_documents.client import (
63
+ BlocksDocumentClient,
64
+ BlocksDocumentAsyncClient,
65
+ )
66
+
67
+ from prefect.client.orchestration._blocks_schemas.client import (
68
+ BlocksSchemaClient,
69
+ BlocksSchemaAsyncClient,
70
+ )
71
+
72
+ from prefect.client.orchestration._blocks_types.client import (
73
+ BlocksTypeClient,
74
+ BlocksTypeAsyncClient,
75
+ )
76
+
43
77
  import prefect
44
78
  import prefect.exceptions
45
79
  import prefect.settings
46
80
  import prefect.states
47
81
  from prefect.client.constants import SERVER_API_VERSION
48
- from prefect.client.schemas import FlowRun, OrchestrationResult, TaskRun, sorting
82
+ from prefect.client.schemas import FlowRun, OrchestrationResult, TaskRun
49
83
  from prefect.client.schemas.actions import (
50
- BlockDocumentCreate,
51
- BlockDocumentUpdate,
52
- BlockSchemaCreate,
53
- BlockTypeCreate,
54
- BlockTypeUpdate,
55
- DeploymentCreate,
56
- DeploymentFlowRunCreate,
57
- DeploymentScheduleCreate,
58
- DeploymentScheduleUpdate,
59
- DeploymentUpdate,
60
- FlowCreate,
61
- FlowRunCreate,
62
84
  FlowRunNotificationPolicyCreate,
63
85
  FlowRunNotificationPolicyUpdate,
64
- FlowRunUpdate,
65
- LogCreate,
66
- GlobalConcurrencyLimitCreate,
67
- GlobalConcurrencyLimitUpdate,
68
86
  TaskRunCreate,
69
87
  TaskRunUpdate,
70
88
  WorkPoolCreate,
@@ -84,16 +102,8 @@ from prefect.client.schemas.filters import (
84
102
  WorkQueueFilterName,
85
103
  )
86
104
  from prefect.client.schemas.objects import (
87
- BlockDocument,
88
- BlockSchema,
89
- BlockType,
90
- ConcurrencyOptions,
91
105
  Constant,
92
- DeploymentSchedule,
93
- Flow,
94
- FlowRunInput,
95
106
  FlowRunNotificationPolicy,
96
- FlowRunPolicy,
97
107
  Parameter,
98
108
  TaskRunPolicy,
99
109
  TaskRunResult,
@@ -104,19 +114,11 @@ from prefect.client.schemas.objects import (
104
114
  WorkQueueStatusDetail,
105
115
  )
106
116
  from prefect.client.schemas.responses import (
107
- DeploymentResponse,
108
- FlowRunResponse,
109
117
  WorkerFlowRunResponse,
110
118
  )
111
- from prefect.client.schemas.schedules import SCHEDULE_TYPES
112
119
  from prefect.client.schemas.sorting import (
113
- DeploymentSort,
114
- FlowRunSort,
115
- FlowSort,
116
120
  TaskRunSort,
117
121
  )
118
- from prefect.events import filters
119
- from prefect.events.schemas.automations import Automation, AutomationCore
120
122
  from prefect.logging import get_logger
121
123
  from prefect.settings import (
122
124
  PREFECT_API_AUTH_STRING,
@@ -133,10 +135,8 @@ from prefect.settings import (
133
135
  PREFECT_TESTING_UNIT_TEST_MODE,
134
136
  get_current_settings,
135
137
  )
136
- from prefect.types import KeyValueLabelsField
137
138
 
138
139
  if TYPE_CHECKING:
139
- from prefect.flows import Flow as FlowObject
140
140
  from prefect.tasks import Task as TaskObject
141
141
 
142
142
  from prefect.client.base import (
@@ -255,6 +255,14 @@ class PrefectClient(
255
255
  LogAsyncClient,
256
256
  VariableAsyncClient,
257
257
  ConcurrencyLimitAsyncClient,
258
+ DeploymentAsyncClient,
259
+ AutomationAsyncClient,
260
+ SlaAsyncClient,
261
+ FlowRunAsyncClient,
262
+ FlowAsyncClient,
263
+ BlocksDocumentAsyncClient,
264
+ BlocksSchemaAsyncClient,
265
+ BlocksTypeAsyncClient,
258
266
  ):
259
267
  """
260
268
  An asynchronous client for interacting with the [Prefect REST API](/api-ref/rest-api/).
@@ -467,361 +475,6 @@ class PrefectClient(
467
475
  """
468
476
  return await self._client.get("/hello")
469
477
 
470
- async def create_flow(self, flow: "FlowObject[Any, Any]") -> UUID:
471
- """
472
- Create a flow in the Prefect API.
473
-
474
- Args:
475
- flow: a [Flow][prefect.flows.Flow] object
476
-
477
- Raises:
478
- httpx.RequestError: if a flow was not created for any reason
479
-
480
- Returns:
481
- the ID of the flow in the backend
482
- """
483
- return await self.create_flow_from_name(flow.name)
484
-
485
- async def create_flow_from_name(self, flow_name: str) -> UUID:
486
- """
487
- Create a flow in the Prefect API.
488
-
489
- Args:
490
- flow_name: the name of the new flow
491
-
492
- Raises:
493
- httpx.RequestError: if a flow was not created for any reason
494
-
495
- Returns:
496
- the ID of the flow in the backend
497
- """
498
- flow_data = FlowCreate(name=flow_name)
499
- response = await self._client.post(
500
- "/flows/", json=flow_data.model_dump(mode="json")
501
- )
502
-
503
- flow_id = response.json().get("id")
504
- if not flow_id:
505
- raise httpx.RequestError(f"Malformed response: {response}")
506
-
507
- # Return the id of the created flow
508
- return UUID(flow_id)
509
-
510
- async def read_flow(self, flow_id: UUID) -> Flow:
511
- """
512
- Query the Prefect API for a flow by id.
513
-
514
- Args:
515
- flow_id: the flow ID of interest
516
-
517
- Returns:
518
- a [Flow model][prefect.client.schemas.objects.Flow] representation of the flow
519
- """
520
- response = await self._client.get(f"/flows/{flow_id}")
521
- return Flow.model_validate(response.json())
522
-
523
- async def delete_flow(self, flow_id: UUID) -> None:
524
- """
525
- Delete a flow by UUID.
526
-
527
- Args:
528
- flow_id: ID of the flow to be deleted
529
- Raises:
530
- prefect.exceptions.ObjectNotFound: If request returns 404
531
- httpx.RequestError: If requests fail
532
- """
533
- try:
534
- await self._client.delete(f"/flows/{flow_id}")
535
- except httpx.HTTPStatusError as e:
536
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
537
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
538
- else:
539
- raise
540
-
541
- async def read_flows(
542
- self,
543
- *,
544
- flow_filter: Optional[FlowFilter] = None,
545
- flow_run_filter: Optional[FlowRunFilter] = None,
546
- task_run_filter: Optional[TaskRunFilter] = None,
547
- deployment_filter: Optional[DeploymentFilter] = None,
548
- work_pool_filter: Optional[WorkPoolFilter] = None,
549
- work_queue_filter: Optional[WorkQueueFilter] = None,
550
- sort: Optional[FlowSort] = None,
551
- limit: Optional[int] = None,
552
- offset: int = 0,
553
- ) -> list[Flow]:
554
- """
555
- Query the Prefect API for flows. Only flows matching all criteria will
556
- be returned.
557
-
558
- Args:
559
- flow_filter: filter criteria for flows
560
- flow_run_filter: filter criteria for flow runs
561
- task_run_filter: filter criteria for task runs
562
- deployment_filter: filter criteria for deployments
563
- work_pool_filter: filter criteria for work pools
564
- work_queue_filter: filter criteria for work pool queues
565
- sort: sort criteria for the flows
566
- limit: limit for the flow query
567
- offset: offset for the flow query
568
-
569
- Returns:
570
- a list of Flow model representations of the flows
571
- """
572
- body: dict[str, Any] = {
573
- "flows": flow_filter.model_dump(mode="json") if flow_filter else None,
574
- "flow_runs": (
575
- flow_run_filter.model_dump(mode="json", exclude_unset=True)
576
- if flow_run_filter
577
- else None
578
- ),
579
- "task_runs": (
580
- task_run_filter.model_dump(mode="json") if task_run_filter else None
581
- ),
582
- "deployments": (
583
- deployment_filter.model_dump(mode="json") if deployment_filter else None
584
- ),
585
- "work_pools": (
586
- work_pool_filter.model_dump(mode="json") if work_pool_filter else None
587
- ),
588
- "work_queues": (
589
- work_queue_filter.model_dump(mode="json") if work_queue_filter else None
590
- ),
591
- "sort": sort,
592
- "limit": limit,
593
- "offset": offset,
594
- }
595
-
596
- response = await self._client.post("/flows/filter", json=body)
597
- return pydantic.TypeAdapter(list[Flow]).validate_python(response.json())
598
-
599
- async def read_flow_by_name(
600
- self,
601
- flow_name: str,
602
- ) -> Flow:
603
- """
604
- Query the Prefect API for a flow by name.
605
-
606
- Args:
607
- flow_name: the name of a flow
608
-
609
- Returns:
610
- a fully hydrated Flow model
611
- """
612
- response = await self._client.get(f"/flows/name/{flow_name}")
613
- return Flow.model_validate(response.json())
614
-
615
- async def create_flow_run_from_deployment(
616
- self,
617
- deployment_id: UUID,
618
- *,
619
- parameters: Optional[dict[str, Any]] = None,
620
- context: Optional[dict[str, Any]] = None,
621
- state: Optional[prefect.states.State[Any]] = None,
622
- name: Optional[str] = None,
623
- tags: Optional[Iterable[str]] = None,
624
- idempotency_key: Optional[str] = None,
625
- parent_task_run_id: Optional[UUID] = None,
626
- work_queue_name: Optional[str] = None,
627
- job_variables: Optional[dict[str, Any]] = None,
628
- labels: Optional[KeyValueLabelsField] = None,
629
- ) -> FlowRun:
630
- """
631
- Create a flow run for a deployment.
632
-
633
- Args:
634
- deployment_id: The deployment ID to create the flow run from
635
- parameters: Parameter overrides for this flow run. Merged with the
636
- deployment defaults
637
- context: Optional run context data
638
- state: The initial state for the run. If not provided, defaults to
639
- `Scheduled` for now. Should always be a `Scheduled` type.
640
- name: An optional name for the flow run. If not provided, the server will
641
- generate a name.
642
- tags: An optional iterable of tags to apply to the flow run; these tags
643
- are merged with the deployment's tags.
644
- idempotency_key: Optional idempotency key for creation of the flow run.
645
- If the key matches the key of an existing flow run, the existing run will
646
- be returned instead of creating a new one.
647
- parent_task_run_id: if a subflow run is being created, the placeholder task
648
- run identifier in the parent flow
649
- work_queue_name: An optional work queue name to add this run to. If not provided,
650
- will default to the deployment's set work queue. If one is provided that does not
651
- exist, a new work queue will be created within the deployment's work pool.
652
- job_variables: Optional variables that will be supplied to the flow run job.
653
-
654
- Raises:
655
- httpx.RequestError: if the Prefect API does not successfully create a run for any reason
656
-
657
- Returns:
658
- The flow run model
659
- """
660
- parameters = parameters or {}
661
- context = context or {}
662
- state = state or prefect.states.Scheduled()
663
- tags = tags or []
664
-
665
- flow_run_create = DeploymentFlowRunCreate(
666
- parameters=parameters,
667
- context=context,
668
- state=state.to_state_create(),
669
- tags=list(tags),
670
- name=name,
671
- idempotency_key=idempotency_key,
672
- parent_task_run_id=parent_task_run_id,
673
- job_variables=job_variables,
674
- labels=labels,
675
- )
676
-
677
- # done separately to avoid including this field in payloads sent to older API versions
678
- if work_queue_name:
679
- flow_run_create.work_queue_name = work_queue_name
680
-
681
- response = await self._client.post(
682
- f"/deployments/{deployment_id}/create_flow_run",
683
- json=flow_run_create.model_dump(mode="json", exclude_unset=True),
684
- )
685
- return FlowRun.model_validate(response.json())
686
-
687
- async def create_flow_run(
688
- self,
689
- flow: "FlowObject[Any, R]",
690
- name: Optional[str] = None,
691
- parameters: Optional[dict[str, Any]] = None,
692
- context: Optional[dict[str, Any]] = None,
693
- tags: Optional[Iterable[str]] = None,
694
- parent_task_run_id: Optional[UUID] = None,
695
- state: Optional["prefect.states.State[R]"] = None,
696
- ) -> FlowRun:
697
- """
698
- Create a flow run for a flow.
699
-
700
- Args:
701
- flow: The flow model to create the flow run for
702
- name: An optional name for the flow run
703
- parameters: Parameter overrides for this flow run.
704
- context: Optional run context data
705
- tags: a list of tags to apply to this flow run
706
- parent_task_run_id: if a subflow run is being created, the placeholder task
707
- run identifier in the parent flow
708
- state: The initial state for the run. If not provided, defaults to
709
- `Scheduled` for now. Should always be a `Scheduled` type.
710
-
711
- Raises:
712
- httpx.RequestError: if the Prefect API does not successfully create a run for any reason
713
-
714
- Returns:
715
- The flow run model
716
- """
717
- parameters = parameters or {}
718
- context = context or {}
719
-
720
- if state is None:
721
- state = prefect.states.Pending()
722
-
723
- # Retrieve the flow id
724
- flow_id = await self.create_flow(flow)
725
-
726
- flow_run_create = FlowRunCreate(
727
- flow_id=flow_id,
728
- flow_version=flow.version,
729
- name=name,
730
- parameters=parameters,
731
- context=context,
732
- tags=list(tags or []),
733
- parent_task_run_id=parent_task_run_id,
734
- state=state.to_state_create(),
735
- empirical_policy=FlowRunPolicy(
736
- retries=flow.retries,
737
- retry_delay=int(flow.retry_delay_seconds or 0),
738
- ),
739
- )
740
-
741
- flow_run_create_json = flow_run_create.model_dump(mode="json")
742
- response = await self._client.post("/flow_runs/", json=flow_run_create_json)
743
- flow_run = FlowRun.model_validate(response.json())
744
-
745
- # Restore the parameters to the local objects to retain expectations about
746
- # Python objects
747
- flow_run.parameters = parameters
748
-
749
- return flow_run
750
-
751
- async def update_flow_run(
752
- self,
753
- flow_run_id: UUID,
754
- flow_version: Optional[str] = None,
755
- parameters: Optional[dict[str, Any]] = None,
756
- name: Optional[str] = None,
757
- tags: Optional[Iterable[str]] = None,
758
- empirical_policy: Optional[FlowRunPolicy] = None,
759
- infrastructure_pid: Optional[str] = None,
760
- job_variables: Optional[dict[str, Any]] = None,
761
- ) -> httpx.Response:
762
- """
763
- Update a flow run's details.
764
-
765
- Args:
766
- flow_run_id: The identifier for the flow run to update.
767
- flow_version: A new version string for the flow run.
768
- parameters: A dictionary of parameter values for the flow run. This will not
769
- be merged with any existing parameters.
770
- name: A new name for the flow run.
771
- empirical_policy: A new flow run orchestration policy. This will not be
772
- merged with any existing policy.
773
- tags: An iterable of new tags for the flow run. These will not be merged with
774
- any existing tags.
775
- infrastructure_pid: The id of flow run as returned by an
776
- infrastructure block.
777
-
778
- Returns:
779
- an `httpx.Response` object from the PATCH request
780
- """
781
- params: dict[str, Any] = {}
782
- if flow_version is not None:
783
- params["flow_version"] = flow_version
784
- if parameters is not None:
785
- params["parameters"] = parameters
786
- if name is not None:
787
- params["name"] = name
788
- if tags is not None:
789
- params["tags"] = tags
790
- if empirical_policy is not None:
791
- params["empirical_policy"] = empirical_policy
792
- if infrastructure_pid:
793
- params["infrastructure_pid"] = infrastructure_pid
794
- if job_variables is not None:
795
- params["job_variables"] = job_variables
796
-
797
- flow_run_data = FlowRunUpdate(**params)
798
-
799
- return await self._client.patch(
800
- f"/flow_runs/{flow_run_id}",
801
- json=flow_run_data.model_dump(mode="json", exclude_unset=True),
802
- )
803
-
804
- async def delete_flow_run(
805
- self,
806
- flow_run_id: UUID,
807
- ) -> None:
808
- """
809
- Delete a flow run by UUID.
810
-
811
- Args:
812
- flow_run_id: The flow run UUID of interest.
813
- Raises:
814
- prefect.exceptions.ObjectNotFound: If request returns 404
815
- httpx.RequestError: If requests fails
816
- """
817
- try:
818
- await self._client.delete(f"/flow_runs/{flow_run_id}")
819
- except httpx.HTTPStatusError as e:
820
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
821
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
822
- else:
823
- raise
824
-
825
478
  async def create_work_queue(
826
479
  self,
827
480
  name: str,
@@ -1089,1003 +742,37 @@ class PrefectClient(
1089
742
  else:
1090
743
  raise
1091
744
 
1092
- async def create_block_type(self, block_type: BlockTypeCreate) -> BlockType:
1093
- """
1094
- Create a block type in the Prefect API.
1095
- """
1096
- try:
1097
- response = await self._client.post(
1098
- "/block_types/",
1099
- json=block_type.model_dump(
1100
- mode="json", exclude_unset=True, exclude={"id"}
1101
- ),
1102
- )
1103
- except httpx.HTTPStatusError as e:
1104
- if e.response.status_code == status.HTTP_409_CONFLICT:
1105
- raise prefect.exceptions.ObjectAlreadyExists(http_exc=e) from e
1106
- else:
1107
- raise
1108
- return BlockType.model_validate(response.json())
1109
-
1110
- async def create_block_schema(self, block_schema: BlockSchemaCreate) -> BlockSchema:
1111
- """
1112
- Create a block schema in the Prefect API.
1113
- """
1114
- try:
1115
- response = await self._client.post(
1116
- "/block_schemas/",
1117
- json=block_schema.model_dump(
1118
- mode="json",
1119
- exclude_unset=True,
1120
- exclude={"id", "block_type", "checksum"},
1121
- ),
1122
- )
1123
- except httpx.HTTPStatusError as e:
1124
- if e.response.status_code == status.HTTP_409_CONFLICT:
1125
- raise prefect.exceptions.ObjectAlreadyExists(http_exc=e) from e
1126
- else:
1127
- raise
1128
- return BlockSchema.model_validate(response.json())
745
+ async def set_task_run_name(self, task_run_id: UUID, name: str) -> httpx.Response:
746
+ task_run_data = TaskRunUpdate(name=name)
747
+ return await self._client.patch(
748
+ f"/task_runs/{task_run_id}",
749
+ json=task_run_data.model_dump(mode="json", exclude_unset=True),
750
+ )
1129
751
 
1130
- async def create_block_document(
752
+ async def create_task_run(
1131
753
  self,
1132
- block_document: Union[BlockDocument, BlockDocumentCreate],
1133
- include_secrets: bool = True,
1134
- ) -> BlockDocument:
754
+ task: "TaskObject[P, R]",
755
+ flow_run_id: Optional[UUID],
756
+ dynamic_key: str,
757
+ id: Optional[UUID] = None,
758
+ name: Optional[str] = None,
759
+ extra_tags: Optional[Iterable[str]] = None,
760
+ state: Optional[prefect.states.State[R]] = None,
761
+ task_inputs: Optional[
762
+ dict[
763
+ str,
764
+ list[
765
+ Union[
766
+ TaskRunResult,
767
+ Parameter,
768
+ Constant,
769
+ ]
770
+ ],
771
+ ]
772
+ ] = None,
773
+ ) -> TaskRun:
1135
774
  """
1136
- Create a block document in the Prefect API. This data is used to configure a
1137
- corresponding Block.
1138
-
1139
- Args:
1140
- include_secrets (bool): whether to include secret values
1141
- on the stored Block, corresponding to Pydantic's `SecretStr` and
1142
- `SecretBytes` fields. Note Blocks may not work as expected if
1143
- this is set to `False`.
1144
- """
1145
- block_document_data = block_document.model_dump(
1146
- mode="json",
1147
- exclude_unset=True,
1148
- exclude={"id", "block_schema", "block_type"},
1149
- context={"include_secrets": include_secrets},
1150
- serialize_as_any=True,
1151
- )
1152
- try:
1153
- response = await self._client.post(
1154
- "/block_documents/",
1155
- json=block_document_data,
1156
- )
1157
- except httpx.HTTPStatusError as e:
1158
- if e.response.status_code == status.HTTP_409_CONFLICT:
1159
- raise prefect.exceptions.ObjectAlreadyExists(http_exc=e) from e
1160
- else:
1161
- raise
1162
- return BlockDocument.model_validate(response.json())
1163
-
1164
- async def update_block_document(
1165
- self,
1166
- block_document_id: UUID,
1167
- block_document: BlockDocumentUpdate,
1168
- ) -> None:
1169
- """
1170
- Update a block document in the Prefect API.
1171
- """
1172
- try:
1173
- await self._client.patch(
1174
- f"/block_documents/{block_document_id}",
1175
- json=block_document.model_dump(
1176
- mode="json",
1177
- exclude_unset=True,
1178
- include={"data", "merge_existing_data", "block_schema_id"},
1179
- ),
1180
- )
1181
- except httpx.HTTPStatusError as e:
1182
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1183
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1184
- else:
1185
- raise
1186
-
1187
- async def delete_block_document(self, block_document_id: UUID) -> None:
1188
- """
1189
- Delete a block document.
1190
- """
1191
- try:
1192
- await self._client.delete(f"/block_documents/{block_document_id}")
1193
- except httpx.HTTPStatusError as e:
1194
- if e.response.status_code == 404:
1195
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1196
- else:
1197
- raise
1198
-
1199
- async def read_block_type_by_slug(self, slug: str) -> BlockType:
1200
- """
1201
- Read a block type by its slug.
1202
- """
1203
- try:
1204
- response = await self._client.get(f"/block_types/slug/{slug}")
1205
- except httpx.HTTPStatusError as e:
1206
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1207
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1208
- else:
1209
- raise
1210
- return BlockType.model_validate(response.json())
1211
-
1212
- async def read_block_schema_by_checksum(
1213
- self, checksum: str, version: Optional[str] = None
1214
- ) -> BlockSchema:
1215
- """
1216
- Look up a block schema checksum
1217
- """
1218
- try:
1219
- url = f"/block_schemas/checksum/{checksum}"
1220
- if version is not None:
1221
- url = f"{url}?version={version}"
1222
- response = await self._client.get(url)
1223
- except httpx.HTTPStatusError as e:
1224
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1225
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1226
- else:
1227
- raise
1228
- return BlockSchema.model_validate(response.json())
1229
-
1230
- async def update_block_type(
1231
- self, block_type_id: UUID, block_type: BlockTypeUpdate
1232
- ) -> None:
1233
- """
1234
- Update a block document in the Prefect API.
1235
- """
1236
- try:
1237
- await self._client.patch(
1238
- f"/block_types/{block_type_id}",
1239
- json=block_type.model_dump(
1240
- mode="json",
1241
- exclude_unset=True,
1242
- include=BlockTypeUpdate.updatable_fields(),
1243
- ),
1244
- )
1245
- except httpx.HTTPStatusError as e:
1246
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1247
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1248
- else:
1249
- raise
1250
-
1251
- async def delete_block_type(self, block_type_id: UUID) -> None:
1252
- """
1253
- Delete a block type.
1254
- """
1255
- try:
1256
- await self._client.delete(f"/block_types/{block_type_id}")
1257
- except httpx.HTTPStatusError as e:
1258
- if e.response.status_code == 404:
1259
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1260
- elif (
1261
- e.response.status_code == status.HTTP_403_FORBIDDEN
1262
- and e.response.json()["detail"]
1263
- == "protected block types cannot be deleted."
1264
- ):
1265
- raise prefect.exceptions.ProtectedBlockError(
1266
- "Protected block types cannot be deleted."
1267
- ) from e
1268
- else:
1269
- raise
1270
-
1271
- async def read_block_types(self) -> list[BlockType]:
1272
- """
1273
- Read all block types
1274
- Raises:
1275
- httpx.RequestError: if the block types were not found
1276
-
1277
- Returns:
1278
- List of BlockTypes.
1279
- """
1280
- response = await self._client.post("/block_types/filter", json={})
1281
- return pydantic.TypeAdapter(list[BlockType]).validate_python(response.json())
1282
-
1283
- async def read_block_schemas(self) -> list[BlockSchema]:
1284
- """
1285
- Read all block schemas
1286
- Raises:
1287
- httpx.RequestError: if a valid block schema was not found
1288
-
1289
- Returns:
1290
- A BlockSchema.
1291
- """
1292
- response = await self._client.post("/block_schemas/filter", json={})
1293
- return pydantic.TypeAdapter(list[BlockSchema]).validate_python(response.json())
1294
-
1295
- async def get_most_recent_block_schema_for_block_type(
1296
- self,
1297
- block_type_id: UUID,
1298
- ) -> Optional[BlockSchema]:
1299
- """
1300
- Fetches the most recent block schema for a specified block type ID.
1301
-
1302
- Args:
1303
- block_type_id: The ID of the block type.
1304
-
1305
- Raises:
1306
- httpx.RequestError: If the request fails for any reason.
1307
-
1308
- Returns:
1309
- The most recent block schema or None.
1310
- """
1311
- try:
1312
- response = await self._client.post(
1313
- "/block_schemas/filter",
1314
- json={
1315
- "block_schemas": {"block_type_id": {"any_": [str(block_type_id)]}},
1316
- "limit": 1,
1317
- },
1318
- )
1319
- except httpx.HTTPStatusError:
1320
- raise
1321
- return (
1322
- BlockSchema.model_validate(response.json()[0]) if response.json() else None
1323
- )
1324
-
1325
- async def read_block_document(
1326
- self,
1327
- block_document_id: UUID,
1328
- include_secrets: bool = True,
1329
- ) -> BlockDocument:
1330
- """
1331
- Read the block document with the specified ID.
1332
-
1333
- Args:
1334
- block_document_id: the block document id
1335
- include_secrets (bool): whether to include secret values
1336
- on the Block, corresponding to Pydantic's `SecretStr` and
1337
- `SecretBytes` fields. These fields are automatically obfuscated
1338
- by Pydantic, but users can additionally choose not to receive
1339
- their values from the API. Note that any business logic on the
1340
- Block may not work if this is `False`.
1341
-
1342
- Raises:
1343
- httpx.RequestError: if the block document was not found for any reason
1344
-
1345
- Returns:
1346
- A block document or None.
1347
- """
1348
- assert (
1349
- block_document_id is not None
1350
- ), "Unexpected ID on block document. Was it persisted?"
1351
- try:
1352
- response = await self._client.get(
1353
- f"/block_documents/{block_document_id}",
1354
- params=dict(include_secrets=include_secrets),
1355
- )
1356
- except httpx.HTTPStatusError as e:
1357
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1358
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1359
- else:
1360
- raise
1361
- return BlockDocument.model_validate(response.json())
1362
-
1363
- async def read_block_document_by_name(
1364
- self,
1365
- name: str,
1366
- block_type_slug: str,
1367
- include_secrets: bool = True,
1368
- ) -> BlockDocument:
1369
- """
1370
- Read the block document with the specified name that corresponds to a
1371
- specific block type name.
1372
-
1373
- Args:
1374
- name: The block document name.
1375
- block_type_slug: The block type slug.
1376
- include_secrets (bool): whether to include secret values
1377
- on the Block, corresponding to Pydantic's `SecretStr` and
1378
- `SecretBytes` fields. These fields are automatically obfuscated
1379
- by Pydantic, but users can additionally choose not to receive
1380
- their values from the API. Note that any business logic on the
1381
- Block may not work if this is `False`.
1382
-
1383
- Raises:
1384
- httpx.RequestError: if the block document was not found for any reason
1385
-
1386
- Returns:
1387
- A block document or None.
1388
- """
1389
- try:
1390
- response = await self._client.get(
1391
- f"/block_types/slug/{block_type_slug}/block_documents/name/{name}",
1392
- params=dict(include_secrets=include_secrets),
1393
- )
1394
- except httpx.HTTPStatusError as e:
1395
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1396
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1397
- else:
1398
- raise
1399
- return BlockDocument.model_validate(response.json())
1400
-
1401
- async def read_block_documents(
1402
- self,
1403
- block_schema_type: Optional[str] = None,
1404
- offset: Optional[int] = None,
1405
- limit: Optional[int] = None,
1406
- include_secrets: bool = True,
1407
- ) -> list[BlockDocument]:
1408
- """
1409
- Read block documents
1410
-
1411
- Args:
1412
- block_schema_type: an optional block schema type
1413
- offset: an offset
1414
- limit: the number of blocks to return
1415
- include_secrets (bool): whether to include secret values
1416
- on the Block, corresponding to Pydantic's `SecretStr` and
1417
- `SecretBytes` fields. These fields are automatically obfuscated
1418
- by Pydantic, but users can additionally choose not to receive
1419
- their values from the API. Note that any business logic on the
1420
- Block may not work if this is `False`.
1421
-
1422
- Returns:
1423
- A list of block documents
1424
- """
1425
- response = await self._client.post(
1426
- "/block_documents/filter",
1427
- json=dict(
1428
- block_schema_type=block_schema_type,
1429
- offset=offset,
1430
- limit=limit,
1431
- include_secrets=include_secrets,
1432
- ),
1433
- )
1434
- return pydantic.TypeAdapter(list[BlockDocument]).validate_python(
1435
- response.json()
1436
- )
1437
-
1438
- async def read_block_documents_by_type(
1439
- self,
1440
- block_type_slug: str,
1441
- offset: Optional[int] = None,
1442
- limit: Optional[int] = None,
1443
- include_secrets: bool = True,
1444
- ) -> list[BlockDocument]:
1445
- """Retrieve block documents by block type slug.
1446
-
1447
- Args:
1448
- block_type_slug: The block type slug.
1449
- offset: an offset
1450
- limit: the number of blocks to return
1451
- include_secrets: whether to include secret values
1452
-
1453
- Returns:
1454
- A list of block documents
1455
- """
1456
- response = await self._client.get(
1457
- f"/block_types/slug/{block_type_slug}/block_documents",
1458
- params=dict(
1459
- offset=offset,
1460
- limit=limit,
1461
- include_secrets=include_secrets,
1462
- ),
1463
- )
1464
-
1465
- return pydantic.TypeAdapter(list[BlockDocument]).validate_python(
1466
- response.json()
1467
- )
1468
-
1469
- async def create_deployment(
1470
- self,
1471
- flow_id: UUID,
1472
- name: str,
1473
- version: Optional[str] = None,
1474
- schedules: Optional[list[DeploymentScheduleCreate]] = None,
1475
- concurrency_limit: Optional[int] = None,
1476
- concurrency_options: Optional[ConcurrencyOptions] = None,
1477
- parameters: Optional[dict[str, Any]] = None,
1478
- description: Optional[str] = None,
1479
- work_queue_name: Optional[str] = None,
1480
- work_pool_name: Optional[str] = None,
1481
- tags: Optional[list[str]] = None,
1482
- storage_document_id: Optional[UUID] = None,
1483
- path: Optional[str] = None,
1484
- entrypoint: Optional[str] = None,
1485
- infrastructure_document_id: Optional[UUID] = None,
1486
- parameter_openapi_schema: Optional[dict[str, Any]] = None,
1487
- paused: Optional[bool] = None,
1488
- pull_steps: Optional[list[dict[str, Any]]] = None,
1489
- enforce_parameter_schema: Optional[bool] = None,
1490
- job_variables: Optional[dict[str, Any]] = None,
1491
- ) -> UUID:
1492
- """
1493
- Create a deployment.
1494
-
1495
- Args:
1496
- flow_id: the flow ID to create a deployment for
1497
- name: the name of the deployment
1498
- version: an optional version string for the deployment
1499
- tags: an optional list of tags to apply to the deployment
1500
- storage_document_id: an reference to the storage block document
1501
- used for the deployed flow
1502
- infrastructure_document_id: an reference to the infrastructure block document
1503
- to use for this deployment
1504
- job_variables: A dictionary of dot delimited infrastructure overrides that
1505
- will be applied at runtime; for example `env.CONFIG_KEY=config_value` or
1506
- `namespace='prefect'`. This argument was previously named `infra_overrides`.
1507
- Both arguments are supported for backwards compatibility.
1508
-
1509
- Raises:
1510
- httpx.RequestError: if the deployment was not created for any reason
1511
-
1512
- Returns:
1513
- the ID of the deployment in the backend
1514
- """
1515
-
1516
- if parameter_openapi_schema is None:
1517
- parameter_openapi_schema = {}
1518
- deployment_create = DeploymentCreate(
1519
- flow_id=flow_id,
1520
- name=name,
1521
- version=version,
1522
- parameters=dict(parameters or {}),
1523
- tags=list(tags or []),
1524
- work_queue_name=work_queue_name,
1525
- description=description,
1526
- storage_document_id=storage_document_id,
1527
- path=path,
1528
- entrypoint=entrypoint,
1529
- infrastructure_document_id=infrastructure_document_id,
1530
- job_variables=dict(job_variables or {}),
1531
- parameter_openapi_schema=parameter_openapi_schema,
1532
- paused=paused,
1533
- schedules=schedules or [],
1534
- concurrency_limit=concurrency_limit,
1535
- concurrency_options=concurrency_options,
1536
- pull_steps=pull_steps,
1537
- enforce_parameter_schema=enforce_parameter_schema,
1538
- )
1539
-
1540
- if work_pool_name is not None:
1541
- deployment_create.work_pool_name = work_pool_name
1542
-
1543
- # Exclude newer fields that are not set to avoid compatibility issues
1544
- exclude = {
1545
- field
1546
- for field in ["work_pool_name", "work_queue_name"]
1547
- if field not in deployment_create.model_fields_set
1548
- }
1549
-
1550
- if deployment_create.paused is None:
1551
- exclude.add("paused")
1552
-
1553
- if deployment_create.pull_steps is None:
1554
- exclude.add("pull_steps")
1555
-
1556
- if deployment_create.enforce_parameter_schema is None:
1557
- exclude.add("enforce_parameter_schema")
1558
-
1559
- json = deployment_create.model_dump(mode="json", exclude=exclude)
1560
- response = await self._client.post(
1561
- "/deployments/",
1562
- json=json,
1563
- )
1564
- deployment_id = response.json().get("id")
1565
- if not deployment_id:
1566
- raise httpx.RequestError(f"Malformed response: {response}")
1567
-
1568
- return UUID(deployment_id)
1569
-
1570
- async def set_deployment_paused_state(
1571
- self, deployment_id: UUID, paused: bool
1572
- ) -> None:
1573
- await self._client.patch(
1574
- f"/deployments/{deployment_id}", json={"paused": paused}
1575
- )
1576
-
1577
- async def update_deployment(
1578
- self,
1579
- deployment_id: UUID,
1580
- deployment: DeploymentUpdate,
1581
- ) -> None:
1582
- await self._client.patch(
1583
- f"/deployments/{deployment_id}",
1584
- json=deployment.model_dump(mode="json", exclude_unset=True),
1585
- )
1586
-
1587
- async def _create_deployment_from_schema(self, schema: DeploymentCreate) -> UUID:
1588
- """
1589
- Create a deployment from a prepared `DeploymentCreate` schema.
1590
- """
1591
- # TODO: We are likely to remove this method once we have considered the
1592
- # packaging interface for deployments further.
1593
- response = await self._client.post(
1594
- "/deployments/", json=schema.model_dump(mode="json")
1595
- )
1596
- deployment_id = response.json().get("id")
1597
- if not deployment_id:
1598
- raise httpx.RequestError(f"Malformed response: {response}")
1599
-
1600
- return UUID(deployment_id)
1601
-
1602
- async def read_deployment(
1603
- self,
1604
- deployment_id: Union[UUID, str],
1605
- ) -> DeploymentResponse:
1606
- """
1607
- Query the Prefect API for a deployment by id.
1608
-
1609
- Args:
1610
- deployment_id: the deployment ID of interest
1611
-
1612
- Returns:
1613
- a [Deployment model][prefect.client.schemas.objects.Deployment] representation of the deployment
1614
- """
1615
- if not isinstance(deployment_id, UUID):
1616
- try:
1617
- deployment_id = UUID(deployment_id)
1618
- except ValueError:
1619
- raise ValueError(f"Invalid deployment ID: {deployment_id}")
1620
-
1621
- try:
1622
- response = await self._client.get(f"/deployments/{deployment_id}")
1623
- except httpx.HTTPStatusError as e:
1624
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1625
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1626
- else:
1627
- raise
1628
- return DeploymentResponse.model_validate(response.json())
1629
-
1630
- async def read_deployment_by_name(
1631
- self,
1632
- name: str,
1633
- ) -> DeploymentResponse:
1634
- """
1635
- Query the Prefect API for a deployment by name.
1636
-
1637
- Args:
1638
- name: A deployed flow's name: <FLOW_NAME>/<DEPLOYMENT_NAME>
1639
-
1640
- Raises:
1641
- prefect.exceptions.ObjectNotFound: If request returns 404
1642
- httpx.RequestError: If request fails
1643
-
1644
- Returns:
1645
- a Deployment model representation of the deployment
1646
- """
1647
- try:
1648
- response = await self._client.get(f"/deployments/name/{name}")
1649
- except httpx.HTTPStatusError as e:
1650
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1651
- from prefect.utilities.text import fuzzy_match_string
1652
-
1653
- deployments = await self.read_deployments()
1654
- flow_name_map = {
1655
- flow.id: flow.name
1656
- for flow in await asyncio.gather(
1657
- *[
1658
- self.read_flow(flow_id)
1659
- for flow_id in {d.flow_id for d in deployments}
1660
- ]
1661
- )
1662
- }
1663
-
1664
- raise prefect.exceptions.ObjectNotFound(
1665
- http_exc=e,
1666
- help_message=(
1667
- f"Deployment {name!r} not found; did you mean {fuzzy_match!r}?"
1668
- if (
1669
- fuzzy_match := fuzzy_match_string(
1670
- name,
1671
- [
1672
- f"{flow_name_map[d.flow_id]}/{d.name}"
1673
- for d in deployments
1674
- ],
1675
- )
1676
- )
1677
- else f"Deployment {name!r} not found. Try `prefect deployment ls` to find available deployments."
1678
- ),
1679
- ) from e
1680
- else:
1681
- raise
1682
-
1683
- return DeploymentResponse.model_validate(response.json())
1684
-
1685
- async def read_deployments(
1686
- self,
1687
- *,
1688
- flow_filter: Optional[FlowFilter] = None,
1689
- flow_run_filter: Optional[FlowRunFilter] = None,
1690
- task_run_filter: Optional[TaskRunFilter] = None,
1691
- deployment_filter: Optional[DeploymentFilter] = None,
1692
- work_pool_filter: Optional[WorkPoolFilter] = None,
1693
- work_queue_filter: Optional[WorkQueueFilter] = None,
1694
- limit: Optional[int] = None,
1695
- sort: Optional[DeploymentSort] = None,
1696
- offset: int = 0,
1697
- ) -> list[DeploymentResponse]:
1698
- """
1699
- Query the Prefect API for deployments. Only deployments matching all
1700
- the provided criteria will be returned.
1701
-
1702
- Args:
1703
- flow_filter: filter criteria for flows
1704
- flow_run_filter: filter criteria for flow runs
1705
- task_run_filter: filter criteria for task runs
1706
- deployment_filter: filter criteria for deployments
1707
- work_pool_filter: filter criteria for work pools
1708
- work_queue_filter: filter criteria for work pool queues
1709
- limit: a limit for the deployment query
1710
- offset: an offset for the deployment query
1711
-
1712
- Returns:
1713
- a list of Deployment model representations
1714
- of the deployments
1715
- """
1716
- body: dict[str, Any] = {
1717
- "flows": flow_filter.model_dump(mode="json") if flow_filter else None,
1718
- "flow_runs": (
1719
- flow_run_filter.model_dump(mode="json", exclude_unset=True)
1720
- if flow_run_filter
1721
- else None
1722
- ),
1723
- "task_runs": (
1724
- task_run_filter.model_dump(mode="json") if task_run_filter else None
1725
- ),
1726
- "deployments": (
1727
- deployment_filter.model_dump(mode="json") if deployment_filter else None
1728
- ),
1729
- "work_pools": (
1730
- work_pool_filter.model_dump(mode="json") if work_pool_filter else None
1731
- ),
1732
- "work_pool_queues": (
1733
- work_queue_filter.model_dump(mode="json") if work_queue_filter else None
1734
- ),
1735
- "limit": limit,
1736
- "offset": offset,
1737
- "sort": sort,
1738
- }
1739
-
1740
- response = await self._client.post("/deployments/filter", json=body)
1741
- return pydantic.TypeAdapter(list[DeploymentResponse]).validate_python(
1742
- response.json()
1743
- )
1744
-
1745
- async def delete_deployment(
1746
- self,
1747
- deployment_id: UUID,
1748
- ) -> None:
1749
- """
1750
- Delete deployment by id.
1751
-
1752
- Args:
1753
- deployment_id: The deployment id of interest.
1754
- Raises:
1755
- prefect.exceptions.ObjectNotFound: If request returns 404
1756
- httpx.RequestError: If requests fails
1757
- """
1758
- try:
1759
- await self._client.delete(f"/deployments/{deployment_id}")
1760
- except httpx.HTTPStatusError as e:
1761
- if e.response.status_code == 404:
1762
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1763
- else:
1764
- raise
1765
-
1766
- async def create_deployment_schedules(
1767
- self,
1768
- deployment_id: UUID,
1769
- schedules: list[tuple[SCHEDULE_TYPES, bool]],
1770
- ) -> list[DeploymentSchedule]:
1771
- """
1772
- Create deployment schedules.
1773
-
1774
- Args:
1775
- deployment_id: the deployment ID
1776
- schedules: a list of tuples containing the schedule to create
1777
- and whether or not it should be active.
1778
-
1779
- Raises:
1780
- httpx.RequestError: if the schedules were not created for any reason
1781
-
1782
- Returns:
1783
- the list of schedules created in the backend
1784
- """
1785
- deployment_schedule_create = [
1786
- DeploymentScheduleCreate(schedule=schedule[0], active=schedule[1])
1787
- for schedule in schedules
1788
- ]
1789
-
1790
- json = [
1791
- deployment_schedule_create.model_dump(mode="json")
1792
- for deployment_schedule_create in deployment_schedule_create
1793
- ]
1794
- response = await self._client.post(
1795
- f"/deployments/{deployment_id}/schedules", json=json
1796
- )
1797
- return pydantic.TypeAdapter(list[DeploymentSchedule]).validate_python(
1798
- response.json()
1799
- )
1800
-
1801
- async def read_deployment_schedules(
1802
- self,
1803
- deployment_id: UUID,
1804
- ) -> list[DeploymentSchedule]:
1805
- """
1806
- Query the Prefect API for a deployment's schedules.
1807
-
1808
- Args:
1809
- deployment_id: the deployment ID
1810
-
1811
- Returns:
1812
- a list of DeploymentSchedule model representations of the deployment schedules
1813
- """
1814
- try:
1815
- response = await self._client.get(f"/deployments/{deployment_id}/schedules")
1816
- except httpx.HTTPStatusError as e:
1817
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1818
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1819
- else:
1820
- raise
1821
- return pydantic.TypeAdapter(list[DeploymentSchedule]).validate_python(
1822
- response.json()
1823
- )
1824
-
1825
- async def update_deployment_schedule(
1826
- self,
1827
- deployment_id: UUID,
1828
- schedule_id: UUID,
1829
- active: Optional[bool] = None,
1830
- schedule: Optional[SCHEDULE_TYPES] = None,
1831
- ) -> None:
1832
- """
1833
- Update a deployment schedule by ID.
1834
-
1835
- Args:
1836
- deployment_id: the deployment ID
1837
- schedule_id: the deployment schedule ID of interest
1838
- active: whether or not the schedule should be active
1839
- schedule: the cron, rrule, or interval schedule this deployment schedule should use
1840
- """
1841
- kwargs: dict[str, Any] = {}
1842
- if active is not None:
1843
- kwargs["active"] = active
1844
- if schedule is not None:
1845
- kwargs["schedule"] = schedule
1846
-
1847
- deployment_schedule_update = DeploymentScheduleUpdate(**kwargs)
1848
- json = deployment_schedule_update.model_dump(mode="json", exclude_unset=True)
1849
-
1850
- try:
1851
- await self._client.patch(
1852
- f"/deployments/{deployment_id}/schedules/{schedule_id}", json=json
1853
- )
1854
- except httpx.HTTPStatusError as e:
1855
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
1856
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1857
- else:
1858
- raise
1859
-
1860
- async def delete_deployment_schedule(
1861
- self,
1862
- deployment_id: UUID,
1863
- schedule_id: UUID,
1864
- ) -> None:
1865
- """
1866
- Delete a deployment schedule.
1867
-
1868
- Args:
1869
- deployment_id: the deployment ID
1870
- schedule_id: the ID of the deployment schedule to delete.
1871
-
1872
- Raises:
1873
- httpx.RequestError: if the schedules were not deleted for any reason
1874
- """
1875
- try:
1876
- await self._client.delete(
1877
- f"/deployments/{deployment_id}/schedules/{schedule_id}"
1878
- )
1879
- except httpx.HTTPStatusError as e:
1880
- if e.response.status_code == 404:
1881
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1882
- else:
1883
- raise
1884
-
1885
- async def read_flow_run(self, flow_run_id: UUID) -> FlowRun:
1886
- """
1887
- Query the Prefect API for a flow run by id.
1888
-
1889
- Args:
1890
- flow_run_id: the flow run ID of interest
1891
-
1892
- Returns:
1893
- a Flow Run model representation of the flow run
1894
- """
1895
- try:
1896
- response = await self._client.get(f"/flow_runs/{flow_run_id}")
1897
- except httpx.HTTPStatusError as e:
1898
- if e.response.status_code == 404:
1899
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
1900
- else:
1901
- raise
1902
- return FlowRun.model_validate(response.json())
1903
-
1904
- async def resume_flow_run(
1905
- self, flow_run_id: UUID, run_input: Optional[dict[str, Any]] = None
1906
- ) -> OrchestrationResult[Any]:
1907
- """
1908
- Resumes a paused flow run.
1909
-
1910
- Args:
1911
- flow_run_id: the flow run ID of interest
1912
- run_input: the input to resume the flow run with
1913
-
1914
- Returns:
1915
- an OrchestrationResult model representation of state orchestration output
1916
- """
1917
- try:
1918
- response = await self._client.post(
1919
- f"/flow_runs/{flow_run_id}/resume", json={"run_input": run_input}
1920
- )
1921
- except httpx.HTTPStatusError:
1922
- raise
1923
-
1924
- result: OrchestrationResult[Any] = OrchestrationResult.model_validate(
1925
- response.json()
1926
- )
1927
- return result
1928
-
1929
- async def read_flow_runs(
1930
- self,
1931
- *,
1932
- flow_filter: Optional[FlowFilter] = None,
1933
- flow_run_filter: Optional[FlowRunFilter] = None,
1934
- task_run_filter: Optional[TaskRunFilter] = None,
1935
- deployment_filter: Optional[DeploymentFilter] = None,
1936
- work_pool_filter: Optional[WorkPoolFilter] = None,
1937
- work_queue_filter: Optional[WorkQueueFilter] = None,
1938
- sort: Optional[FlowRunSort] = None,
1939
- limit: Optional[int] = None,
1940
- offset: int = 0,
1941
- ) -> list[FlowRun]:
1942
- """
1943
- Query the Prefect API for flow runs. Only flow runs matching all criteria will
1944
- be returned.
1945
-
1946
- Args:
1947
- flow_filter: filter criteria for flows
1948
- flow_run_filter: filter criteria for flow runs
1949
- task_run_filter: filter criteria for task runs
1950
- deployment_filter: filter criteria for deployments
1951
- work_pool_filter: filter criteria for work pools
1952
- work_queue_filter: filter criteria for work pool queues
1953
- sort: sort criteria for the flow runs
1954
- limit: limit for the flow run query
1955
- offset: offset for the flow run query
1956
-
1957
- Returns:
1958
- a list of Flow Run model representations
1959
- of the flow runs
1960
- """
1961
- body: dict[str, Any] = {
1962
- "flows": flow_filter.model_dump(mode="json") if flow_filter else None,
1963
- "flow_runs": (
1964
- flow_run_filter.model_dump(mode="json", exclude_unset=True)
1965
- if flow_run_filter
1966
- else None
1967
- ),
1968
- "task_runs": (
1969
- task_run_filter.model_dump(mode="json") if task_run_filter else None
1970
- ),
1971
- "deployments": (
1972
- deployment_filter.model_dump(mode="json") if deployment_filter else None
1973
- ),
1974
- "work_pools": (
1975
- work_pool_filter.model_dump(mode="json") if work_pool_filter else None
1976
- ),
1977
- "work_pool_queues": (
1978
- work_queue_filter.model_dump(mode="json") if work_queue_filter else None
1979
- ),
1980
- "sort": sort,
1981
- "limit": limit,
1982
- "offset": offset,
1983
- }
1984
-
1985
- response = await self._client.post("/flow_runs/filter", json=body)
1986
- return pydantic.TypeAdapter(list[FlowRun]).validate_python(response.json())
1987
-
1988
- async def set_flow_run_state(
1989
- self,
1990
- flow_run_id: Union[UUID, str],
1991
- state: "prefect.states.State[T]",
1992
- force: bool = False,
1993
- ) -> OrchestrationResult[T]:
1994
- """
1995
- Set the state of a flow run.
1996
-
1997
- Args:
1998
- flow_run_id: the id of the flow run
1999
- state: the state to set
2000
- force: if True, disregard orchestration logic when setting the state,
2001
- forcing the Prefect API to accept the state
2002
-
2003
- Returns:
2004
- an OrchestrationResult model representation of state orchestration output
2005
- """
2006
- flow_run_id = (
2007
- flow_run_id if isinstance(flow_run_id, UUID) else UUID(flow_run_id)
2008
- )
2009
- state_create = state.to_state_create()
2010
- state_create.state_details.flow_run_id = flow_run_id
2011
- state_create.state_details.transition_id = uuid4()
2012
- try:
2013
- response = await self._client.post(
2014
- f"/flow_runs/{flow_run_id}/set_state",
2015
- json=dict(
2016
- state=state_create.model_dump(mode="json", serialize_as_any=True),
2017
- force=force,
2018
- ),
2019
- )
2020
- except httpx.HTTPStatusError as e:
2021
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
2022
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
2023
- else:
2024
- raise
2025
-
2026
- result: OrchestrationResult[T] = OrchestrationResult.model_validate(
2027
- response.json()
2028
- )
2029
- return result
2030
-
2031
- async def read_flow_run_states(
2032
- self, flow_run_id: UUID
2033
- ) -> list[prefect.states.State]:
2034
- """
2035
- Query for the states of a flow run
2036
-
2037
- Args:
2038
- flow_run_id: the id of the flow run
2039
-
2040
- Returns:
2041
- a list of State model representations
2042
- of the flow run states
2043
- """
2044
- response = await self._client.get(
2045
- "/flow_run_states/", params=dict(flow_run_id=str(flow_run_id))
2046
- )
2047
- return pydantic.TypeAdapter(list[prefect.states.State]).validate_python(
2048
- response.json()
2049
- )
2050
-
2051
- async def set_flow_run_name(self, flow_run_id: UUID, name: str) -> httpx.Response:
2052
- flow_run_data = FlowRunUpdate(name=name)
2053
- return await self._client.patch(
2054
- f"/flow_runs/{flow_run_id}",
2055
- json=flow_run_data.model_dump(mode="json", exclude_unset=True),
2056
- )
2057
-
2058
- async def set_task_run_name(self, task_run_id: UUID, name: str) -> httpx.Response:
2059
- task_run_data = TaskRunUpdate(name=name)
2060
- return await self._client.patch(
2061
- f"/task_runs/{task_run_id}",
2062
- json=task_run_data.model_dump(mode="json", exclude_unset=True),
2063
- )
2064
-
2065
- async def create_task_run(
2066
- self,
2067
- task: "TaskObject[P, R]",
2068
- flow_run_id: Optional[UUID],
2069
- dynamic_key: str,
2070
- id: Optional[UUID] = None,
2071
- name: Optional[str] = None,
2072
- extra_tags: Optional[Iterable[str]] = None,
2073
- state: Optional[prefect.states.State[R]] = None,
2074
- task_inputs: Optional[
2075
- dict[
2076
- str,
2077
- list[
2078
- Union[
2079
- TaskRunResult,
2080
- Parameter,
2081
- Constant,
2082
- ]
2083
- ],
2084
- ]
2085
- ] = None,
2086
- ) -> TaskRun:
2087
- """
2088
- Create a task run
775
+ Create a task run
2089
776
 
2090
777
  Args:
2091
778
  task: The Task to run
@@ -2666,251 +1353,46 @@ class PrefectClient(
2666
1353
 
2667
1354
  return pydantic.TypeAdapter(list[WorkQueue]).validate_python(response.json())
2668
1355
 
2669
- async def get_scheduled_flow_runs_for_deployments(
2670
- self,
2671
- deployment_ids: list[UUID],
2672
- scheduled_before: Optional[datetime.datetime] = None,
2673
- limit: Optional[int] = None,
2674
- ) -> list[FlowRunResponse]:
2675
- body: dict[str, Any] = dict(deployment_ids=[str(id) for id in deployment_ids])
2676
- if scheduled_before:
2677
- body["scheduled_before"] = str(scheduled_before)
2678
- if limit:
2679
- body["limit"] = limit
2680
-
2681
- response = await self._client.post(
2682
- "/deployments/get_scheduled_flow_runs",
2683
- json=body,
2684
- )
2685
-
2686
- return pydantic.TypeAdapter(list[FlowRunResponse]).validate_python(
2687
- response.json()
2688
- )
2689
-
2690
1356
  async def get_scheduled_flow_runs_for_work_pool(
2691
1357
  self,
2692
1358
  work_pool_name: str,
2693
1359
  work_queue_names: Optional[list[str]] = None,
2694
1360
  scheduled_before: Optional[datetime.datetime] = None,
2695
- ) -> list[WorkerFlowRunResponse]:
2696
- """
2697
- Retrieves scheduled flow runs for the provided set of work pool queues.
2698
-
2699
- Args:
2700
- work_pool_name: The name of the work pool that the work pool
2701
- queues are associated with.
2702
- work_queue_names: The names of the work pool queues from which
2703
- to get scheduled flow runs.
2704
- scheduled_before: Datetime used to filter returned flow runs. Flow runs
2705
- scheduled for after the given datetime string will not be returned.
2706
-
2707
- Returns:
2708
- A list of worker flow run responses containing information about the
2709
- retrieved flow runs.
2710
- """
2711
- body: dict[str, Any] = {}
2712
- if work_queue_names is not None:
2713
- body["work_queue_names"] = list(work_queue_names)
2714
- if scheduled_before:
2715
- body["scheduled_before"] = str(scheduled_before)
2716
-
2717
- response = await self._client.post(
2718
- f"/work_pools/{work_pool_name}/get_scheduled_flow_runs",
2719
- json=body,
2720
- )
2721
- return pydantic.TypeAdapter(list[WorkerFlowRunResponse]).validate_python(
2722
- response.json()
2723
- )
2724
-
2725
- async def read_worker_metadata(self) -> dict[str, Any]:
2726
- """Reads worker metadata stored in Prefect collection registry."""
2727
- response = await self._client.get("collections/views/aggregate-worker-metadata")
2728
- response.raise_for_status()
2729
- return response.json()
2730
-
2731
- async def create_flow_run_input(
2732
- self, flow_run_id: UUID, key: str, value: str, sender: Optional[str] = None
2733
- ) -> None:
2734
- """
2735
- Creates a flow run input.
2736
-
2737
- Args:
2738
- flow_run_id: The flow run id.
2739
- key: The input key.
2740
- value: The input value.
2741
- sender: The sender of the input.
2742
- """
2743
-
2744
- # Initialize the input to ensure that the key is valid.
2745
- FlowRunInput(flow_run_id=flow_run_id, key=key, value=value)
2746
-
2747
- response = await self._client.post(
2748
- f"/flow_runs/{flow_run_id}/input",
2749
- json={"key": key, "value": value, "sender": sender},
2750
- )
2751
- response.raise_for_status()
2752
-
2753
- async def filter_flow_run_input(
2754
- self, flow_run_id: UUID, key_prefix: str, limit: int, exclude_keys: set[str]
2755
- ) -> list[FlowRunInput]:
2756
- response = await self._client.post(
2757
- f"/flow_runs/{flow_run_id}/input/filter",
2758
- json={
2759
- "prefix": key_prefix,
2760
- "limit": limit,
2761
- "exclude_keys": list(exclude_keys),
2762
- },
2763
- )
2764
- response.raise_for_status()
2765
- return pydantic.TypeAdapter(list[FlowRunInput]).validate_python(response.json())
2766
-
2767
- async def read_flow_run_input(self, flow_run_id: UUID, key: str) -> str:
2768
- """
2769
- Reads a flow run input.
2770
-
2771
- Args:
2772
- flow_run_id: The flow run id.
2773
- key: The input key.
2774
- """
2775
- response = await self._client.get(f"/flow_runs/{flow_run_id}/input/{key}")
2776
- response.raise_for_status()
2777
- return response.content.decode()
2778
-
2779
- async def delete_flow_run_input(self, flow_run_id: UUID, key: str) -> None:
2780
- """
2781
- Deletes a flow run input.
2782
-
2783
- Args:
2784
- flow_run_id: The flow run id.
2785
- key: The input key.
2786
- """
2787
- response = await self._client.delete(f"/flow_runs/{flow_run_id}/input/{key}")
2788
- response.raise_for_status()
2789
-
2790
- async def create_automation(self, automation: AutomationCore) -> UUID:
2791
- """Creates an automation in Prefect Cloud."""
2792
- response = await self._client.post(
2793
- "/automations/",
2794
- json=automation.model_dump(mode="json"),
2795
- )
2796
-
2797
- return UUID(response.json()["id"])
2798
-
2799
- async def update_automation(
2800
- self, automation_id: UUID, automation: AutomationCore
2801
- ) -> None:
2802
- """Updates an automation in Prefect Cloud."""
2803
- response = await self._client.put(
2804
- f"/automations/{automation_id}",
2805
- json=automation.model_dump(mode="json", exclude_unset=True),
2806
- )
2807
- response.raise_for_status
2808
-
2809
- async def read_automations(self) -> list[Automation]:
2810
- response = await self._client.post("/automations/filter")
2811
- response.raise_for_status()
2812
- return pydantic.TypeAdapter(list[Automation]).validate_python(response.json())
2813
-
2814
- async def find_automation(
2815
- self, id_or_name: Union[str, UUID]
2816
- ) -> Optional[Automation]:
2817
- if isinstance(id_or_name, str):
2818
- name = id_or_name
2819
- try:
2820
- id = UUID(id_or_name)
2821
- except ValueError:
2822
- id = None
2823
- else:
2824
- id = id_or_name
2825
- name = str(id)
2826
-
2827
- if id:
2828
- try:
2829
- automation = await self.read_automation(id)
2830
- return automation
2831
- except prefect.exceptions.HTTPStatusError as e:
2832
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
2833
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
2834
-
2835
- automations = await self.read_automations()
2836
-
2837
- # Look for it by an exact name
2838
- for automation in automations:
2839
- if automation.name == name:
2840
- return automation
2841
-
2842
- # Look for it by a case-insensitive name
2843
- for automation in automations:
2844
- if automation.name.lower() == name.lower():
2845
- return automation
2846
-
2847
- return None
2848
-
2849
- async def read_automation(
2850
- self, automation_id: Union[UUID, str]
2851
- ) -> Optional[Automation]:
2852
- response = await self._client.get(f"/automations/{automation_id}")
2853
- if response.status_code == 404:
2854
- return None
2855
- response.raise_for_status()
2856
- return Automation.model_validate(response.json())
2857
-
2858
- async def read_automations_by_name(self, name: str) -> list[Automation]:
1361
+ ) -> list[WorkerFlowRunResponse]:
2859
1362
  """
2860
- Query the Prefect API for an automation by name. Only automations matching the provided name will be returned.
1363
+ Retrieves scheduled flow runs for the provided set of work pool queues.
2861
1364
 
2862
1365
  Args:
2863
- name: the name of the automation to query
1366
+ work_pool_name: The name of the work pool that the work pool
1367
+ queues are associated with.
1368
+ work_queue_names: The names of the work pool queues from which
1369
+ to get scheduled flow runs.
1370
+ scheduled_before: Datetime used to filter returned flow runs. Flow runs
1371
+ scheduled for after the given datetime string will not be returned.
2864
1372
 
2865
1373
  Returns:
2866
- a list of Automation model representations of the automations
1374
+ A list of worker flow run responses containing information about the
1375
+ retrieved flow runs.
2867
1376
  """
2868
- automation_filter = filters.AutomationFilter(
2869
- name=filters.AutomationFilterName(any_=[name])
2870
- )
1377
+ body: dict[str, Any] = {}
1378
+ if work_queue_names is not None:
1379
+ body["work_queue_names"] = list(work_queue_names)
1380
+ if scheduled_before:
1381
+ body["scheduled_before"] = str(scheduled_before)
2871
1382
 
2872
1383
  response = await self._client.post(
2873
- "/automations/filter",
2874
- json={
2875
- "sort": sorting.AutomationSort.UPDATED_DESC,
2876
- "automations": automation_filter.model_dump(mode="json")
2877
- if automation_filter
2878
- else None,
2879
- },
2880
- )
2881
-
2882
- response.raise_for_status()
2883
-
2884
- return pydantic.TypeAdapter(list[Automation]).validate_python(response.json())
2885
-
2886
- async def pause_automation(self, automation_id: UUID) -> None:
2887
- response = await self._client.patch(
2888
- f"/automations/{automation_id}", json={"enabled": False}
1384
+ f"/work_pools/{work_pool_name}/get_scheduled_flow_runs",
1385
+ json=body,
2889
1386
  )
2890
- response.raise_for_status()
2891
-
2892
- async def resume_automation(self, automation_id: UUID) -> None:
2893
- response = await self._client.patch(
2894
- f"/automations/{automation_id}", json={"enabled": True}
1387
+ return pydantic.TypeAdapter(list[WorkerFlowRunResponse]).validate_python(
1388
+ response.json()
2895
1389
  )
2896
- response.raise_for_status()
2897
-
2898
- async def delete_automation(self, automation_id: UUID) -> None:
2899
- response = await self._client.delete(f"/automations/{automation_id}")
2900
- if response.status_code == 404:
2901
- return
2902
1390
 
1391
+ async def read_worker_metadata(self) -> dict[str, Any]:
1392
+ """Reads worker metadata stored in Prefect collection registry."""
1393
+ response = await self._client.get("collections/views/aggregate-worker-metadata")
2903
1394
  response.raise_for_status()
2904
-
2905
- async def read_resource_related_automations(
2906
- self, resource_id: str
2907
- ) -> list[Automation]:
2908
- response = await self._client.get(f"/automations/related-to/{resource_id}")
2909
- response.raise_for_status()
2910
- return pydantic.TypeAdapter(list[Automation]).validate_python(response.json())
2911
-
2912
- async def delete_resource_owned_automations(self, resource_id: str) -> None:
2913
- await self._client.delete(f"/automations/owned-by/{resource_id}")
1395
+ return response.json()
2914
1396
 
2915
1397
  async def api_version(self) -> str:
2916
1398
  res = await self._client.get("/admin/version")
@@ -2940,18 +1422,6 @@ class PrefectClient(
2940
1422
  f"Major versions must match."
2941
1423
  )
2942
1424
 
2943
- async def update_flow_run_labels(
2944
- self, flow_run_id: UUID, labels: KeyValueLabelsField
2945
- ) -> None:
2946
- """
2947
- Updates the labels of a flow run.
2948
- """
2949
-
2950
- response = await self._client.patch(
2951
- f"/flow_runs/{flow_run_id}/labels", json=labels
2952
- )
2953
- response.raise_for_status()
2954
-
2955
1425
  async def __aenter__(self) -> Self:
2956
1426
  """
2957
1427
  Start the client.
@@ -3026,6 +1496,14 @@ class SyncPrefectClient(
3026
1496
  LogClient,
3027
1497
  VariableClient,
3028
1498
  ConcurrencyLimitClient,
1499
+ DeploymentClient,
1500
+ AutomationClient,
1501
+ SlaClient,
1502
+ FlowRunClient,
1503
+ FlowClient,
1504
+ BlocksDocumentClient,
1505
+ BlocksSchemaClient,
1506
+ BlocksTypeClient,
3029
1507
  ):
3030
1508
  """
3031
1509
  A synchronous client for interacting with the [Prefect REST API](/api-ref/rest-api/).
@@ -3284,288 +1762,6 @@ class SyncPrefectClient(
3284
1762
  f"Major versions must match."
3285
1763
  )
3286
1764
 
3287
- def create_flow(self, flow: "FlowObject[Any, Any]") -> UUID:
3288
- """
3289
- Create a flow in the Prefect API.
3290
-
3291
- Args:
3292
- flow: a [Flow][prefect.flows.Flow] object
3293
-
3294
- Raises:
3295
- httpx.RequestError: if a flow was not created for any reason
3296
-
3297
- Returns:
3298
- the ID of the flow in the backend
3299
- """
3300
- return self.create_flow_from_name(flow.name)
3301
-
3302
- def create_flow_from_name(self, flow_name: str) -> UUID:
3303
- """
3304
- Create a flow in the Prefect API.
3305
-
3306
- Args:
3307
- flow_name: the name of the new flow
3308
-
3309
- Raises:
3310
- httpx.RequestError: if a flow was not created for any reason
3311
-
3312
- Returns:
3313
- the ID of the flow in the backend
3314
- """
3315
- flow_data = FlowCreate(name=flow_name)
3316
- response = self._client.post("/flows/", json=flow_data.model_dump(mode="json"))
3317
-
3318
- flow_id = response.json().get("id")
3319
- if not flow_id:
3320
- raise httpx.RequestError(f"Malformed response: {response}")
3321
-
3322
- # Return the id of the created flow
3323
- return UUID(flow_id)
3324
-
3325
- def create_flow_run(
3326
- self,
3327
- flow: "FlowObject[Any, R]",
3328
- name: Optional[str] = None,
3329
- parameters: Optional[dict[str, Any]] = None,
3330
- context: Optional[dict[str, Any]] = None,
3331
- tags: Optional[Iterable[str]] = None,
3332
- parent_task_run_id: Optional[UUID] = None,
3333
- state: Optional["prefect.states.State[R]"] = None,
3334
- ) -> FlowRun:
3335
- """
3336
- Create a flow run for a flow.
3337
-
3338
- Args:
3339
- flow: The flow model to create the flow run for
3340
- name: An optional name for the flow run
3341
- parameters: Parameter overrides for this flow run.
3342
- context: Optional run context data
3343
- tags: a list of tags to apply to this flow run
3344
- parent_task_run_id: if a subflow run is being created, the placeholder task
3345
- run identifier in the parent flow
3346
- state: The initial state for the run. If not provided, defaults to
3347
- `Scheduled` for now. Should always be a `Scheduled` type.
3348
-
3349
- Raises:
3350
- httpx.RequestError: if the Prefect API does not successfully create a run for any reason
3351
-
3352
- Returns:
3353
- The flow run model
3354
- """
3355
- parameters = parameters or {}
3356
- context = context or {}
3357
-
3358
- if state is None:
3359
- state = prefect.states.Pending()
3360
-
3361
- # Retrieve the flow id
3362
- flow_id = self.create_flow(flow)
3363
-
3364
- flow_run_create = FlowRunCreate(
3365
- flow_id=flow_id,
3366
- flow_version=flow.version,
3367
- name=name,
3368
- parameters=parameters,
3369
- context=context,
3370
- tags=list(tags or []),
3371
- parent_task_run_id=parent_task_run_id,
3372
- state=state.to_state_create(),
3373
- empirical_policy=FlowRunPolicy(
3374
- retries=flow.retries,
3375
- retry_delay=int(flow.retry_delay_seconds or 0),
3376
- ),
3377
- )
3378
-
3379
- flow_run_create_json = flow_run_create.model_dump(mode="json")
3380
- response = self._client.post("/flow_runs/", json=flow_run_create_json)
3381
- flow_run = FlowRun.model_validate(response.json())
3382
-
3383
- # Restore the parameters to the local objects to retain expectations about
3384
- # Python objects
3385
- flow_run.parameters = parameters
3386
-
3387
- return flow_run
3388
-
3389
- def update_flow_run(
3390
- self,
3391
- flow_run_id: UUID,
3392
- flow_version: Optional[str] = None,
3393
- parameters: Optional[dict[str, Any]] = None,
3394
- name: Optional[str] = None,
3395
- tags: Optional[Iterable[str]] = None,
3396
- empirical_policy: Optional[FlowRunPolicy] = None,
3397
- infrastructure_pid: Optional[str] = None,
3398
- job_variables: Optional[dict[str, Any]] = None,
3399
- ) -> httpx.Response:
3400
- """
3401
- Update a flow run's details.
3402
-
3403
- Args:
3404
- flow_run_id: The identifier for the flow run to update.
3405
- flow_version: A new version string for the flow run.
3406
- parameters: A dictionary of parameter values for the flow run. This will not
3407
- be merged with any existing parameters.
3408
- name: A new name for the flow run.
3409
- empirical_policy: A new flow run orchestration policy. This will not be
3410
- merged with any existing policy.
3411
- tags: An iterable of new tags for the flow run. These will not be merged with
3412
- any existing tags.
3413
- infrastructure_pid: The id of flow run as returned by an
3414
- infrastructure block.
3415
-
3416
- Returns:
3417
- an `httpx.Response` object from the PATCH request
3418
- """
3419
- params: dict[str, Any] = {}
3420
- if flow_version is not None:
3421
- params["flow_version"] = flow_version
3422
- if parameters is not None:
3423
- params["parameters"] = parameters
3424
- if name is not None:
3425
- params["name"] = name
3426
- if tags is not None:
3427
- params["tags"] = tags
3428
- if empirical_policy is not None:
3429
- params["empirical_policy"] = empirical_policy.model_dump(
3430
- mode="json", exclude_unset=True
3431
- )
3432
- if infrastructure_pid:
3433
- params["infrastructure_pid"] = infrastructure_pid
3434
- if job_variables is not None:
3435
- params["job_variables"] = job_variables
3436
-
3437
- flow_run_data = FlowRunUpdate(**params)
3438
-
3439
- return self._client.patch(
3440
- f"/flow_runs/{flow_run_id}",
3441
- json=flow_run_data.model_dump(mode="json", exclude_unset=True),
3442
- )
3443
-
3444
- def read_flow_run(self, flow_run_id: UUID) -> FlowRun:
3445
- """
3446
- Query the Prefect API for a flow run by id.
3447
-
3448
- Args:
3449
- flow_run_id: the flow run ID of interest
3450
-
3451
- Returns:
3452
- a Flow Run model representation of the flow run
3453
- """
3454
- try:
3455
- response = self._client.get(f"/flow_runs/{flow_run_id}")
3456
- except httpx.HTTPStatusError as e:
3457
- if e.response.status_code == 404:
3458
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
3459
- else:
3460
- raise
3461
- return FlowRun.model_validate(response.json())
3462
-
3463
- def read_flow_runs(
3464
- self,
3465
- *,
3466
- flow_filter: Optional[FlowFilter] = None,
3467
- flow_run_filter: Optional[FlowRunFilter] = None,
3468
- task_run_filter: Optional[TaskRunFilter] = None,
3469
- deployment_filter: Optional[DeploymentFilter] = None,
3470
- work_pool_filter: Optional[WorkPoolFilter] = None,
3471
- work_queue_filter: Optional[WorkQueueFilter] = None,
3472
- sort: Optional[FlowRunSort] = None,
3473
- limit: Optional[int] = None,
3474
- offset: int = 0,
3475
- ) -> list[FlowRun]:
3476
- """
3477
- Query the Prefect API for flow runs. Only flow runs matching all criteria will
3478
- be returned.
3479
-
3480
- Args:
3481
- flow_filter: filter criteria for flows
3482
- flow_run_filter: filter criteria for flow runs
3483
- task_run_filter: filter criteria for task runs
3484
- deployment_filter: filter criteria for deployments
3485
- work_pool_filter: filter criteria for work pools
3486
- work_queue_filter: filter criteria for work pool queues
3487
- sort: sort criteria for the flow runs
3488
- limit: limit for the flow run query
3489
- offset: offset for the flow run query
3490
-
3491
- Returns:
3492
- a list of Flow Run model representations
3493
- of the flow runs
3494
- """
3495
- body: dict[str, Any] = {
3496
- "flows": flow_filter.model_dump(mode="json") if flow_filter else None,
3497
- "flow_runs": (
3498
- flow_run_filter.model_dump(mode="json", exclude_unset=True)
3499
- if flow_run_filter
3500
- else None
3501
- ),
3502
- "task_runs": (
3503
- task_run_filter.model_dump(mode="json") if task_run_filter else None
3504
- ),
3505
- "deployments": (
3506
- deployment_filter.model_dump(mode="json") if deployment_filter else None
3507
- ),
3508
- "work_pools": (
3509
- work_pool_filter.model_dump(mode="json") if work_pool_filter else None
3510
- ),
3511
- "work_pool_queues": (
3512
- work_queue_filter.model_dump(mode="json") if work_queue_filter else None
3513
- ),
3514
- "sort": sort,
3515
- "limit": limit,
3516
- "offset": offset,
3517
- }
3518
-
3519
- response = self._client.post("/flow_runs/filter", json=body)
3520
- return pydantic.TypeAdapter(list[FlowRun]).validate_python(response.json())
3521
-
3522
- def set_flow_run_state(
3523
- self,
3524
- flow_run_id: UUID,
3525
- state: "prefect.states.State[T]",
3526
- force: bool = False,
3527
- ) -> OrchestrationResult[T]:
3528
- """
3529
- Set the state of a flow run.
3530
-
3531
- Args:
3532
- flow_run_id: the id of the flow run
3533
- state: the state to set
3534
- force: if True, disregard orchestration logic when setting the state,
3535
- forcing the Prefect API to accept the state
3536
-
3537
- Returns:
3538
- an OrchestrationResult model representation of state orchestration output
3539
- """
3540
- state_create = state.to_state_create()
3541
- state_create.state_details.flow_run_id = flow_run_id
3542
- state_create.state_details.transition_id = uuid4()
3543
- try:
3544
- response = self._client.post(
3545
- f"/flow_runs/{flow_run_id}/set_state",
3546
- json=dict(
3547
- state=state_create.model_dump(mode="json", serialize_as_any=True),
3548
- force=force,
3549
- ),
3550
- )
3551
- except httpx.HTTPStatusError as e:
3552
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
3553
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
3554
- else:
3555
- raise
3556
-
3557
- result: OrchestrationResult[T] = OrchestrationResult.model_validate(
3558
- response.json()
3559
- )
3560
- return result
3561
-
3562
- def set_flow_run_name(self, flow_run_id: UUID, name: str) -> httpx.Response:
3563
- flow_run_data = FlowRunUpdate(name=name)
3564
- return self._client.patch(
3565
- f"/flow_runs/{flow_run_id}",
3566
- json=flow_run_data.model_dump(mode="json", exclude_unset=True),
3567
- )
3568
-
3569
1765
  def set_task_run_name(self, task_run_id: UUID, name: str) -> httpx.Response:
3570
1766
  task_run_data = TaskRunUpdate(name=name)
3571
1767
  return self._client.patch(
@@ -3759,102 +1955,3 @@ class SyncPrefectClient(
3759
1955
  return pydantic.TypeAdapter(list[prefect.states.State]).validate_python(
3760
1956
  response.json()
3761
1957
  )
3762
-
3763
- def read_deployment(
3764
- self,
3765
- deployment_id: UUID,
3766
- ) -> DeploymentResponse:
3767
- """
3768
- Query the Prefect API for a deployment by id.
3769
-
3770
- Args:
3771
- deployment_id: the deployment ID of interest
3772
-
3773
- Returns:
3774
- a [Deployment model][prefect.client.schemas.objects.Deployment] representation of the deployment
3775
- """
3776
- try:
3777
- response = self._client.get(f"/deployments/{deployment_id}")
3778
- except httpx.HTTPStatusError as e:
3779
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
3780
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
3781
- else:
3782
- raise
3783
- return DeploymentResponse.model_validate(response.json())
3784
-
3785
- def read_deployment_by_name(
3786
- self,
3787
- name: str,
3788
- ) -> DeploymentResponse:
3789
- """
3790
- Query the Prefect API for a deployment by name.
3791
-
3792
- Args:
3793
- name: A deployed flow's name: <FLOW_NAME>/<DEPLOYMENT_NAME>
3794
-
3795
- Raises:
3796
- prefect.exceptions.ObjectNotFound: If request returns 404
3797
- httpx.RequestError: If request fails
3798
-
3799
- Returns:
3800
- a Deployment model representation of the deployment
3801
- """
3802
- try:
3803
- response = self._client.get(f"/deployments/name/{name}")
3804
- except httpx.HTTPStatusError as e:
3805
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
3806
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
3807
- else:
3808
- raise
3809
-
3810
- return DeploymentResponse.model_validate(response.json())
3811
-
3812
- def update_flow_run_labels(
3813
- self, flow_run_id: UUID, labels: KeyValueLabelsField
3814
- ) -> None:
3815
- """
3816
- Updates the labels of a flow run.
3817
- """
3818
- response = self._client.patch(
3819
- f"/flow_runs/{flow_run_id}/labels",
3820
- json=labels,
3821
- )
3822
- response.raise_for_status()
3823
-
3824
- def read_block_document_by_name(
3825
- self,
3826
- name: str,
3827
- block_type_slug: str,
3828
- include_secrets: bool = True,
3829
- ) -> BlockDocument:
3830
- """
3831
- Read the block document with the specified name that corresponds to a
3832
- specific block type name.
3833
-
3834
- Args:
3835
- name: The block document name.
3836
- block_type_slug: The block type slug.
3837
- include_secrets (bool): whether to include secret values
3838
- on the Block, corresponding to Pydantic's `SecretStr` and
3839
- `SecretBytes` fields. These fields are automatically obfuscated
3840
- by Pydantic, but users can additionally choose not to receive
3841
- their values from the API. Note that any business logic on the
3842
- Block may not work if this is `False`.
3843
-
3844
- Raises:
3845
- httpx.RequestError: if the block document was not found for any reason
3846
-
3847
- Returns:
3848
- A block document or None.
3849
- """
3850
- try:
3851
- response = self._client.get(
3852
- f"/block_types/slug/{block_type_slug}/block_documents/name/{name}",
3853
- params=dict(include_secrets=include_secrets),
3854
- )
3855
- except httpx.HTTPStatusError as e:
3856
- if e.response.status_code == status.HTTP_404_NOT_FOUND:
3857
- raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
3858
- else:
3859
- raise
3860
- return BlockDocument.model_validate(response.json())