prefect-client 2.20.4__py3-none-any.whl → 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. prefect/__init__.py +74 -110
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/compatibility/migration.py +166 -0
  5. prefect/_internal/concurrency/__init__.py +2 -2
  6. prefect/_internal/concurrency/api.py +1 -35
  7. prefect/_internal/concurrency/calls.py +0 -6
  8. prefect/_internal/concurrency/cancellation.py +0 -3
  9. prefect/_internal/concurrency/event_loop.py +0 -20
  10. prefect/_internal/concurrency/inspection.py +3 -3
  11. prefect/_internal/concurrency/primitives.py +1 -0
  12. prefect/_internal/concurrency/services.py +23 -0
  13. prefect/_internal/concurrency/threads.py +35 -0
  14. prefect/_internal/concurrency/waiters.py +0 -28
  15. prefect/_internal/integrations.py +7 -0
  16. prefect/_internal/pydantic/__init__.py +0 -45
  17. prefect/_internal/pydantic/annotations/pendulum.py +2 -2
  18. prefect/_internal/pydantic/v1_schema.py +21 -22
  19. prefect/_internal/pydantic/v2_schema.py +0 -2
  20. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  21. prefect/_internal/pytz.py +1 -1
  22. prefect/_internal/retries.py +61 -0
  23. prefect/_internal/schemas/bases.py +45 -177
  24. prefect/_internal/schemas/fields.py +1 -43
  25. prefect/_internal/schemas/validators.py +47 -233
  26. prefect/agent.py +3 -695
  27. prefect/artifacts.py +173 -14
  28. prefect/automations.py +39 -4
  29. prefect/blocks/abstract.py +1 -1
  30. prefect/blocks/core.py +405 -153
  31. prefect/blocks/fields.py +2 -57
  32. prefect/blocks/notifications.py +43 -28
  33. prefect/blocks/redis.py +168 -0
  34. prefect/blocks/system.py +67 -20
  35. prefect/blocks/webhook.py +2 -9
  36. prefect/cache_policies.py +239 -0
  37. prefect/client/__init__.py +4 -0
  38. prefect/client/base.py +33 -27
  39. prefect/client/cloud.py +65 -20
  40. prefect/client/collections.py +1 -1
  41. prefect/client/orchestration.py +650 -442
  42. prefect/client/schemas/actions.py +115 -100
  43. prefect/client/schemas/filters.py +46 -52
  44. prefect/client/schemas/objects.py +228 -178
  45. prefect/client/schemas/responses.py +18 -36
  46. prefect/client/schemas/schedules.py +55 -36
  47. prefect/client/schemas/sorting.py +2 -0
  48. prefect/client/subscriptions.py +8 -7
  49. prefect/client/types/flexible_schedule_list.py +11 -0
  50. prefect/client/utilities.py +9 -6
  51. prefect/concurrency/asyncio.py +60 -11
  52. prefect/concurrency/context.py +24 -0
  53. prefect/concurrency/events.py +2 -2
  54. prefect/concurrency/services.py +46 -16
  55. prefect/concurrency/sync.py +51 -7
  56. prefect/concurrency/v1/asyncio.py +143 -0
  57. prefect/concurrency/v1/context.py +27 -0
  58. prefect/concurrency/v1/events.py +61 -0
  59. prefect/concurrency/v1/services.py +116 -0
  60. prefect/concurrency/v1/sync.py +92 -0
  61. prefect/context.py +246 -149
  62. prefect/deployments/__init__.py +33 -18
  63. prefect/deployments/base.py +10 -15
  64. prefect/deployments/deployments.py +2 -1048
  65. prefect/deployments/flow_runs.py +178 -0
  66. prefect/deployments/runner.py +72 -173
  67. prefect/deployments/schedules.py +31 -25
  68. prefect/deployments/steps/__init__.py +0 -1
  69. prefect/deployments/steps/core.py +7 -0
  70. prefect/deployments/steps/pull.py +15 -21
  71. prefect/deployments/steps/utility.py +2 -1
  72. prefect/docker/__init__.py +20 -0
  73. prefect/docker/docker_image.py +82 -0
  74. prefect/engine.py +15 -2475
  75. prefect/events/actions.py +17 -23
  76. prefect/events/cli/automations.py +20 -7
  77. prefect/events/clients.py +142 -80
  78. prefect/events/filters.py +14 -18
  79. prefect/events/related.py +74 -75
  80. prefect/events/schemas/__init__.py +0 -5
  81. prefect/events/schemas/automations.py +55 -46
  82. prefect/events/schemas/deployment_triggers.py +7 -197
  83. prefect/events/schemas/events.py +46 -65
  84. prefect/events/schemas/labelling.py +10 -14
  85. prefect/events/utilities.py +4 -5
  86. prefect/events/worker.py +23 -8
  87. prefect/exceptions.py +15 -0
  88. prefect/filesystems.py +30 -529
  89. prefect/flow_engine.py +827 -0
  90. prefect/flow_runs.py +379 -7
  91. prefect/flows.py +470 -360
  92. prefect/futures.py +382 -331
  93. prefect/infrastructure/__init__.py +5 -26
  94. prefect/infrastructure/base.py +3 -320
  95. prefect/infrastructure/provisioners/__init__.py +5 -3
  96. prefect/infrastructure/provisioners/cloud_run.py +13 -8
  97. prefect/infrastructure/provisioners/container_instance.py +14 -9
  98. prefect/infrastructure/provisioners/ecs.py +10 -8
  99. prefect/infrastructure/provisioners/modal.py +8 -5
  100. prefect/input/__init__.py +4 -0
  101. prefect/input/actions.py +2 -4
  102. prefect/input/run_input.py +9 -9
  103. prefect/logging/formatters.py +2 -4
  104. prefect/logging/handlers.py +9 -14
  105. prefect/logging/loggers.py +5 -5
  106. prefect/main.py +72 -0
  107. prefect/plugins.py +2 -64
  108. prefect/profiles.toml +16 -2
  109. prefect/records/__init__.py +1 -0
  110. prefect/records/base.py +223 -0
  111. prefect/records/filesystem.py +207 -0
  112. prefect/records/memory.py +178 -0
  113. prefect/records/result_store.py +64 -0
  114. prefect/results.py +577 -504
  115. prefect/runner/runner.py +117 -47
  116. prefect/runner/server.py +32 -34
  117. prefect/runner/storage.py +3 -12
  118. prefect/runner/submit.py +2 -10
  119. prefect/runner/utils.py +2 -2
  120. prefect/runtime/__init__.py +1 -0
  121. prefect/runtime/deployment.py +1 -0
  122. prefect/runtime/flow_run.py +40 -5
  123. prefect/runtime/task_run.py +1 -0
  124. prefect/serializers.py +28 -39
  125. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  126. prefect/settings.py +209 -332
  127. prefect/states.py +160 -63
  128. prefect/task_engine.py +1478 -57
  129. prefect/task_runners.py +383 -287
  130. prefect/task_runs.py +240 -0
  131. prefect/task_worker.py +463 -0
  132. prefect/tasks.py +684 -374
  133. prefect/transactions.py +410 -0
  134. prefect/types/__init__.py +72 -86
  135. prefect/types/entrypoint.py +13 -0
  136. prefect/utilities/annotations.py +4 -3
  137. prefect/utilities/asyncutils.py +227 -148
  138. prefect/utilities/callables.py +137 -45
  139. prefect/utilities/collections.py +134 -86
  140. prefect/utilities/dispatch.py +27 -14
  141. prefect/utilities/dockerutils.py +11 -4
  142. prefect/utilities/engine.py +186 -32
  143. prefect/utilities/filesystem.py +4 -5
  144. prefect/utilities/importtools.py +26 -27
  145. prefect/utilities/pydantic.py +128 -38
  146. prefect/utilities/schema_tools/hydration.py +18 -1
  147. prefect/utilities/schema_tools/validation.py +30 -0
  148. prefect/utilities/services.py +35 -9
  149. prefect/utilities/templating.py +12 -2
  150. prefect/utilities/timeout.py +20 -5
  151. prefect/utilities/urls.py +195 -0
  152. prefect/utilities/visualization.py +1 -0
  153. prefect/variables.py +78 -59
  154. prefect/workers/__init__.py +0 -1
  155. prefect/workers/base.py +237 -244
  156. prefect/workers/block.py +5 -226
  157. prefect/workers/cloud.py +6 -0
  158. prefect/workers/process.py +265 -12
  159. prefect/workers/server.py +29 -11
  160. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/METADATA +28 -24
  161. prefect_client-3.0.0.dist-info/RECORD +201 -0
  162. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/WHEEL +1 -1
  163. prefect/_internal/pydantic/_base_model.py +0 -51
  164. prefect/_internal/pydantic/_compat.py +0 -82
  165. prefect/_internal/pydantic/_flags.py +0 -20
  166. prefect/_internal/pydantic/_types.py +0 -8
  167. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  168. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  169. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  170. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  171. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  172. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  173. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  174. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  175. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  176. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  177. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  178. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  179. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  180. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  181. prefect/_vendor/fastapi/__init__.py +0 -25
  182. prefect/_vendor/fastapi/applications.py +0 -946
  183. prefect/_vendor/fastapi/background.py +0 -3
  184. prefect/_vendor/fastapi/concurrency.py +0 -44
  185. prefect/_vendor/fastapi/datastructures.py +0 -58
  186. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  187. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  188. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  189. prefect/_vendor/fastapi/encoders.py +0 -177
  190. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  191. prefect/_vendor/fastapi/exceptions.py +0 -46
  192. prefect/_vendor/fastapi/logger.py +0 -3
  193. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  194. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  195. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  196. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  197. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  198. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  199. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  200. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  201. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  202. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  203. prefect/_vendor/fastapi/openapi/models.py +0 -480
  204. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  205. prefect/_vendor/fastapi/param_functions.py +0 -340
  206. prefect/_vendor/fastapi/params.py +0 -453
  207. prefect/_vendor/fastapi/py.typed +0 -0
  208. prefect/_vendor/fastapi/requests.py +0 -4
  209. prefect/_vendor/fastapi/responses.py +0 -40
  210. prefect/_vendor/fastapi/routing.py +0 -1331
  211. prefect/_vendor/fastapi/security/__init__.py +0 -15
  212. prefect/_vendor/fastapi/security/api_key.py +0 -98
  213. prefect/_vendor/fastapi/security/base.py +0 -6
  214. prefect/_vendor/fastapi/security/http.py +0 -172
  215. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  216. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  217. prefect/_vendor/fastapi/security/utils.py +0 -10
  218. prefect/_vendor/fastapi/staticfiles.py +0 -1
  219. prefect/_vendor/fastapi/templating.py +0 -3
  220. prefect/_vendor/fastapi/testclient.py +0 -1
  221. prefect/_vendor/fastapi/types.py +0 -3
  222. prefect/_vendor/fastapi/utils.py +0 -235
  223. prefect/_vendor/fastapi/websockets.py +0 -7
  224. prefect/_vendor/starlette/__init__.py +0 -1
  225. prefect/_vendor/starlette/_compat.py +0 -28
  226. prefect/_vendor/starlette/_exception_handler.py +0 -80
  227. prefect/_vendor/starlette/_utils.py +0 -88
  228. prefect/_vendor/starlette/applications.py +0 -261
  229. prefect/_vendor/starlette/authentication.py +0 -159
  230. prefect/_vendor/starlette/background.py +0 -43
  231. prefect/_vendor/starlette/concurrency.py +0 -59
  232. prefect/_vendor/starlette/config.py +0 -151
  233. prefect/_vendor/starlette/convertors.py +0 -87
  234. prefect/_vendor/starlette/datastructures.py +0 -707
  235. prefect/_vendor/starlette/endpoints.py +0 -130
  236. prefect/_vendor/starlette/exceptions.py +0 -60
  237. prefect/_vendor/starlette/formparsers.py +0 -276
  238. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  239. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  240. prefect/_vendor/starlette/middleware/base.py +0 -220
  241. prefect/_vendor/starlette/middleware/cors.py +0 -176
  242. prefect/_vendor/starlette/middleware/errors.py +0 -265
  243. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  244. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  245. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  246. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  247. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  248. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  249. prefect/_vendor/starlette/py.typed +0 -0
  250. prefect/_vendor/starlette/requests.py +0 -328
  251. prefect/_vendor/starlette/responses.py +0 -347
  252. prefect/_vendor/starlette/routing.py +0 -933
  253. prefect/_vendor/starlette/schemas.py +0 -154
  254. prefect/_vendor/starlette/staticfiles.py +0 -248
  255. prefect/_vendor/starlette/status.py +0 -199
  256. prefect/_vendor/starlette/templating.py +0 -231
  257. prefect/_vendor/starlette/testclient.py +0 -804
  258. prefect/_vendor/starlette/types.py +0 -30
  259. prefect/_vendor/starlette/websockets.py +0 -193
  260. prefect/blocks/kubernetes.py +0 -119
  261. prefect/deprecated/__init__.py +0 -0
  262. prefect/deprecated/data_documents.py +0 -350
  263. prefect/deprecated/packaging/__init__.py +0 -12
  264. prefect/deprecated/packaging/base.py +0 -96
  265. prefect/deprecated/packaging/docker.py +0 -146
  266. prefect/deprecated/packaging/file.py +0 -92
  267. prefect/deprecated/packaging/orion.py +0 -80
  268. prefect/deprecated/packaging/serializers.py +0 -171
  269. prefect/events/instrument.py +0 -135
  270. prefect/infrastructure/container.py +0 -824
  271. prefect/infrastructure/kubernetes.py +0 -920
  272. prefect/infrastructure/process.py +0 -289
  273. prefect/manifests.py +0 -20
  274. prefect/new_flow_engine.py +0 -449
  275. prefect/new_task_engine.py +0 -423
  276. prefect/pydantic/__init__.py +0 -76
  277. prefect/pydantic/main.py +0 -39
  278. prefect/software/__init__.py +0 -2
  279. prefect/software/base.py +0 -50
  280. prefect/software/conda.py +0 -199
  281. prefect/software/pip.py +0 -122
  282. prefect/software/python.py +0 -52
  283. prefect/task_server.py +0 -322
  284. prefect_client-2.20.4.dist-info/RECORD +0 -294
  285. /prefect/{_internal/pydantic/utilities → client/types}/__init__.py +0 -0
  286. /prefect/{_vendor → concurrency/v1}/__init__.py +0 -0
  287. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
  288. {prefect_client-2.20.4.dist-info → prefect_client-3.0.0.dist-info}/top_level.txt +0 -0
prefect/events/related.py CHANGED
@@ -21,6 +21,7 @@ from .schemas.events import RelatedResource
21
21
 
22
22
  if TYPE_CHECKING:
23
23
  from prefect._internal.schemas.bases import ObjectBaseModel
24
+ from prefect.client.orchestration import PrefectClient
24
25
 
25
26
  ResourceCacheEntry = Dict[str, Union[str, "ObjectBaseModel", None]]
26
27
  RelatedResourceCache = Dict[str, Tuple[ResourceCacheEntry, DateTime]]
@@ -31,7 +32,7 @@ RESOURCE_CACHE: RelatedResourceCache = {}
31
32
 
32
33
  def tags_as_related_resources(tags: Iterable[str]) -> List[RelatedResource]:
33
34
  return [
34
- RelatedResource.parse_obj(
35
+ RelatedResource.model_validate(
35
36
  {
36
37
  "prefect.resource.id": f"prefect.tag.{tag}",
37
38
  "prefect.resource.role": "tag",
@@ -44,7 +45,7 @@ def tags_as_related_resources(tags: Iterable[str]) -> List[RelatedResource]:
44
45
  def object_as_related_resource(kind: str, role: str, object: Any) -> RelatedResource:
45
46
  resource_id = f"prefect.{kind}.{object.id}"
46
47
 
47
- return RelatedResource.parse_obj(
48
+ return RelatedResource.model_validate(
48
49
  {
49
50
  "prefect.resource.id": resource_id,
50
51
  "prefect.resource.role": role,
@@ -54,9 +55,9 @@ def object_as_related_resource(kind: str, role: str, object: Any) -> RelatedReso
54
55
 
55
56
 
56
57
  async def related_resources_from_run_context(
58
+ client: "PrefectClient",
57
59
  exclude: Optional[Set[str]] = None,
58
60
  ) -> List[RelatedResource]:
59
- from prefect.client.orchestration import get_client
60
61
  from prefect.client.schemas.objects import FlowRun
61
62
  from prefect.context import FlowRunContext, TaskRunContext
62
63
 
@@ -77,86 +78,84 @@ async def related_resources_from_run_context(
77
78
 
78
79
  related_objects: List[ResourceCacheEntry] = []
79
80
 
80
- async with get_client() as client:
81
+ async def dummy_read():
82
+ return {}
81
83
 
82
- async def dummy_read():
83
- return {}
84
-
85
- if flow_run_context:
86
- related_objects.append(
87
- {
88
- "kind": "flow-run",
89
- "role": "flow-run",
90
- "object": flow_run_context.flow_run,
91
- },
92
- )
93
- else:
94
- related_objects.append(
95
- await _get_and_cache_related_object(
96
- kind="flow-run",
97
- role="flow-run",
98
- client_method=client.read_flow_run,
99
- obj_id=flow_run_id,
100
- cache=RESOURCE_CACHE,
101
- )
84
+ if flow_run_context:
85
+ related_objects.append(
86
+ {
87
+ "kind": "flow-run",
88
+ "role": "flow-run",
89
+ "object": flow_run_context.flow_run,
90
+ },
91
+ )
92
+ else:
93
+ related_objects.append(
94
+ await _get_and_cache_related_object(
95
+ kind="flow-run",
96
+ role="flow-run",
97
+ client_method=client.read_flow_run,
98
+ obj_id=flow_run_id,
99
+ cache=RESOURCE_CACHE,
102
100
  )
101
+ )
103
102
 
104
- if task_run_context:
105
- related_objects.append(
106
- {
107
- "kind": "task-run",
108
- "role": "task-run",
109
- "object": task_run_context.task_run,
110
- },
111
- )
103
+ if task_run_context:
104
+ related_objects.append(
105
+ {
106
+ "kind": "task-run",
107
+ "role": "task-run",
108
+ "object": task_run_context.task_run,
109
+ },
110
+ )
112
111
 
113
- flow_run = related_objects[0]["object"]
112
+ flow_run = related_objects[0]["object"]
114
113
 
115
- if isinstance(flow_run, FlowRun):
116
- related_objects += list(
117
- await asyncio.gather(
114
+ if isinstance(flow_run, FlowRun):
115
+ related_objects += list(
116
+ await asyncio.gather(
117
+ _get_and_cache_related_object(
118
+ kind="flow",
119
+ role="flow",
120
+ client_method=client.read_flow,
121
+ obj_id=flow_run.flow_id,
122
+ cache=RESOURCE_CACHE,
123
+ ),
124
+ (
125
+ _get_and_cache_related_object(
126
+ kind="deployment",
127
+ role="deployment",
128
+ client_method=client.read_deployment,
129
+ obj_id=flow_run.deployment_id,
130
+ cache=RESOURCE_CACHE,
131
+ )
132
+ if flow_run.deployment_id
133
+ else dummy_read()
134
+ ),
135
+ (
136
+ _get_and_cache_related_object(
137
+ kind="work-queue",
138
+ role="work-queue",
139
+ client_method=client.read_work_queue,
140
+ obj_id=flow_run.work_queue_id,
141
+ cache=RESOURCE_CACHE,
142
+ )
143
+ if flow_run.work_queue_id
144
+ else dummy_read()
145
+ ),
146
+ (
118
147
  _get_and_cache_related_object(
119
- kind="flow",
120
- role="flow",
121
- client_method=client.read_flow,
122
- obj_id=flow_run.flow_id,
148
+ kind="work-pool",
149
+ role="work-pool",
150
+ client_method=client.read_work_pool,
151
+ obj_id=flow_run.work_pool_name,
123
152
  cache=RESOURCE_CACHE,
124
- ),
125
- (
126
- _get_and_cache_related_object(
127
- kind="deployment",
128
- role="deployment",
129
- client_method=client.read_deployment,
130
- obj_id=flow_run.deployment_id,
131
- cache=RESOURCE_CACHE,
132
- )
133
- if flow_run.deployment_id
134
- else dummy_read()
135
- ),
136
- (
137
- _get_and_cache_related_object(
138
- kind="work-queue",
139
- role="work-queue",
140
- client_method=client.read_work_queue,
141
- obj_id=flow_run.work_queue_id,
142
- cache=RESOURCE_CACHE,
143
- )
144
- if flow_run.work_queue_id
145
- else dummy_read()
146
- ),
147
- (
148
- _get_and_cache_related_object(
149
- kind="work-pool",
150
- role="work-pool",
151
- client_method=client.read_work_pool,
152
- obj_id=flow_run.work_pool_name,
153
- cache=RESOURCE_CACHE,
154
- )
155
- if flow_run.work_pool_name
156
- else dummy_read()
157
- ),
158
- )
153
+ )
154
+ if flow_run.work_pool_name
155
+ else dummy_read()
156
+ ),
159
157
  )
158
+ )
160
159
 
161
160
  related = []
162
161
  tags = set()
@@ -1,5 +0,0 @@
1
- # TODO: these are just for backward compatibility, can can be removed in the future
2
-
3
- from .deployment_triggers import DeploymentTrigger
4
-
5
- __all__ = ["DeploymentTrigger"]
@@ -14,19 +14,15 @@ from typing import (
14
14
  )
15
15
  from uuid import UUID
16
16
 
17
- from typing_extensions import TypeAlias
18
-
19
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
20
-
21
- if HAS_PYDANTIC_V2:
22
- from pydantic.v1 import Field, PrivateAttr, root_validator, validator
23
- from pydantic.v1.fields import ModelField
24
- else:
25
- from pydantic import Field, PrivateAttr, root_validator, validator # type: ignore
26
- from pydantic.fields import ModelField # type: ignore
17
+ from pydantic import (
18
+ Field,
19
+ PrivateAttr,
20
+ field_validator,
21
+ model_validator,
22
+ )
23
+ from typing_extensions import Self, TypeAlias
27
24
 
28
25
  from prefect._internal.schemas.bases import PrefectBaseModel
29
- from prefect._internal.schemas.validators import validate_trigger_within
30
26
  from prefect.events.actions import ActionTypes, RunDeployment
31
27
  from prefect.utilities.collections import AutoEnum
32
28
 
@@ -81,7 +77,7 @@ class Trigger(PrefectBaseModel, abc.ABC, extra="ignore"): # type: ignore[call-a
81
77
  # This is one of the Deployment*Trigger classes, so translate it over to a
82
78
  # plain Trigger
83
79
  if hasattr(self, "trigger_type"):
84
- trigger = self.trigger_type(**self.dict())
80
+ trigger = self.trigger_type(**self.model_dump())
85
81
 
86
82
  return AutomationCore(
87
83
  name=(
@@ -104,11 +100,11 @@ class ResourceTrigger(Trigger, abc.ABC):
104
100
  type: str
105
101
 
106
102
  match: ResourceSpecification = Field(
107
- default_factory=lambda: ResourceSpecification.parse_obj({}),
103
+ default_factory=lambda: ResourceSpecification.model_validate({}),
108
104
  description="Labels for resources which this trigger will match.",
109
105
  )
110
106
  match_related: ResourceSpecification = Field(
111
- default_factory=lambda: ResourceSpecification.parse_obj({}),
107
+ default_factory=lambda: ResourceSpecification.model_validate({}),
112
108
  description="Labels for related resources which this trigger will match.",
113
109
  )
114
110
 
@@ -167,9 +163,8 @@ class EventTrigger(ResourceTrigger):
167
163
  ),
168
164
  )
169
165
  within: timedelta = Field(
170
- timedelta(0),
171
- minimum=0.0,
172
- exclusiveMinimum=False,
166
+ timedelta(seconds=0),
167
+ ge=timedelta(seconds=0),
173
168
  description=(
174
169
  "The time period over which the events must occur. For Reactive triggers, "
175
170
  "this may be as low as 0 seconds, but must be at least 10 seconds for "
@@ -177,26 +172,33 @@ class EventTrigger(ResourceTrigger):
177
172
  ),
178
173
  )
179
174
 
180
- @validator("within")
181
- def enforce_minimum_within(
182
- cls, value: timedelta, values, config, field: ModelField
183
- ):
184
- return validate_trigger_within(value, field)
175
+ @model_validator(mode="before")
176
+ @classmethod
177
+ def enforce_minimum_within_for_proactive_triggers(
178
+ cls, data: Dict[str, Any]
179
+ ) -> Dict[str, Any]:
180
+ if not isinstance(data, dict):
181
+ return data
182
+
183
+ if "within" in data and data["within"] is None:
184
+ raise ValueError("`within` should be a valid timedelta")
185
185
 
186
- @root_validator(skip_on_failure=True)
187
- def enforce_minimum_within_for_proactive_triggers(cls, values: Dict[str, Any]):
188
- posture: Optional[Posture] = values.get("posture")
189
- within: Optional[timedelta] = values.get("within")
186
+ posture: Optional[Posture] = data.get("posture")
187
+ within: Optional[timedelta] = data.get("within")
188
+
189
+ if isinstance(within, (int, float)):
190
+ within = timedelta(seconds=within)
190
191
 
191
192
  if posture == Posture.Proactive:
192
193
  if not within or within == timedelta(0):
193
- values["within"] = timedelta(seconds=10.0)
194
+ within = timedelta(seconds=10.0)
194
195
  elif within < timedelta(seconds=10.0):
195
196
  raise ValueError(
196
- "The minimum within for Proactive triggers is 10 seconds"
197
+ "`within` for Proactive triggers must be greater than or equal to "
198
+ "10 seconds"
197
199
  )
198
200
 
199
- return values
201
+ return data | {"within": within} if within else data
200
202
 
201
203
  def describe_for_cli(self, indent: int = 0) -> str:
202
204
  """Return a human-readable description of this trigger for the CLI"""
@@ -258,8 +260,6 @@ class MetricTriggerQuery(PrefectBaseModel):
258
260
  )
259
261
  range: timedelta = Field(
260
262
  timedelta(seconds=300), # defaults to 5 minutes
261
- minimum=300.0,
262
- exclusiveMinimum=False,
263
263
  description=(
264
264
  "The lookback duration (seconds) for a metric query. This duration is "
265
265
  "used to determine the time range over which the query will be executed. "
@@ -268,8 +268,6 @@ class MetricTriggerQuery(PrefectBaseModel):
268
268
  )
269
269
  firing_for: timedelta = Field(
270
270
  timedelta(seconds=300), # defaults to 5 minutes
271
- minimum=300.0,
272
- exclusiveMinimum=False,
273
271
  description=(
274
272
  "The duration (seconds) for which the metric query must breach "
275
273
  "or resolve continuously before the state is updated and the "
@@ -278,6 +276,12 @@ class MetricTriggerQuery(PrefectBaseModel):
278
276
  ),
279
277
  )
280
278
 
279
+ @field_validator("range", "firing_for")
280
+ def enforce_minimum_range(cls, value: timedelta):
281
+ if value < timedelta(seconds=300):
282
+ raise ValueError("The minimum range is 300 seconds (5 minutes)")
283
+ return value
284
+
281
285
 
282
286
  class MetricTrigger(ResourceTrigger):
283
287
  """
@@ -316,7 +320,14 @@ class CompositeTrigger(Trigger, abc.ABC):
316
320
 
317
321
  type: Literal["compound", "sequence"]
318
322
  triggers: List["TriggerTypes"]
319
- within: Optional[timedelta]
323
+ within: Optional[timedelta] = Field(
324
+ None,
325
+ description=(
326
+ "The time period over which the events must occur. For Reactive triggers, "
327
+ "this may be as low as 0 seconds, but must be at least 10 seconds for "
328
+ "Proactive triggers"
329
+ ),
330
+ )
320
331
 
321
332
 
322
333
  class CompoundTrigger(CompositeTrigger):
@@ -326,19 +337,17 @@ class CompoundTrigger(CompositeTrigger):
326
337
  type: Literal["compound"] = "compound"
327
338
  require: Union[int, Literal["any", "all"]]
328
339
 
329
- @root_validator
330
- def validate_require(cls, values: Dict[str, Any]) -> Dict[str, Any]:
331
- require = values.get("require")
332
-
333
- if isinstance(require, int):
334
- if require < 1:
335
- raise ValueError("required must be at least 1")
336
- if require > len(values["triggers"]):
340
+ @model_validator(mode="after")
341
+ def validate_require(self) -> Self:
342
+ if isinstance(self.require, int):
343
+ if self.require < 1:
344
+ raise ValueError("require must be at least 1")
345
+ if self.require > len(self.triggers):
337
346
  raise ValueError(
338
- "required must be less than or equal to the number of triggers"
347
+ "require must be less than or equal to the number of triggers"
339
348
  )
340
349
 
341
- return values
350
+ return self
342
351
 
343
352
  def describe_for_cli(self, indent: int = 0) -> str:
344
353
  """Return a human-readable description of this trigger for the CLI"""
@@ -387,8 +396,8 @@ TriggerTypes: TypeAlias = Union[
387
396
  ]
388
397
  """The union of all concrete trigger types that a user may actually create"""
389
398
 
390
- CompoundTrigger.update_forward_refs()
391
- SequenceTrigger.update_forward_refs()
399
+ CompoundTrigger.model_rebuild()
400
+ SequenceTrigger.model_rebuild()
392
401
 
393
402
 
394
403
  class AutomationCore(PrefectBaseModel, extra="ignore"): # type: ignore[call-arg]
@@ -10,42 +10,27 @@ create them from YAML.
10
10
  """
11
11
 
12
12
  import abc
13
- import textwrap
14
- from datetime import timedelta
15
13
  from typing import (
16
14
  Any,
15
+ ClassVar,
17
16
  Dict,
18
- List,
19
17
  Optional,
20
- Set,
18
+ Type,
21
19
  Union,
22
20
  )
23
- from uuid import UUID
24
21
 
22
+ from pydantic import Field
25
23
  from typing_extensions import TypeAlias
26
24
 
27
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
28
-
29
- if HAS_PYDANTIC_V2:
30
- from pydantic.v1 import Field, PrivateAttr
31
- else:
32
- from pydantic import Field, PrivateAttr # type: ignore
33
-
34
- from prefect._internal.compatibility.deprecated import deprecated_class
35
25
  from prefect._internal.schemas.bases import PrefectBaseModel
36
- from prefect.events.actions import ActionTypes, RunDeployment
37
26
 
38
27
  from .automations import (
39
- AutomationCore,
40
28
  CompoundTrigger,
41
29
  EventTrigger,
42
30
  MetricTrigger,
43
- MetricTriggerQuery,
44
- Posture,
45
31
  SequenceTrigger,
46
32
  TriggerTypes,
47
33
  )
48
- from .events import ResourceSpecification
49
34
 
50
35
 
51
36
  class BaseDeploymentTrigger(PrefectBaseModel, abc.ABC, extra="ignore"): # type: ignore[call-arg]
@@ -86,7 +71,7 @@ class DeploymentEventTrigger(BaseDeploymentTrigger, EventTrigger):
86
71
  period of time.
87
72
  """
88
73
 
89
- trigger_type = EventTrigger
74
+ trigger_type: ClassVar[Type[TriggerTypes]] = EventTrigger
90
75
 
91
76
 
92
77
  class DeploymentMetricTrigger(BaseDeploymentTrigger, MetricTrigger):
@@ -94,21 +79,21 @@ class DeploymentMetricTrigger(BaseDeploymentTrigger, MetricTrigger):
94
79
  A trigger that fires based on the results of a metric query.
95
80
  """
96
81
 
97
- trigger_type = MetricTrigger
82
+ trigger_type: ClassVar[Type[TriggerTypes]] = MetricTrigger
98
83
 
99
84
 
100
85
  class DeploymentCompoundTrigger(BaseDeploymentTrigger, CompoundTrigger):
101
86
  """A composite trigger that requires some number of triggers to have
102
87
  fired within the given time period"""
103
88
 
104
- trigger_type = CompoundTrigger
89
+ trigger_type: ClassVar[Type[TriggerTypes]] = CompoundTrigger
105
90
 
106
91
 
107
92
  class DeploymentSequenceTrigger(BaseDeploymentTrigger, SequenceTrigger):
108
93
  """A composite trigger that requires some number of triggers to have fired
109
94
  within the given time period in a specific order"""
110
95
 
111
- trigger_type = SequenceTrigger
96
+ trigger_type: ClassVar[Type[TriggerTypes]] = SequenceTrigger
112
97
 
113
98
 
114
99
  # Concrete deployment trigger types
@@ -118,178 +103,3 @@ DeploymentTriggerTypes: TypeAlias = Union[
118
103
  DeploymentCompoundTrigger,
119
104
  DeploymentSequenceTrigger,
120
105
  ]
121
-
122
-
123
- # The deprecated all-in-one DeploymentTrigger
124
-
125
-
126
- @deprecated_class(
127
- start_date="Mar 2024",
128
- help=textwrap.dedent(
129
- """
130
- To associate a specific kind of trigger with a Deployment, use one of the more
131
- specific deployment trigger types instead:
132
-
133
- * DeploymentEventTrigger to associate an EventTrigger with a deployment
134
- * DeploymentMetricTrigger to associate an MetricTrigger with a deployment
135
- * DeploymentCompoundTrigger to associate an CompoundTrigger with a deployment
136
- * DeploymentSequenceTrigger to associate an SequenceTrigger with a deployment
137
-
138
- In other cases, use the Automation and Trigger class hierarchy directly.
139
- """
140
- ),
141
- )
142
- class DeploymentTrigger(PrefectBaseModel):
143
- name: Optional[str] = Field(
144
- None, description="The name to give to the automation created for this trigger."
145
- )
146
- description: str = Field("", description="A longer description of this automation")
147
- enabled: bool = Field(True, description="Whether this automation will be evaluated")
148
- job_variables: Optional[Dict[str, Any]] = Field(
149
- None,
150
- description=(
151
- "Job variables to pass to the run, or None to use the "
152
- "deployment's default job variables"
153
- ),
154
- )
155
-
156
- # from ResourceTrigger
157
-
158
- match: ResourceSpecification = Field(
159
- default_factory=lambda: ResourceSpecification.parse_obj({}),
160
- description="Labels for resources which this trigger will match.",
161
- )
162
- match_related: ResourceSpecification = Field(
163
- default_factory=lambda: ResourceSpecification.parse_obj({}),
164
- description="Labels for related resources which this trigger will match.",
165
- )
166
-
167
- # from both EventTrigger and MetricTrigger
168
-
169
- posture: Posture = Field(
170
- Posture.Reactive,
171
- description=(
172
- "The posture of this trigger, either Reactive, Proactive, or Metric. "
173
- "Reactive triggers respond to the _presence_ of the expected events, while "
174
- "Proactive triggers respond to the _absence_ of those expected events. "
175
- "Metric triggers periodically evaluate the configured metric query."
176
- ),
177
- )
178
-
179
- # from EventTrigger
180
-
181
- after: Set[str] = Field(
182
- default_factory=set,
183
- description=(
184
- "The event(s) which must first been seen to fire this trigger. If "
185
- "empty, then fire this trigger immediately. Events may include "
186
- "trailing wildcards, like `prefect.flow-run.*`"
187
- ),
188
- )
189
- expect: Set[str] = Field(
190
- default_factory=set,
191
- description=(
192
- "The event(s) this trigger is expecting to see. If empty, this "
193
- "trigger will match any event. Events may include trailing wildcards, "
194
- "like `prefect.flow-run.*`"
195
- ),
196
- )
197
-
198
- for_each: Set[str] = Field(
199
- default_factory=set,
200
- description=(
201
- "Evaluate the trigger separately for each distinct value of these labels "
202
- "on the resource. By default, labels refer to the primary resource of the "
203
- "triggering event. You may also refer to labels from related "
204
- "resources by specifying `related:<role>:<label>`. This will use the "
205
- "value of that label for the first related resource in that role. For "
206
- 'example, `"for_each": ["related:flow:prefect.resource.id"]` would '
207
- "evaluate the trigger for each flow."
208
- ),
209
- )
210
- threshold: int = Field(
211
- 1,
212
- description=(
213
- "The number of events required for this trigger to fire (for "
214
- "Reactive triggers), or the number of events expected (for Proactive "
215
- "triggers)"
216
- ),
217
- )
218
- within: timedelta = Field(
219
- timedelta(0),
220
- minimum=0.0,
221
- exclusiveMinimum=False,
222
- description=(
223
- "The time period over which the events must occur. For Reactive triggers, "
224
- "this may be as low as 0 seconds, but must be at least 10 seconds for "
225
- "Proactive triggers"
226
- ),
227
- )
228
-
229
- # from MetricTrigger
230
-
231
- metric: Optional[MetricTriggerQuery] = Field(
232
- None,
233
- description="The metric query to evaluate for this trigger. ",
234
- )
235
-
236
- _deployment_id: Optional[UUID] = PrivateAttr(default=None)
237
- parameters: Optional[Dict[str, Any]] = Field(
238
- None,
239
- description=(
240
- "The parameters to pass to the deployment, or None to use the "
241
- "deployment's default parameters"
242
- ),
243
- )
244
-
245
- def as_automation(self) -> AutomationCore:
246
- assert self.name
247
-
248
- trigger: TriggerTypes
249
-
250
- if self.posture == Posture.Metric:
251
- assert self.metric
252
- trigger = MetricTrigger(
253
- type="metric",
254
- match=self.match,
255
- match_related=self.match_related,
256
- posture=self.posture,
257
- metric=self.metric,
258
- )
259
- else:
260
- trigger = EventTrigger(
261
- match=self.match,
262
- match_related=self.match_related,
263
- after=self.after,
264
- expect=self.expect,
265
- for_each=self.for_each,
266
- posture=self.posture,
267
- threshold=self.threshold,
268
- within=self.within,
269
- )
270
-
271
- return AutomationCore(
272
- name=self.name,
273
- description=self.description,
274
- enabled=self.enabled,
275
- trigger=trigger,
276
- actions=self.actions(),
277
- owner_resource=self.owner_resource(),
278
- )
279
-
280
- def set_deployment_id(self, deployment_id: UUID):
281
- self._deployment_id = deployment_id
282
-
283
- def owner_resource(self) -> Optional[str]:
284
- return f"prefect.deployment.{self._deployment_id}"
285
-
286
- def actions(self) -> List[ActionTypes]:
287
- assert self._deployment_id
288
- return [
289
- RunDeployment(
290
- source="selected",
291
- deployment_id=self._deployment_id,
292
- parameters=self.parameters,
293
- job_variables=self.job_variables,
294
- )
295
- ]