prefect-client 2.20.2__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 +423 -164
  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 +667 -440
  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 -2466
  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 +124 -51
  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 +138 -48
  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.2.dist-info → prefect_client-3.0.0.dist-info}/METADATA +30 -26
  161. prefect_client-3.0.0.dist-info/RECORD +201 -0
  162. {prefect_client-2.20.2.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.2.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.2.dist-info → prefect_client-3.0.0.dist-info}/LICENSE +0 -0
  288. {prefect_client-2.20.2.dist-info → prefect_client-3.0.0.dist-info}/top_level.txt +0 -0
@@ -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
61
-
62
- labels = cast(Dict[str, str], labels)
44
+ return self
63
45
 
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:
@@ -76,26 +60,30 @@ class Resource(Labelled):
76
60
  def name(self) -> Optional[str]:
77
61
  return self.get("prefect.resource.name")
78
62
 
63
+ def prefect_object_id(self, kind: str) -> UUID:
64
+ """Extracts the UUID from an event's resource ID if it's the expected kind
65
+ of prefect resource"""
66
+ prefix = f"{kind}." if not kind.endswith(".") else kind
79
67
 
80
- class RelatedResource(Resource):
81
- """A Resource with a specific role in an Event"""
68
+ if not self.id.startswith(prefix):
69
+ raise ValueError(f"Resource ID {self.id} does not start with {prefix}")
82
70
 
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
71
+ return UUID(self.id[len(prefix) :])
88
72
 
89
- labels = cast(Dict[str, str], labels)
90
73
 
91
- if "prefect.resource.role" not in labels:
74
+ class RelatedResource(Resource):
75
+ """A Resource with a specific role in an Event"""
76
+
77
+ @model_validator(mode="after")
78
+ def requires_resource_role(self) -> Self:
79
+ if "prefect.resource.role" not in self.root:
92
80
  raise ValueError(
93
81
  "Related Resources must include the prefect.resource.role label"
94
82
  )
95
- if not labels["prefect.resource.role"]:
83
+ if not self.root["prefect.resource.role"]:
96
84
  raise ValueError("The prefect.resource.role label must be non-empty")
97
85
 
98
- return values
86
+ return self
99
87
 
100
88
  @property
101
89
  def role(self) -> str:
@@ -105,7 +93,9 @@ class RelatedResource(Resource):
105
93
  class Event(PrefectBaseModel):
106
94
  """The client-side view of an event that has happened to a Resource"""
107
95
 
108
- occurred: DateTimeTZ = Field(
96
+ model_config = ConfigDict(extra="ignore")
97
+
98
+ occurred: DateTime = Field(
109
99
  default_factory=lambda: pendulum.now("UTC"),
110
100
  description="When the event happened from the sender's perspective",
111
101
  )
@@ -154,7 +144,8 @@ class Event(PrefectBaseModel):
154
144
  resources[related.role].append(related)
155
145
  return resources
156
146
 
157
- @validator("related")
147
+ @field_validator("related")
148
+ @classmethod
158
149
  def enforce_maximum_related_resources(cls, value: List[RelatedResource]):
159
150
  if len(value) > PREFECT_EVENTS_MAXIMUM_RELATED_RESOURCES.value():
160
151
  raise ValueError(
@@ -181,10 +172,9 @@ class ReceivedEvent(Event):
181
172
  """The server-side view of an event that has happened to a Resource after it has
182
173
  been received by the server"""
183
174
 
184
- class Config:
185
- orm_mode = True
175
+ model_config = ConfigDict(from_attributes=True)
186
176
 
187
- received: DateTimeTZ = Field(
177
+ received: DateTime = Field(
188
178
  ...,
189
179
  description="When the event was received by Prefect Cloud",
190
180
  )
@@ -210,35 +200,26 @@ def matches(expected: str, value: Optional[str]) -> bool:
210
200
  return match if positive else not match
211
201
 
212
202
 
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
-
203
+ class ResourceSpecification(RootModel[Dict[str, Union[str, List[str]]]]):
220
204
  def matches_every_resource(self) -> bool:
221
- return len(self) == 0
205
+ return len(self.root) == 0
222
206
 
223
207
  def matches_every_resource_of_kind(self, prefix: str) -> bool:
224
208
  if self.matches_every_resource():
225
209
  return True
226
-
227
- if len(self.__root__) == 1:
228
- if resource_id := self.__root__.get("prefect.resource.id"):
210
+ if len(self.root) == 1:
211
+ resource_id = self.root.get("prefect.resource.id")
212
+ if resource_id:
229
213
  values = [resource_id] if isinstance(resource_id, str) else resource_id
230
214
  return any(value == f"{prefix}.*" for value in values)
231
-
232
215
  return False
233
216
 
234
217
  def includes(self, candidates: Iterable[Resource]) -> bool:
235
218
  if self.matches_every_resource():
236
219
  return True
237
-
238
220
  for candidate in candidates:
239
221
  if self.matches(candidate):
240
222
  return True
241
-
242
223
  return False
243
224
 
244
225
  def matches(self, resource: Resource) -> bool:
@@ -251,14 +232,14 @@ class ResourceSpecification(PrefectBaseModel):
251
232
  def items(self) -> Iterable[Tuple[str, List[str]]]:
252
233
  return [
253
234
  (label, [value] if isinstance(value, str) else value)
254
- for label, value in self.__root__.items()
235
+ for label, value in self.root.items()
255
236
  ]
256
237
 
257
238
  def __contains__(self, key: str) -> bool:
258
- return self.__root__.__contains__(key)
239
+ return key in self.root
259
240
 
260
241
  def __getitem__(self, key: str) -> List[str]:
261
- value = self.__root__[key]
242
+ value = self.root[key]
262
243
  if not value:
263
244
  return []
264
245
  if not isinstance(value, list):
@@ -268,7 +249,7 @@ class ResourceSpecification(PrefectBaseModel):
268
249
  def pop(
269
250
  self, key: str, default: Optional[Union[str, List[str]]] = None
270
251
  ) -> Optional[List[str]]:
271
- value = self.__root__.pop(key, default)
252
+ value = self.root.pop(key, default)
272
253
  if not value:
273
254
  return []
274
255
  if not isinstance(value, list):
@@ -278,7 +259,7 @@ class ResourceSpecification(PrefectBaseModel):
278
259
  def get(
279
260
  self, key: str, default: Optional[Union[str, List[str]]] = None
280
261
  ) -> Optional[List[str]]:
281
- value = self.__root__.get(key, default)
262
+ value = self.root.get(key, default)
282
263
  if not value:
283
264
  return []
284
265
  if not isinstance(value, list):
@@ -286,7 +267,7 @@ class ResourceSpecification(PrefectBaseModel):
286
267
  return value
287
268
 
288
269
  def __len__(self) -> int:
289
- return len(self.__root__)
270
+ return len(self.root)
290
271
 
291
272
  def deepcopy(self) -> "ResourceSpecification":
292
- return ResourceSpecification.parse_obj(copy.deepcopy(self.__root__))
273
+ 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,13 +3,12 @@ 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,
10
+ AssertingPassthroughEventsClient,
11
11
  PrefectCloudEventsClient,
12
- PrefectEphemeralEventsClient,
13
12
  PrefectEventsClient,
14
13
  )
15
14
  from .schemas.events import Event, RelatedResource
@@ -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,
@@ -51,10 +50,10 @@ def emit_event(
51
50
  return None
52
51
 
53
52
  operational_clients = [
53
+ AssertingPassthroughEventsClient,
54
54
  AssertingEventsClient,
55
55
  PrefectCloudEventsClient,
56
56
  PrefectEventsClient,
57
- PrefectEphemeralEventsClient,
58
57
  ]
59
58
  worker_instance = EventsWorker.instance()
60
59
 
prefect/events/worker.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from contextlib import asynccontextmanager
2
2
  from contextvars import Context, copy_context
3
- from typing import Any, Dict, Optional, Tuple, Type
3
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Type
4
4
  from uuid import UUID
5
5
 
6
6
  from typing_extensions import Self
@@ -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
 
@@ -18,12 +17,14 @@ from .clients import (
18
17
  EventsClient,
19
18
  NullEventsClient,
20
19
  PrefectCloudEventsClient,
21
- PrefectEphemeralEventsClient,
22
20
  PrefectEventsClient,
23
21
  )
24
22
  from .related import related_resources_from_run_context
25
23
  from .schemas.events import Event
26
24
 
25
+ if TYPE_CHECKING:
26
+ from prefect.client.orchestration import PrefectClient
27
+
27
28
 
28
29
  def should_emit_events() -> bool:
29
30
  return (
@@ -42,11 +43,11 @@ def emit_events_to_cloud() -> bool:
42
43
 
43
44
  def should_emit_events_to_running_server() -> bool:
44
45
  api_url = PREFECT_API_URL.value()
45
- return isinstance(api_url, str) and PREFECT_EXPERIMENTAL_EVENTS.value()
46
+ return isinstance(api_url, str)
46
47
 
47
48
 
48
49
  def should_emit_events_to_ephemeral_server() -> bool:
49
- return PREFECT_API_KEY.value() is None and PREFECT_EXPERIMENTAL_EVENTS.value()
50
+ return PREFECT_API_KEY.value() is None
50
51
 
51
52
 
52
53
  class EventsWorker(QueueService[Event]):
@@ -57,14 +58,18 @@ class EventsWorker(QueueService[Event]):
57
58
  self.client_type = client_type
58
59
  self.client_options = client_options
59
60
  self._client: EventsClient
61
+ self._orchestration_client: "PrefectClient"
60
62
  self._context_cache: Dict[UUID, Context] = {}
61
63
 
62
64
  @asynccontextmanager
63
65
  async def _lifespan(self):
64
66
  self._client = self.client_type(**{k: v for k, v in self.client_options})
67
+ from prefect.client.orchestration import get_client
65
68
 
69
+ self._orchestration_client = get_client()
66
70
  async with self._client:
67
- yield
71
+ async with self._orchestration_client:
72
+ yield
68
73
 
69
74
  def _prepare_item(self, event: Event) -> Event:
70
75
  self._context_cache[event.id] = copy_context()
@@ -79,7 +84,9 @@ class EventsWorker(QueueService[Event]):
79
84
 
80
85
  async def attach_related_resources_from_context(self, event: Event):
81
86
  exclude = {resource.id for resource in event.involved_resources}
82
- event.related += await related_resources_from_run_context(exclude=exclude)
87
+ event.related += await related_resources_from_run_context(
88
+ client=self._orchestration_client, exclude=exclude
89
+ )
83
90
 
84
91
  @classmethod
85
92
  def instance(
@@ -98,7 +105,15 @@ class EventsWorker(QueueService[Event]):
98
105
  elif should_emit_events_to_running_server():
99
106
  client_type = PrefectEventsClient
100
107
  elif should_emit_events_to_ephemeral_server():
101
- client_type = PrefectEphemeralEventsClient
108
+ # create an ephemeral API if none was provided
109
+ from prefect.server.api.server import SubprocessASGIServer
110
+
111
+ server = SubprocessASGIServer()
112
+ server.start()
113
+ assert server.server_process is not None, "Server process did not start"
114
+
115
+ client_kwargs = {"api_url": server.api_url}
116
+ client_type = PrefectEventsClient
102
117
  else:
103
118
  client_type = NullEventsClient
104
119
 
prefect/exceptions.py CHANGED
@@ -403,3 +403,18 @@ class FlowPauseTimeout(PrefectException):
403
403
 
404
404
  class FlowRunWaitTimeout(PrefectException):
405
405
  """Raised when a flow run takes longer than a given timeout"""
406
+
407
+
408
+ class PrefectImportError(ImportError):
409
+ """
410
+ An error raised when a Prefect object cannot be imported due to a move or removal.
411
+ """
412
+
413
+ def __init__(self, message: str) -> None:
414
+ super().__init__(message)
415
+
416
+
417
+ class SerializationError(PrefectException):
418
+ """
419
+ Raised when an object cannot be serialized.
420
+ """