prefect-client 3.1.10__py3-none-any.whl → 3.1.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. prefect/_experimental/lineage.py +7 -8
  2. prefect/_experimental/sla/__init__.py +0 -0
  3. prefect/_experimental/sla/client.py +66 -0
  4. prefect/_experimental/sla/objects.py +53 -0
  5. prefect/_internal/_logging.py +15 -3
  6. prefect/_internal/compatibility/async_dispatch.py +22 -16
  7. prefect/_internal/compatibility/deprecated.py +42 -18
  8. prefect/_internal/compatibility/migration.py +2 -2
  9. prefect/_internal/concurrency/inspection.py +12 -14
  10. prefect/_internal/concurrency/primitives.py +2 -2
  11. prefect/_internal/concurrency/services.py +154 -80
  12. prefect/_internal/concurrency/waiters.py +13 -9
  13. prefect/_internal/pydantic/annotations/pendulum.py +7 -7
  14. prefect/_internal/pytz.py +4 -3
  15. prefect/_internal/retries.py +10 -5
  16. prefect/_internal/schemas/bases.py +19 -10
  17. prefect/_internal/schemas/validators.py +227 -388
  18. prefect/_version.py +3 -3
  19. prefect/automations.py +236 -30
  20. prefect/blocks/__init__.py +3 -3
  21. prefect/blocks/abstract.py +53 -30
  22. prefect/blocks/core.py +183 -84
  23. prefect/blocks/notifications.py +133 -73
  24. prefect/blocks/redis.py +13 -9
  25. prefect/blocks/system.py +24 -11
  26. prefect/blocks/webhook.py +7 -5
  27. prefect/cache_policies.py +3 -2
  28. prefect/client/orchestration/__init__.py +1957 -0
  29. prefect/client/orchestration/_artifacts/__init__.py +0 -0
  30. prefect/client/orchestration/_artifacts/client.py +239 -0
  31. prefect/client/orchestration/_automations/__init__.py +0 -0
  32. prefect/client/orchestration/_automations/client.py +329 -0
  33. prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
  34. prefect/client/orchestration/_blocks_documents/client.py +334 -0
  35. prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
  36. prefect/client/orchestration/_blocks_schemas/client.py +200 -0
  37. prefect/client/orchestration/_blocks_types/__init__.py +0 -0
  38. prefect/client/orchestration/_blocks_types/client.py +380 -0
  39. prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
  40. prefect/client/orchestration/_concurrency_limits/client.py +762 -0
  41. prefect/client/orchestration/_deployments/__init__.py +0 -0
  42. prefect/client/orchestration/_deployments/client.py +1128 -0
  43. prefect/client/orchestration/_flow_runs/__init__.py +0 -0
  44. prefect/client/orchestration/_flow_runs/client.py +903 -0
  45. prefect/client/orchestration/_flows/__init__.py +0 -0
  46. prefect/client/orchestration/_flows/client.py +343 -0
  47. prefect/client/orchestration/_logs/__init__.py +0 -0
  48. prefect/client/orchestration/_logs/client.py +97 -0
  49. prefect/client/orchestration/_variables/__init__.py +0 -0
  50. prefect/client/orchestration/_variables/client.py +157 -0
  51. prefect/client/orchestration/base.py +46 -0
  52. prefect/client/orchestration/routes.py +145 -0
  53. prefect/client/schemas/__init__.py +68 -28
  54. prefect/client/schemas/actions.py +2 -2
  55. prefect/client/schemas/filters.py +5 -0
  56. prefect/client/schemas/objects.py +8 -15
  57. prefect/client/schemas/schedules.py +22 -10
  58. prefect/concurrency/_asyncio.py +87 -0
  59. prefect/concurrency/{events.py → _events.py} +10 -10
  60. prefect/concurrency/asyncio.py +20 -104
  61. prefect/concurrency/context.py +6 -4
  62. prefect/concurrency/services.py +26 -74
  63. prefect/concurrency/sync.py +23 -44
  64. prefect/concurrency/v1/_asyncio.py +63 -0
  65. prefect/concurrency/v1/{events.py → _events.py} +13 -15
  66. prefect/concurrency/v1/asyncio.py +27 -80
  67. prefect/concurrency/v1/context.py +6 -4
  68. prefect/concurrency/v1/services.py +33 -79
  69. prefect/concurrency/v1/sync.py +18 -37
  70. prefect/context.py +66 -45
  71. prefect/deployments/base.py +10 -144
  72. prefect/deployments/flow_runs.py +12 -2
  73. prefect/deployments/runner.py +53 -4
  74. prefect/deployments/steps/pull.py +13 -0
  75. prefect/engine.py +17 -4
  76. prefect/events/clients.py +7 -1
  77. prefect/events/schemas/events.py +3 -2
  78. prefect/filesystems.py +6 -2
  79. prefect/flow_engine.py +101 -85
  80. prefect/flows.py +10 -1
  81. prefect/input/run_input.py +2 -1
  82. prefect/logging/logging.yml +1 -1
  83. prefect/main.py +1 -3
  84. prefect/results.py +2 -307
  85. prefect/runner/runner.py +4 -2
  86. prefect/runner/storage.py +87 -21
  87. prefect/serializers.py +32 -25
  88. prefect/settings/legacy.py +4 -4
  89. prefect/settings/models/api.py +3 -3
  90. prefect/settings/models/cli.py +3 -3
  91. prefect/settings/models/client.py +5 -3
  92. prefect/settings/models/cloud.py +8 -3
  93. prefect/settings/models/deployments.py +3 -3
  94. prefect/settings/models/experiments.py +4 -7
  95. prefect/settings/models/flows.py +3 -3
  96. prefect/settings/models/internal.py +4 -2
  97. prefect/settings/models/logging.py +4 -3
  98. prefect/settings/models/results.py +3 -3
  99. prefect/settings/models/root.py +3 -2
  100. prefect/settings/models/runner.py +4 -4
  101. prefect/settings/models/server/api.py +3 -3
  102. prefect/settings/models/server/database.py +11 -4
  103. prefect/settings/models/server/deployments.py +6 -2
  104. prefect/settings/models/server/ephemeral.py +4 -2
  105. prefect/settings/models/server/events.py +3 -2
  106. prefect/settings/models/server/flow_run_graph.py +6 -2
  107. prefect/settings/models/server/root.py +3 -3
  108. prefect/settings/models/server/services.py +26 -11
  109. prefect/settings/models/server/tasks.py +6 -3
  110. prefect/settings/models/server/ui.py +3 -3
  111. prefect/settings/models/tasks.py +5 -5
  112. prefect/settings/models/testing.py +3 -3
  113. prefect/settings/models/worker.py +5 -3
  114. prefect/settings/profiles.py +15 -2
  115. prefect/states.py +61 -45
  116. prefect/task_engine.py +54 -75
  117. prefect/task_runners.py +56 -55
  118. prefect/task_worker.py +2 -2
  119. prefect/tasks.py +90 -36
  120. prefect/telemetry/bootstrap.py +10 -9
  121. prefect/telemetry/run_telemetry.py +13 -8
  122. prefect/telemetry/services.py +4 -0
  123. prefect/transactions.py +4 -15
  124. prefect/utilities/_git.py +34 -0
  125. prefect/utilities/asyncutils.py +1 -1
  126. prefect/utilities/engine.py +3 -19
  127. prefect/utilities/generics.py +18 -0
  128. prefect/utilities/templating.py +25 -1
  129. prefect/workers/base.py +6 -3
  130. prefect/workers/process.py +1 -1
  131. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/METADATA +2 -2
  132. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/RECORD +135 -109
  133. prefect/client/orchestration.py +0 -4523
  134. prefect/records/__init__.py +0 -1
  135. prefect/records/base.py +0 -235
  136. prefect/records/filesystem.py +0 -213
  137. prefect/records/memory.py +0 -184
  138. prefect/records/result_store.py +0 -70
  139. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/LICENSE +0 -0
  140. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/WHEEL +0 -0
  141. {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/top_level.txt +0 -0
File without changes
@@ -0,0 +1,239 @@
1
+ from typing import TYPE_CHECKING, Annotated, Optional
2
+
3
+ from httpx import HTTPStatusError
4
+ from pydantic import Field
5
+ from typing_extensions import TypedDict, Unpack
6
+
7
+ from prefect.client.orchestration.base import BaseAsyncClient, BaseClient
8
+ from prefect.exceptions import ObjectNotFound
9
+
10
+ if TYPE_CHECKING:
11
+ from uuid import UUID
12
+
13
+ from prefect.client.schemas.actions import ArtifactCreate, ArtifactUpdate
14
+ from prefect.client.schemas.filters import (
15
+ ArtifactCollectionFilter,
16
+ ArtifactFilter,
17
+ FlowRunFilter,
18
+ TaskRunFilter,
19
+ )
20
+ from prefect.client.schemas.objects import Artifact, ArtifactCollection
21
+ from prefect.client.schemas.sorting import ArtifactCollectionSort, ArtifactSort
22
+
23
+
24
+ class BaseArtifactReadParams(TypedDict, total=False):
25
+ flow_run_filter: Annotated[Optional["FlowRunFilter"], Field(default=None)]
26
+ task_run_filter: Annotated[Optional["TaskRunFilter"], Field(default=None)]
27
+ limit: Annotated[Optional[int], Field(default=None)]
28
+ offset: Annotated[int, Field(default=0)]
29
+
30
+
31
+ class ArtifactReadParams(BaseArtifactReadParams, total=False):
32
+ artifact_filter: Annotated[Optional["ArtifactFilter"], Field(default=None)]
33
+ sort: Annotated[Optional["ArtifactSort"], Field(default=None)]
34
+
35
+
36
+ class ArtifactCollectionReadParams(BaseArtifactReadParams, total=False):
37
+ artifact_filter: Annotated[
38
+ Optional["ArtifactCollectionFilter"], Field(default=None)
39
+ ]
40
+ sort: Annotated[Optional["ArtifactCollectionSort"], Field(default=None)]
41
+
42
+
43
+ class ArtifactClient(BaseClient):
44
+ def create_artifact(self, artifact: "ArtifactCreate") -> "Artifact":
45
+ response = self.request(
46
+ "POST",
47
+ "/artifacts/",
48
+ json=artifact.model_dump(mode="json", exclude_unset=True),
49
+ )
50
+ from prefect.client.schemas.objects import Artifact
51
+
52
+ return Artifact.model_validate(response.json())
53
+
54
+ def update_artifact(self, artifact_id: "UUID", artifact: "ArtifactUpdate") -> None:
55
+ self.request(
56
+ "PATCH",
57
+ "/artifacts/{id}",
58
+ json=artifact.model_dump(mode="json", exclude_unset=True),
59
+ path_params={"id": artifact_id},
60
+ )
61
+ return None
62
+
63
+ def delete_artifact(self, artifact_id: "UUID") -> None:
64
+ try:
65
+ self.request(
66
+ "DELETE",
67
+ "/artifacts/{id}",
68
+ path_params={"id": artifact_id},
69
+ )
70
+ except HTTPStatusError as e:
71
+ if e.response.status_code == 404:
72
+ raise ObjectNotFound(http_exc=e) from e
73
+ else:
74
+ raise
75
+ return None
76
+
77
+ def read_artifacts(
78
+ self, **kwargs: Unpack["ArtifactReadParams"]
79
+ ) -> list["Artifact"]:
80
+ response = self.request(
81
+ "POST",
82
+ "/artifacts/filter",
83
+ json={
84
+ "artifacts": (
85
+ artifact_filter.model_dump(mode="json", exclude_unset=True)
86
+ if (artifact_filter := kwargs.get("artifact_filter"))
87
+ else None
88
+ ),
89
+ "flow_runs": (
90
+ flow_run_filter.model_dump(mode="json", exclude_unset=True)
91
+ if (flow_run_filter := kwargs.get("flow_run_filter"))
92
+ else None
93
+ ),
94
+ "task_runs": (
95
+ task_run_filter.model_dump(mode="json", exclude_unset=True)
96
+ if (task_run_filter := kwargs.get("task_run_filter"))
97
+ else None
98
+ ),
99
+ "limit": kwargs.get("limit"),
100
+ "offset": kwargs.get("offset"),
101
+ "sort": kwargs.get("sort"),
102
+ },
103
+ )
104
+ from prefect.client.schemas.objects import Artifact
105
+
106
+ return Artifact.model_validate_list(response.json())
107
+
108
+
109
+ class ArtifactAsyncClient(BaseAsyncClient):
110
+ async def create_artifact(self, artifact: "ArtifactCreate") -> "Artifact":
111
+ response = await self.request(
112
+ "POST",
113
+ "/artifacts/",
114
+ json=artifact.model_dump(mode="json", exclude_unset=True),
115
+ )
116
+ from prefect.client.schemas.objects import Artifact
117
+
118
+ return Artifact.model_validate(response.json())
119
+
120
+ async def update_artifact(
121
+ self, artifact_id: "UUID", artifact: "ArtifactUpdate"
122
+ ) -> None:
123
+ await self.request(
124
+ "PATCH",
125
+ "/artifacts/{id}",
126
+ path_params={"id": artifact_id},
127
+ json=artifact.model_dump(mode="json", exclude_unset=True),
128
+ )
129
+ return None
130
+
131
+ async def read_artifacts(
132
+ self, **kwargs: Unpack["ArtifactReadParams"]
133
+ ) -> list["Artifact"]:
134
+ response = await self.request(
135
+ "POST",
136
+ "/artifacts/filter",
137
+ json={
138
+ "artifacts": (
139
+ artifact_filter.model_dump(mode="json", exclude_unset=True)
140
+ if (artifact_filter := kwargs.get("artifact_filter"))
141
+ else None
142
+ ),
143
+ "flow_runs": (
144
+ flow_run_filter.model_dump(mode="json", exclude_unset=True)
145
+ if (flow_run_filter := kwargs.get("flow_run_filter"))
146
+ else None
147
+ ),
148
+ "task_runs": (
149
+ task_run_filter.model_dump(mode="json", exclude_unset=True)
150
+ if (task_run_filter := kwargs.get("task_run_filter"))
151
+ else None
152
+ ),
153
+ "limit": kwargs.get("limit", None),
154
+ "offset": kwargs.get("offset", 0),
155
+ "sort": kwargs.get("sort", None),
156
+ },
157
+ )
158
+ from prefect.client.schemas.objects import Artifact
159
+
160
+ return Artifact.model_validate_list(response.json())
161
+
162
+ async def delete_artifact(self, artifact_id: "UUID") -> None:
163
+ try:
164
+ await self.request(
165
+ "DELETE",
166
+ "/artifacts/{id}",
167
+ path_params={"id": artifact_id},
168
+ )
169
+ except HTTPStatusError as e:
170
+ if e.response.status_code == 404:
171
+ raise ObjectNotFound(http_exc=e) from e
172
+ else:
173
+ raise
174
+
175
+
176
+ class ArtifactCollectionClient(BaseClient):
177
+ def read_latest_artifacts(
178
+ self, **kwargs: Unpack["ArtifactCollectionReadParams"]
179
+ ) -> list["ArtifactCollection"]:
180
+ response = self.request(
181
+ "POST",
182
+ "/artifacts/latest/filter",
183
+ json={
184
+ "artifacts": (
185
+ artifact_filter.model_dump(mode="json", exclude_unset=True)
186
+ if (artifact_filter := kwargs.get("artifact_filter"))
187
+ else None
188
+ ),
189
+ "flow_runs": (
190
+ flow_run_filter.model_dump(mode="json", exclude_unset=True)
191
+ if (flow_run_filter := kwargs.get("flow_run_filter"))
192
+ else None
193
+ ),
194
+ "task_runs": (
195
+ task_run_filter.model_dump(mode="json", exclude_unset=True)
196
+ if (task_run_filter := kwargs.get("task_run_filter"))
197
+ else None
198
+ ),
199
+ "limit": kwargs.get("limit", None),
200
+ "offset": kwargs.get("offset", 0),
201
+ "sort": kwargs.get("sort", None),
202
+ },
203
+ )
204
+ from prefect.client.schemas.objects import ArtifactCollection
205
+
206
+ return ArtifactCollection.model_validate_list(response.json())
207
+
208
+
209
+ class ArtifactCollectionAsyncClient(BaseAsyncClient):
210
+ async def read_latest_artifacts(
211
+ self, **kwargs: Unpack["ArtifactCollectionReadParams"]
212
+ ) -> list["ArtifactCollection"]:
213
+ response = await self.request(
214
+ "POST",
215
+ "/artifacts/latest/filter",
216
+ json={
217
+ "artifacts": (
218
+ artifact_filter.model_dump(mode="json", exclude_unset=True)
219
+ if (artifact_filter := kwargs.get("artifact_filter"))
220
+ else None
221
+ ),
222
+ "flow_runs": (
223
+ flow_run_filter.model_dump(mode="json", exclude_unset=True)
224
+ if (flow_run_filter := kwargs.get("flow_run_filter"))
225
+ else None
226
+ ),
227
+ "task_runs": (
228
+ task_run_filter.model_dump(mode="json", exclude_unset=True)
229
+ if (task_run_filter := kwargs.get("task_run_filter"))
230
+ else None
231
+ ),
232
+ "limit": kwargs.get("limit", None),
233
+ "offset": kwargs.get("offset", 0),
234
+ "sort": kwargs.get("sort", None),
235
+ },
236
+ )
237
+ from prefect.client.schemas.objects import ArtifactCollection
238
+
239
+ return ArtifactCollection.model_validate_list(response.json())
File without changes
@@ -0,0 +1,329 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from httpx import HTTPStatusError
6
+
7
+ from prefect.client.orchestration.base import BaseAsyncClient, BaseClient
8
+ from prefect.exceptions import ObjectNotFound
9
+
10
+ if TYPE_CHECKING:
11
+ from uuid import UUID
12
+
13
+ from prefect.events.schemas.automations import Automation, AutomationCore
14
+
15
+
16
+ class AutomationClient(BaseClient):
17
+ def create_automation(self, automation: "AutomationCore") -> "UUID":
18
+ """Creates an automation in Prefect Cloud."""
19
+ response = self.request(
20
+ "POST",
21
+ "/automations/",
22
+ json=automation.model_dump(mode="json"),
23
+ )
24
+ from uuid import UUID
25
+
26
+ return UUID(response.json()["id"])
27
+
28
+ def update_automation(
29
+ self, automation_id: "UUID", automation: "AutomationCore"
30
+ ) -> None:
31
+ """Updates an automation in Prefect Cloud."""
32
+ response = self.request(
33
+ "PUT",
34
+ "/automations/{id}",
35
+ path_params={"id": automation_id},
36
+ json=automation.model_dump(mode="json", exclude_unset=True),
37
+ )
38
+ response.raise_for_status()
39
+
40
+ def read_automations(self) -> list["Automation"]:
41
+ response = self.request("POST", "/automations/filter")
42
+ response.raise_for_status()
43
+ from prefect.events.schemas.automations import Automation
44
+
45
+ return Automation.model_validate_list(response.json())
46
+
47
+ def find_automation(self, id_or_name: "str | UUID") -> "Automation | None":
48
+ if isinstance(id_or_name, str):
49
+ name = id_or_name
50
+ try:
51
+ id = UUID(id_or_name)
52
+ except ValueError:
53
+ id = None
54
+ else:
55
+ id = id_or_name
56
+ name = str(id)
57
+
58
+ if id:
59
+ try:
60
+ automation = self.read_automation(id)
61
+ return automation
62
+ except HTTPStatusError as e:
63
+ if e.response.status_code == 404:
64
+ raise ObjectNotFound(http_exc=e) from e
65
+
66
+ automations = self.read_automations()
67
+
68
+ # Look for it by an exact name
69
+ for automation in automations:
70
+ if automation.name == name:
71
+ return automation
72
+
73
+ # Look for it by a case-insensitive name
74
+ for automation in automations:
75
+ if automation.name.lower() == name.lower():
76
+ return automation
77
+
78
+ return None
79
+
80
+ def read_automation(self, automation_id: "UUID | str") -> "Automation | None":
81
+ response = self.request(
82
+ "GET", "/automations/{id}", path_params={"id": automation_id}
83
+ )
84
+ if response.status_code == 404:
85
+ return None
86
+ response.raise_for_status()
87
+ from prefect.events.schemas.automations import Automation
88
+
89
+ return Automation.model_validate(response.json())
90
+
91
+ def read_automations_by_name(self, name: str) -> list["Automation"]:
92
+ """
93
+ Query the Prefect API for an automation by name. Only automations matching the provided name will be returned.
94
+
95
+ Args:
96
+ name: the name of the automation to query
97
+
98
+ Returns:
99
+ a list of Automation model representations of the automations
100
+ """
101
+ from prefect.client.schemas.sorting import AutomationSort
102
+ from prefect.events.filters import (
103
+ AutomationFilter,
104
+ AutomationFilterName,
105
+ )
106
+
107
+ automation_filter = AutomationFilter(name=AutomationFilterName(any_=[name]))
108
+
109
+ response = self.request(
110
+ "POST",
111
+ "/automations/filter",
112
+ json={
113
+ "sort": AutomationSort.UPDATED_DESC,
114
+ "automations": automation_filter.model_dump(mode="json")
115
+ if automation_filter
116
+ else None,
117
+ },
118
+ )
119
+
120
+ response.raise_for_status()
121
+ from prefect.events.schemas.automations import Automation
122
+
123
+ return Automation.model_validate_list(response.json())
124
+
125
+ def pause_automation(self, automation_id: "UUID") -> None:
126
+ response = self.request(
127
+ "PATCH",
128
+ "/automations/{id}",
129
+ path_params={"id": automation_id},
130
+ json={"enabled": False},
131
+ )
132
+ response.raise_for_status()
133
+
134
+ def resume_automation(self, automation_id: "UUID") -> None:
135
+ response = self.request(
136
+ "PATCH",
137
+ "/automations/{id}",
138
+ path_params={"id": automation_id},
139
+ json={"enabled": True},
140
+ )
141
+ response.raise_for_status()
142
+
143
+ def delete_automation(self, automation_id: "UUID") -> None:
144
+ response = self.request(
145
+ "DELETE",
146
+ "/automations/{id}",
147
+ path_params={"id": automation_id},
148
+ )
149
+ if response.status_code == 404:
150
+ return
151
+
152
+ response.raise_for_status()
153
+
154
+ def read_resource_related_automations(self, resource_id: str) -> list["Automation"]:
155
+ response = self.request(
156
+ "GET",
157
+ "/automations/related-to/{resource_id}",
158
+ path_params={"resource_id": resource_id},
159
+ )
160
+ response.raise_for_status()
161
+ from prefect.events.schemas.automations import Automation
162
+
163
+ return Automation.model_validate_list(response.json())
164
+
165
+ def delete_resource_owned_automations(self, resource_id: str) -> None:
166
+ self.request(
167
+ "DELETE",
168
+ "/automations/owned-by/{resource_id}",
169
+ path_params={"resource_id": resource_id},
170
+ )
171
+
172
+
173
+ class AutomationAsyncClient(BaseAsyncClient):
174
+ async def create_automation(self, automation: "AutomationCore") -> "UUID":
175
+ """Creates an automation in Prefect Cloud."""
176
+ response = await self.request(
177
+ "POST",
178
+ "/automations/",
179
+ json=automation.model_dump(mode="json"),
180
+ )
181
+ from uuid import UUID
182
+
183
+ return UUID(response.json()["id"])
184
+
185
+ async def update_automation(
186
+ self, automation_id: "UUID", automation: "AutomationCore"
187
+ ) -> None:
188
+ """Updates an automation in Prefect Cloud."""
189
+ response = await self.request(
190
+ "PUT",
191
+ "/automations/{id}",
192
+ path_params={"id": automation_id},
193
+ json=automation.model_dump(mode="json", exclude_unset=True),
194
+ )
195
+ response.raise_for_status()
196
+
197
+ async def read_automations(self) -> list["Automation"]:
198
+ response = await self.request("POST", "/automations/filter")
199
+ response.raise_for_status()
200
+ from prefect.events.schemas.automations import Automation
201
+
202
+ return Automation.model_validate_list(response.json())
203
+
204
+ async def find_automation(self, id_or_name: "str | UUID") -> "Automation | None":
205
+ if isinstance(id_or_name, str):
206
+ name = id_or_name
207
+ try:
208
+ id = UUID(id_or_name)
209
+ except ValueError:
210
+ id = None
211
+ else:
212
+ id = id_or_name
213
+ name = str(id)
214
+
215
+ if id:
216
+ try:
217
+ automation = await self.read_automation(id)
218
+ return automation
219
+ except HTTPStatusError as e:
220
+ if e.response.status_code == 404:
221
+ raise ObjectNotFound(http_exc=e) from e
222
+
223
+ automations = await self.read_automations()
224
+
225
+ # Look for it by an exact name
226
+ for automation in automations:
227
+ if automation.name == name:
228
+ return automation
229
+
230
+ # Look for it by a case-insensitive name
231
+ for automation in automations:
232
+ if automation.name.lower() == name.lower():
233
+ return automation
234
+
235
+ return None
236
+
237
+ async def read_automation(self, automation_id: "UUID | str") -> "Automation | None":
238
+ response = await self.request(
239
+ "GET", "/automations/{id}", path_params={"id": automation_id}
240
+ )
241
+ if response.status_code == 404:
242
+ return None
243
+ response.raise_for_status()
244
+ from prefect.events.schemas.automations import Automation
245
+
246
+ return Automation.model_validate(response.json())
247
+
248
+ async def read_automations_by_name(self, name: str) -> list["Automation"]:
249
+ """
250
+ Query the Prefect API for an automation by name. Only automations matching the provided name will be returned.
251
+
252
+ Args:
253
+ name: the name of the automation to query
254
+
255
+ Returns:
256
+ a list of Automation model representations of the automations
257
+ """
258
+ from prefect.client.schemas.sorting import AutomationSort
259
+ from prefect.events.filters import (
260
+ AutomationFilter,
261
+ AutomationFilterName,
262
+ )
263
+
264
+ automation_filter = AutomationFilter(name=AutomationFilterName(any_=[name]))
265
+
266
+ response = await self.request(
267
+ "POST",
268
+ "/automations/filter",
269
+ json={
270
+ "sort": AutomationSort.UPDATED_DESC,
271
+ "automations": automation_filter.model_dump(mode="json")
272
+ if automation_filter
273
+ else None,
274
+ },
275
+ )
276
+
277
+ response.raise_for_status()
278
+ from prefect.events.schemas.automations import Automation
279
+
280
+ return Automation.model_validate_list(response.json())
281
+
282
+ async def pause_automation(self, automation_id: "UUID") -> None:
283
+ response = await self.request(
284
+ "PATCH",
285
+ "/automations/{id}",
286
+ path_params={"id": automation_id},
287
+ json={"enabled": False},
288
+ )
289
+ response.raise_for_status()
290
+
291
+ async def resume_automation(self, automation_id: "UUID") -> None:
292
+ response = await self.request(
293
+ "PATCH",
294
+ "/automations/{id}",
295
+ path_params={"id": automation_id},
296
+ json={"enabled": True},
297
+ )
298
+ response.raise_for_status()
299
+
300
+ async def delete_automation(self, automation_id: "UUID") -> None:
301
+ response = await self.request(
302
+ "DELETE",
303
+ "/automations/{id}",
304
+ path_params={"id": automation_id},
305
+ )
306
+ if response.status_code == 404:
307
+ return
308
+
309
+ response.raise_for_status()
310
+
311
+ async def read_resource_related_automations(
312
+ self, resource_id: str
313
+ ) -> list["Automation"]:
314
+ response = await self.request(
315
+ "GET",
316
+ "/automations/related-to/{resource_id}",
317
+ path_params={"resource_id": resource_id},
318
+ )
319
+ response.raise_for_status()
320
+ from prefect.events.schemas.automations import Automation
321
+
322
+ return Automation.model_validate_list(response.json())
323
+
324
+ async def delete_resource_owned_automations(self, resource_id: str) -> None:
325
+ await self.request(
326
+ "DELETE",
327
+ "/automations/owned-by/{resource_id}",
328
+ path_params={"resource_id": resource_id},
329
+ )