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