prefect-client 2.19.2__py3-none-any.whl → 3.0.0rc1__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 (239) hide show
  1. prefect/__init__.py +8 -56
  2. prefect/_internal/compatibility/deprecated.py +6 -115
  3. prefect/_internal/compatibility/experimental.py +4 -79
  4. prefect/_internal/concurrency/api.py +0 -34
  5. prefect/_internal/concurrency/calls.py +0 -6
  6. prefect/_internal/concurrency/cancellation.py +0 -3
  7. prefect/_internal/concurrency/event_loop.py +0 -20
  8. prefect/_internal/concurrency/inspection.py +3 -3
  9. prefect/_internal/concurrency/threads.py +35 -0
  10. prefect/_internal/concurrency/waiters.py +0 -28
  11. prefect/_internal/pydantic/__init__.py +0 -45
  12. prefect/_internal/pydantic/v1_schema.py +21 -22
  13. prefect/_internal/pydantic/v2_schema.py +0 -2
  14. prefect/_internal/pydantic/v2_validated_func.py +18 -23
  15. prefect/_internal/schemas/bases.py +44 -177
  16. prefect/_internal/schemas/fields.py +1 -43
  17. prefect/_internal/schemas/validators.py +60 -158
  18. prefect/artifacts.py +161 -14
  19. prefect/automations.py +39 -4
  20. prefect/blocks/abstract.py +1 -1
  21. prefect/blocks/core.py +268 -148
  22. prefect/blocks/fields.py +2 -57
  23. prefect/blocks/kubernetes.py +8 -12
  24. prefect/blocks/notifications.py +40 -20
  25. prefect/blocks/system.py +22 -11
  26. prefect/blocks/webhook.py +2 -9
  27. prefect/client/base.py +4 -4
  28. prefect/client/cloud.py +8 -13
  29. prefect/client/orchestration.py +347 -341
  30. prefect/client/schemas/actions.py +92 -86
  31. prefect/client/schemas/filters.py +20 -40
  32. prefect/client/schemas/objects.py +151 -145
  33. prefect/client/schemas/responses.py +16 -24
  34. prefect/client/schemas/schedules.py +47 -35
  35. prefect/client/subscriptions.py +2 -2
  36. prefect/client/utilities.py +5 -2
  37. prefect/concurrency/asyncio.py +3 -1
  38. prefect/concurrency/events.py +1 -1
  39. prefect/concurrency/services.py +6 -3
  40. prefect/context.py +195 -27
  41. prefect/deployments/__init__.py +5 -6
  42. prefect/deployments/base.py +7 -5
  43. prefect/deployments/flow_runs.py +185 -0
  44. prefect/deployments/runner.py +50 -45
  45. prefect/deployments/schedules.py +28 -23
  46. prefect/deployments/steps/__init__.py +0 -1
  47. prefect/deployments/steps/core.py +1 -0
  48. prefect/deployments/steps/pull.py +7 -21
  49. prefect/engine.py +12 -2422
  50. prefect/events/actions.py +17 -23
  51. prefect/events/cli/automations.py +19 -6
  52. prefect/events/clients.py +14 -37
  53. prefect/events/filters.py +14 -18
  54. prefect/events/related.py +2 -2
  55. prefect/events/schemas/__init__.py +0 -5
  56. prefect/events/schemas/automations.py +55 -46
  57. prefect/events/schemas/deployment_triggers.py +7 -197
  58. prefect/events/schemas/events.py +34 -65
  59. prefect/events/schemas/labelling.py +10 -14
  60. prefect/events/utilities.py +2 -3
  61. prefect/events/worker.py +2 -3
  62. prefect/filesystems.py +6 -517
  63. prefect/{new_flow_engine.py → flow_engine.py} +313 -72
  64. prefect/flow_runs.py +377 -5
  65. prefect/flows.py +307 -166
  66. prefect/futures.py +186 -345
  67. prefect/infrastructure/__init__.py +0 -27
  68. prefect/infrastructure/provisioners/__init__.py +5 -3
  69. prefect/infrastructure/provisioners/cloud_run.py +11 -6
  70. prefect/infrastructure/provisioners/container_instance.py +11 -7
  71. prefect/infrastructure/provisioners/ecs.py +6 -4
  72. prefect/infrastructure/provisioners/modal.py +8 -5
  73. prefect/input/actions.py +2 -4
  74. prefect/input/run_input.py +5 -7
  75. prefect/logging/formatters.py +0 -2
  76. prefect/logging/handlers.py +3 -11
  77. prefect/logging/loggers.py +2 -2
  78. prefect/manifests.py +2 -1
  79. prefect/records/__init__.py +1 -0
  80. prefect/records/result_store.py +42 -0
  81. prefect/records/store.py +9 -0
  82. prefect/results.py +43 -39
  83. prefect/runner/runner.py +19 -15
  84. prefect/runner/server.py +6 -10
  85. prefect/runner/storage.py +3 -8
  86. prefect/runner/submit.py +2 -2
  87. prefect/runner/utils.py +2 -2
  88. prefect/serializers.py +24 -35
  89. prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
  90. prefect/settings.py +70 -133
  91. prefect/states.py +17 -47
  92. prefect/task_engine.py +697 -58
  93. prefect/task_runners.py +269 -301
  94. prefect/task_server.py +53 -34
  95. prefect/tasks.py +327 -337
  96. prefect/transactions.py +220 -0
  97. prefect/types/__init__.py +61 -82
  98. prefect/utilities/asyncutils.py +195 -136
  99. prefect/utilities/callables.py +311 -43
  100. prefect/utilities/collections.py +23 -38
  101. prefect/utilities/dispatch.py +11 -3
  102. prefect/utilities/dockerutils.py +4 -0
  103. prefect/utilities/engine.py +140 -20
  104. prefect/utilities/importtools.py +97 -27
  105. prefect/utilities/pydantic.py +128 -38
  106. prefect/utilities/schema_tools/hydration.py +5 -1
  107. prefect/utilities/templating.py +12 -2
  108. prefect/variables.py +78 -61
  109. prefect/workers/__init__.py +0 -1
  110. prefect/workers/base.py +15 -17
  111. prefect/workers/process.py +3 -8
  112. prefect/workers/server.py +2 -2
  113. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/METADATA +22 -21
  114. prefect_client-3.0.0rc1.dist-info/RECORD +176 -0
  115. prefect/_internal/pydantic/_base_model.py +0 -51
  116. prefect/_internal/pydantic/_compat.py +0 -82
  117. prefect/_internal/pydantic/_flags.py +0 -20
  118. prefect/_internal/pydantic/_types.py +0 -8
  119. prefect/_internal/pydantic/utilities/__init__.py +0 -0
  120. prefect/_internal/pydantic/utilities/config_dict.py +0 -72
  121. prefect/_internal/pydantic/utilities/field_validator.py +0 -150
  122. prefect/_internal/pydantic/utilities/model_construct.py +0 -56
  123. prefect/_internal/pydantic/utilities/model_copy.py +0 -55
  124. prefect/_internal/pydantic/utilities/model_dump.py +0 -136
  125. prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
  126. prefect/_internal/pydantic/utilities/model_fields.py +0 -50
  127. prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
  128. prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
  129. prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
  130. prefect/_internal/pydantic/utilities/model_validate.py +0 -75
  131. prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
  132. prefect/_internal/pydantic/utilities/model_validator.py +0 -87
  133. prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
  134. prefect/_vendor/__init__.py +0 -0
  135. prefect/_vendor/fastapi/__init__.py +0 -25
  136. prefect/_vendor/fastapi/applications.py +0 -946
  137. prefect/_vendor/fastapi/background.py +0 -3
  138. prefect/_vendor/fastapi/concurrency.py +0 -44
  139. prefect/_vendor/fastapi/datastructures.py +0 -58
  140. prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
  141. prefect/_vendor/fastapi/dependencies/models.py +0 -64
  142. prefect/_vendor/fastapi/dependencies/utils.py +0 -877
  143. prefect/_vendor/fastapi/encoders.py +0 -177
  144. prefect/_vendor/fastapi/exception_handlers.py +0 -40
  145. prefect/_vendor/fastapi/exceptions.py +0 -46
  146. prefect/_vendor/fastapi/logger.py +0 -3
  147. prefect/_vendor/fastapi/middleware/__init__.py +0 -1
  148. prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
  149. prefect/_vendor/fastapi/middleware/cors.py +0 -3
  150. prefect/_vendor/fastapi/middleware/gzip.py +0 -3
  151. prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
  152. prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
  153. prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
  154. prefect/_vendor/fastapi/openapi/__init__.py +0 -0
  155. prefect/_vendor/fastapi/openapi/constants.py +0 -2
  156. prefect/_vendor/fastapi/openapi/docs.py +0 -203
  157. prefect/_vendor/fastapi/openapi/models.py +0 -480
  158. prefect/_vendor/fastapi/openapi/utils.py +0 -485
  159. prefect/_vendor/fastapi/param_functions.py +0 -340
  160. prefect/_vendor/fastapi/params.py +0 -453
  161. prefect/_vendor/fastapi/requests.py +0 -4
  162. prefect/_vendor/fastapi/responses.py +0 -40
  163. prefect/_vendor/fastapi/routing.py +0 -1331
  164. prefect/_vendor/fastapi/security/__init__.py +0 -15
  165. prefect/_vendor/fastapi/security/api_key.py +0 -98
  166. prefect/_vendor/fastapi/security/base.py +0 -6
  167. prefect/_vendor/fastapi/security/http.py +0 -172
  168. prefect/_vendor/fastapi/security/oauth2.py +0 -227
  169. prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
  170. prefect/_vendor/fastapi/security/utils.py +0 -10
  171. prefect/_vendor/fastapi/staticfiles.py +0 -1
  172. prefect/_vendor/fastapi/templating.py +0 -3
  173. prefect/_vendor/fastapi/testclient.py +0 -1
  174. prefect/_vendor/fastapi/types.py +0 -3
  175. prefect/_vendor/fastapi/utils.py +0 -235
  176. prefect/_vendor/fastapi/websockets.py +0 -7
  177. prefect/_vendor/starlette/__init__.py +0 -1
  178. prefect/_vendor/starlette/_compat.py +0 -28
  179. prefect/_vendor/starlette/_exception_handler.py +0 -80
  180. prefect/_vendor/starlette/_utils.py +0 -88
  181. prefect/_vendor/starlette/applications.py +0 -261
  182. prefect/_vendor/starlette/authentication.py +0 -159
  183. prefect/_vendor/starlette/background.py +0 -43
  184. prefect/_vendor/starlette/concurrency.py +0 -59
  185. prefect/_vendor/starlette/config.py +0 -151
  186. prefect/_vendor/starlette/convertors.py +0 -87
  187. prefect/_vendor/starlette/datastructures.py +0 -707
  188. prefect/_vendor/starlette/endpoints.py +0 -130
  189. prefect/_vendor/starlette/exceptions.py +0 -60
  190. prefect/_vendor/starlette/formparsers.py +0 -276
  191. prefect/_vendor/starlette/middleware/__init__.py +0 -17
  192. prefect/_vendor/starlette/middleware/authentication.py +0 -52
  193. prefect/_vendor/starlette/middleware/base.py +0 -220
  194. prefect/_vendor/starlette/middleware/cors.py +0 -176
  195. prefect/_vendor/starlette/middleware/errors.py +0 -265
  196. prefect/_vendor/starlette/middleware/exceptions.py +0 -74
  197. prefect/_vendor/starlette/middleware/gzip.py +0 -113
  198. prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
  199. prefect/_vendor/starlette/middleware/sessions.py +0 -82
  200. prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
  201. prefect/_vendor/starlette/middleware/wsgi.py +0 -147
  202. prefect/_vendor/starlette/requests.py +0 -328
  203. prefect/_vendor/starlette/responses.py +0 -347
  204. prefect/_vendor/starlette/routing.py +0 -933
  205. prefect/_vendor/starlette/schemas.py +0 -154
  206. prefect/_vendor/starlette/staticfiles.py +0 -248
  207. prefect/_vendor/starlette/status.py +0 -199
  208. prefect/_vendor/starlette/templating.py +0 -231
  209. prefect/_vendor/starlette/testclient.py +0 -804
  210. prefect/_vendor/starlette/types.py +0 -30
  211. prefect/_vendor/starlette/websockets.py +0 -193
  212. prefect/agent.py +0 -698
  213. prefect/deployments/deployments.py +0 -1042
  214. prefect/deprecated/__init__.py +0 -0
  215. prefect/deprecated/data_documents.py +0 -350
  216. prefect/deprecated/packaging/__init__.py +0 -12
  217. prefect/deprecated/packaging/base.py +0 -96
  218. prefect/deprecated/packaging/docker.py +0 -146
  219. prefect/deprecated/packaging/file.py +0 -92
  220. prefect/deprecated/packaging/orion.py +0 -80
  221. prefect/deprecated/packaging/serializers.py +0 -171
  222. prefect/events/instrument.py +0 -135
  223. prefect/infrastructure/base.py +0 -323
  224. prefect/infrastructure/container.py +0 -818
  225. prefect/infrastructure/kubernetes.py +0 -920
  226. prefect/infrastructure/process.py +0 -289
  227. prefect/new_task_engine.py +0 -423
  228. prefect/pydantic/__init__.py +0 -76
  229. prefect/pydantic/main.py +0 -39
  230. prefect/software/__init__.py +0 -2
  231. prefect/software/base.py +0 -50
  232. prefect/software/conda.py +0 -199
  233. prefect/software/pip.py +0 -122
  234. prefect/software/python.py +0 -52
  235. prefect/workers/block.py +0 -218
  236. prefect_client-2.19.2.dist-info/RECORD +0 -292
  237. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/LICENSE +0 -0
  238. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/WHEEL +0 -0
  239. {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -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
- ]
@@ -10,21 +10,15 @@ from typing import (
10
10
  Sequence,
11
11
  Tuple,
12
12
  Union,
13
- cast,
14
13
  )
15
14
  from uuid import UUID, uuid4
16
15
 
17
16
  import pendulum
18
-
19
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
20
-
21
- if HAS_PYDANTIC_V2:
22
- from pydantic.v1 import Field, root_validator, validator
23
- else:
24
- from pydantic import Field, root_validator, validator # type: ignore
17
+ from pydantic import ConfigDict, Field, RootModel, field_validator, model_validator
18
+ from pydantic_extra_types.pendulum_dt import DateTime
19
+ from typing_extensions import Self
25
20
 
26
21
  from prefect._internal.schemas.bases import PrefectBaseModel
27
- from prefect._internal.schemas.fields import DateTimeTZ
28
22
  from prefect.logging import get_logger
29
23
  from prefect.settings import (
30
24
  PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE,
@@ -39,34 +33,24 @@ logger = get_logger(__name__)
39
33
  class Resource(Labelled):
40
34
  """An observable business object of interest to the user"""
41
35
 
42
- @root_validator(pre=True)
43
- def enforce_maximum_labels(cls, values: Dict[str, Any]):
44
- labels = values.get("__root__")
45
- if not isinstance(labels, dict):
46
- return values
47
-
48
- if len(labels) > PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value():
36
+ @model_validator(mode="after")
37
+ def enforce_maximum_labels(self) -> Self:
38
+ if len(self.root) > PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value():
49
39
  raise ValueError(
50
40
  "The maximum number of labels per resource "
51
41
  f"is {PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value()}"
52
42
  )
53
43
 
54
- return values
55
-
56
- @root_validator(pre=True)
57
- def requires_resource_id(cls, values: Dict[str, Any]):
58
- labels = values.get("__root__")
59
- if not isinstance(labels, dict):
60
- return values
44
+ return self
61
45
 
62
- labels = cast(Dict[str, str], labels)
63
-
64
- if "prefect.resource.id" not in labels:
46
+ @model_validator(mode="after")
47
+ def requires_resource_id(self) -> Self:
48
+ if "prefect.resource.id" not in self.root:
65
49
  raise ValueError("Resources must include the prefect.resource.id label")
66
- if not labels["prefect.resource.id"]:
50
+ if not self.root["prefect.resource.id"]:
67
51
  raise ValueError("The prefect.resource.id label must be non-empty")
68
52
 
69
- return values
53
+ return self
70
54
 
71
55
  @property
72
56
  def id(self) -> str:
@@ -80,22 +64,16 @@ class Resource(Labelled):
80
64
  class RelatedResource(Resource):
81
65
  """A Resource with a specific role in an Event"""
82
66
 
83
- @root_validator(pre=True)
84
- def requires_resource_role(cls, values: Dict[str, Any]):
85
- labels = values.get("__root__")
86
- if not isinstance(labels, dict):
87
- return values
88
-
89
- labels = cast(Dict[str, str], labels)
90
-
91
- if "prefect.resource.role" not in labels:
67
+ @model_validator(mode="after")
68
+ def requires_resource_role(self) -> Self:
69
+ if "prefect.resource.role" not in self.root:
92
70
  raise ValueError(
93
71
  "Related Resources must include the prefect.resource.role label"
94
72
  )
95
- if not labels["prefect.resource.role"]:
73
+ if not self.root["prefect.resource.role"]:
96
74
  raise ValueError("The prefect.resource.role label must be non-empty")
97
75
 
98
- return values
76
+ return self
99
77
 
100
78
  @property
101
79
  def role(self) -> str:
@@ -105,7 +83,7 @@ class RelatedResource(Resource):
105
83
  class Event(PrefectBaseModel):
106
84
  """The client-side view of an event that has happened to a Resource"""
107
85
 
108
- occurred: DateTimeTZ = Field(
86
+ occurred: DateTime = Field(
109
87
  default_factory=lambda: pendulum.now("UTC"),
110
88
  description="When the event happened from the sender's perspective",
111
89
  )
@@ -154,7 +132,8 @@ class Event(PrefectBaseModel):
154
132
  resources[related.role].append(related)
155
133
  return resources
156
134
 
157
- @validator("related")
135
+ @field_validator("related")
136
+ @classmethod
158
137
  def enforce_maximum_related_resources(cls, value: List[RelatedResource]):
159
138
  if len(value) > PREFECT_EVENTS_MAXIMUM_RELATED_RESOURCES.value():
160
139
  raise ValueError(
@@ -181,10 +160,9 @@ class ReceivedEvent(Event):
181
160
  """The server-side view of an event that has happened to a Resource after it has
182
161
  been received by the server"""
183
162
 
184
- class Config:
185
- orm_mode = True
163
+ model_config = ConfigDict(from_attributes=True)
186
164
 
187
- received: DateTimeTZ = Field(
165
+ received: DateTime = Field(
188
166
  ...,
189
167
  description="When the event was received by Prefect Cloud",
190
168
  )
@@ -210,35 +188,26 @@ def matches(expected: str, value: Optional[str]) -> bool:
210
188
  return match if positive else not match
211
189
 
212
190
 
213
- class ResourceSpecification(PrefectBaseModel):
214
- """A specification that may match zero, one, or many resources, used to target or
215
- select a set of resources in a query or automation. A resource must match at least
216
- one value of all of the provided labels"""
217
-
218
- __root__: Dict[str, Union[str, List[str]]]
219
-
191
+ class ResourceSpecification(RootModel[Dict[str, Union[str, List[str]]]]):
220
192
  def matches_every_resource(self) -> bool:
221
- return len(self) == 0
193
+ return len(self.root) == 0
222
194
 
223
195
  def matches_every_resource_of_kind(self, prefix: str) -> bool:
224
196
  if self.matches_every_resource():
225
197
  return True
226
-
227
- if len(self.__root__) == 1:
228
- if resource_id := self.__root__.get("prefect.resource.id"):
198
+ if len(self.root) == 1:
199
+ resource_id = self.root.get("prefect.resource.id")
200
+ if resource_id:
229
201
  values = [resource_id] if isinstance(resource_id, str) else resource_id
230
202
  return any(value == f"{prefix}.*" for value in values)
231
-
232
203
  return False
233
204
 
234
205
  def includes(self, candidates: Iterable[Resource]) -> bool:
235
206
  if self.matches_every_resource():
236
207
  return True
237
-
238
208
  for candidate in candidates:
239
209
  if self.matches(candidate):
240
210
  return True
241
-
242
211
  return False
243
212
 
244
213
  def matches(self, resource: Resource) -> bool:
@@ -251,14 +220,14 @@ class ResourceSpecification(PrefectBaseModel):
251
220
  def items(self) -> Iterable[Tuple[str, List[str]]]:
252
221
  return [
253
222
  (label, [value] if isinstance(value, str) else value)
254
- for label, value in self.__root__.items()
223
+ for label, value in self.root.items()
255
224
  ]
256
225
 
257
226
  def __contains__(self, key: str) -> bool:
258
- return self.__root__.__contains__(key)
227
+ return key in self.root
259
228
 
260
229
  def __getitem__(self, key: str) -> List[str]:
261
- value = self.__root__[key]
230
+ value = self.root[key]
262
231
  if not value:
263
232
  return []
264
233
  if not isinstance(value, list):
@@ -268,7 +237,7 @@ class ResourceSpecification(PrefectBaseModel):
268
237
  def pop(
269
238
  self, key: str, default: Optional[Union[str, List[str]]] = None
270
239
  ) -> Optional[List[str]]:
271
- value = self.__root__.pop(key, default)
240
+ value = self.root.pop(key, default)
272
241
  if not value:
273
242
  return []
274
243
  if not isinstance(value, list):
@@ -278,7 +247,7 @@ class ResourceSpecification(PrefectBaseModel):
278
247
  def get(
279
248
  self, key: str, default: Optional[Union[str, List[str]]] = None
280
249
  ) -> Optional[List[str]]:
281
- value = self.__root__.get(key, default)
250
+ value = self.root.get(key, default)
282
251
  if not value:
283
252
  return []
284
253
  if not isinstance(value, list):
@@ -286,7 +255,7 @@ class ResourceSpecification(PrefectBaseModel):
286
255
  return value
287
256
 
288
257
  def __len__(self) -> int:
289
- return len(self.__root__)
258
+ return len(self.root)
290
259
 
291
260
  def deepcopy(self) -> "ResourceSpecification":
292
- return ResourceSpecification.parse_obj(copy.deepcopy(self.__root__))
261
+ return ResourceSpecification(root=copy.deepcopy(self.root))
@@ -1,6 +1,6 @@
1
1
  from typing import Dict, Iterable, Iterator, List, Optional, Tuple
2
2
 
3
- from prefect._internal.schemas.bases import PrefectBaseModel
3
+ from pydantic import RootModel
4
4
 
5
5
 
6
6
  class LabelDiver:
@@ -71,36 +71,32 @@ class LabelDiver:
71
71
  raise AttributeError
72
72
 
73
73
 
74
- class Labelled(PrefectBaseModel, extra="ignore"): # type: ignore[call-arg]
75
- """An object defined by string labels and values"""
76
-
77
- __root__: Dict[str, str]
78
-
74
+ class Labelled(RootModel[Dict[str, str]]):
79
75
  def keys(self) -> Iterable[str]:
80
- return self.__root__.keys()
76
+ return self.root.keys()
81
77
 
82
78
  def items(self) -> Iterable[Tuple[str, str]]:
83
- return self.__root__.items()
79
+ return self.root.items()
84
80
 
85
81
  def __getitem__(self, label: str) -> str:
86
- return self.__root__[label]
82
+ return self.root[label]
87
83
 
88
84
  def __setitem__(self, label: str, value: str) -> str:
89
- self.__root__[label] = value
85
+ self.root[label] = value
90
86
  return value
91
87
 
92
88
  def __contains__(self, key: str) -> bool:
93
- return key in self.__root__
89
+ return key in self.root
94
90
 
95
91
  def get(self, label: str, default: Optional[str] = None) -> Optional[str]:
96
- return self.__root__.get(label, default)
92
+ return self.root.get(label, default)
97
93
 
98
94
  def as_label_value_array(self) -> List[Dict[str, str]]:
99
95
  return [{"label": label, "value": value} for label, value in self.items()]
100
96
 
101
97
  @property
102
98
  def labels(self) -> LabelDiver:
103
- return LabelDiver(self.__root__)
99
+ return LabelDiver(self.root)
104
100
 
105
101
  def has_all_labels(self, labels: Dict[str, str]) -> bool:
106
- return all(self.__root__.get(label) == value for label, value in labels.items())
102
+ return all(self.root.get(label) == value for label, value in labels.items())
@@ -3,8 +3,7 @@ from typing import Any, Dict, List, Optional, Union
3
3
  from uuid import UUID
4
4
 
5
5
  import pendulum
6
-
7
- from prefect._internal.schemas.fields import DateTimeTZ
6
+ from pydantic_extra_types.pendulum_dt import DateTime
8
7
 
9
8
  from .clients import (
10
9
  AssertingEventsClient,
@@ -21,7 +20,7 @@ TIGHT_TIMING = timedelta(minutes=5)
21
20
  def emit_event(
22
21
  event: str,
23
22
  resource: Dict[str, str],
24
- occurred: Optional[DateTimeTZ] = None,
23
+ occurred: Optional[DateTime] = None,
25
24
  related: Optional[Union[List[Dict[str, str]], List[RelatedResource]]] = None,
26
25
  payload: Optional[Dict[str, Any]] = None,
27
26
  id: Optional[UUID] = None,
prefect/events/worker.py CHANGED
@@ -10,7 +10,6 @@ from prefect.settings import (
10
10
  PREFECT_API_KEY,
11
11
  PREFECT_API_URL,
12
12
  PREFECT_CLOUD_API_URL,
13
- PREFECT_EXPERIMENTAL_EVENTS,
14
13
  )
15
14
  from prefect.utilities.context import temporary_context
16
15
 
@@ -42,11 +41,11 @@ def emit_events_to_cloud() -> bool:
42
41
 
43
42
  def should_emit_events_to_running_server() -> bool:
44
43
  api_url = PREFECT_API_URL.value()
45
- return isinstance(api_url, str) and PREFECT_EXPERIMENTAL_EVENTS.value()
44
+ return isinstance(api_url, str)
46
45
 
47
46
 
48
47
  def should_emit_events_to_ephemeral_server() -> bool:
49
- return PREFECT_API_KEY.value() is None and PREFECT_EXPERIMENTAL_EVENTS.value()
48
+ return PREFECT_API_KEY.value() is None
50
49
 
51
50
 
52
51
  class EventsWorker(QueueService[Event]):