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
prefect/__init__.py CHANGED
@@ -5,8 +5,6 @@
5
5
  from . import _version
6
6
  import importlib
7
7
  import pathlib
8
- import warnings
9
- import sys
10
8
 
11
9
  __version_info__ = _version.get_versions()
12
10
  __version__ = __version_info__["version"]
@@ -31,12 +29,13 @@ from prefect.deployments import deploy
31
29
  from prefect.states import State
32
30
  from prefect.logging import get_run_logger
33
31
  from prefect.flows import flow, Flow, serve
32
+ from prefect.transactions import Transaction
34
33
  from prefect.tasks import task, Task
35
34
  from prefect.context import tags
36
35
  from prefect.manifests import Manifest
37
36
  from prefect.utilities.annotations import unmapped, allow_failure
38
37
  from prefect.results import BaseResult
39
- from prefect.engine import pause_flow_run, resume_flow_run, suspend_flow_run
38
+ from prefect.flow_runs import pause_flow_run, resume_flow_run, suspend_flow_run
40
39
  from prefect.client.orchestration import get_client, PrefectClient
41
40
  from prefect.client.cloud import get_cloud_client, CloudClient
42
41
  import prefect.variables
@@ -44,14 +43,9 @@ import prefect.runtime
44
43
 
45
44
  # Import modules that register types
46
45
  import prefect.serializers
47
- import prefect.deprecated.data_documents
48
- import prefect.deprecated.packaging
49
46
  import prefect.blocks.kubernetes
50
47
  import prefect.blocks.notifications
51
48
  import prefect.blocks.system
52
- import prefect.infrastructure.process
53
- import prefect.infrastructure.kubernetes
54
- import prefect.infrastructure.container
55
49
 
56
50
  # Initialize the process-wide profile and registry at import time
57
51
  import prefect.context
@@ -61,14 +55,11 @@ prefect.context.initialize_object_registry()
61
55
  # Perform any forward-ref updates needed for Pydantic models
62
56
  import prefect.client.schemas
63
57
 
64
- prefect.context.FlowRunContext.update_forward_refs(Flow=Flow)
65
- prefect.context.TaskRunContext.update_forward_refs(Task=Task)
66
- prefect.client.schemas.State.update_forward_refs(
67
- BaseResult=BaseResult, DataDocument=prefect.deprecated.data_documents.DataDocument
68
- )
69
- prefect.client.schemas.StateCreate.update_forward_refs(
70
- BaseResult=BaseResult, DataDocument=prefect.deprecated.data_documents.DataDocument
71
- )
58
+ prefect.context.FlowRunContext.model_rebuild()
59
+ prefect.context.TaskRunContext.model_rebuild()
60
+ prefect.client.schemas.State.model_rebuild()
61
+ prefect.client.schemas.StateCreate.model_rebuild()
62
+ Transaction.model_rebuild()
72
63
 
73
64
 
74
65
  prefect.plugins.load_extra_entrypoints()
@@ -82,57 +73,17 @@ prefect.logging.get_logger("profiles").debug(
82
73
  )
83
74
 
84
75
  # Ensure moved names are accessible at old locations
85
- import prefect.client
86
-
87
76
  prefect.client.get_client = get_client
88
77
  prefect.client.PrefectClient = PrefectClient
89
78
 
90
79
 
91
80
  from prefect._internal.compatibility.deprecated import (
92
81
  inject_renamed_module_alias_finder,
93
- register_renamed_module,
94
82
  )
95
83
 
96
- register_renamed_module(
97
- "prefect.packaging", "prefect.deprecated.packaging", start_date="Mar 2024"
98
- )
99
84
  inject_renamed_module_alias_finder()
100
85
 
101
86
 
102
- # Attempt to warn users who are importing Prefect 1.x attributes that they may
103
- # have accidentally installed Prefect 2.x
104
-
105
- PREFECT_1_ATTRIBUTES = [
106
- "prefect.Client",
107
- "prefect.Parameter",
108
- "prefect.api",
109
- "prefect.apply_map",
110
- "prefect.case",
111
- "prefect.config",
112
- "prefect.context",
113
- "prefect.flatten",
114
- "prefect.mapped",
115
- "prefect.models",
116
- "prefect.resource_manager",
117
- ]
118
-
119
-
120
- class Prefect1ImportInterceptor(importlib.abc.Loader):
121
- def find_spec(self, fullname, path, target=None):
122
- if fullname in PREFECT_1_ATTRIBUTES:
123
- warnings.warn(
124
- f"Attempted import of {fullname!r}, which is part of Prefect 1.x, while"
125
- f" Prefect {__version__} is installed. If you're upgrading you'll need"
126
- " to update your code, see the Prefect 2.x migration guide:"
127
- " `https://orion-docs.prefect.io/migration_guide/`. Otherwise ensure"
128
- " that your code is pinned to the expected version."
129
- )
130
-
131
-
132
- if not hasattr(sys, "frozen"):
133
- sys.meta_path.insert(0, Prefect1ImportInterceptor())
134
-
135
-
136
87
  # Declare API for type-checkers
137
88
  __all__ = [
138
89
  "allow_failure",
@@ -145,6 +96,7 @@ __all__ = [
145
96
  "tags",
146
97
  "task",
147
98
  "Task",
99
+ "Transaction",
148
100
  "unmapped",
149
101
  "serve",
150
102
  "deploy",
@@ -9,21 +9,14 @@ Deprecated items require a start or end date. If a start date is given, the end
9
9
  will be calculated 6 months later. Start and end dates are always in the format MMM YYYY
10
10
  e.g. Jan 2023.
11
11
  """
12
+
12
13
  import functools
13
14
  import sys
14
15
  import warnings
15
- from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union
16
+ from typing import Any, Callable, List, Optional, Type, TypeVar
16
17
 
17
18
  import pendulum
18
-
19
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
20
-
21
- if HAS_PYDANTIC_V2:
22
- from pydantic.v1 import BaseModel, Field, root_validator
23
- from pydantic.v1.schema import default_ref_template
24
- else:
25
- from pydantic import BaseModel, Field, root_validator
26
- from pydantic.schema import default_ref_template
19
+ from pydantic import BaseModel
27
20
 
28
21
  from prefect.utilities.callables import get_call_parameters
29
22
  from prefect.utilities.importtools import (
@@ -237,9 +230,10 @@ def deprecated_field(
237
230
 
238
231
  cls_init(__pydantic_self__, **data)
239
232
 
240
- field = __pydantic_self__.__fields__.get(name)
233
+ field = __pydantic_self__.model_fields.get(name)
241
234
  if field is not None:
242
- field.field_info.extra["deprecated"] = True
235
+ field.json_schema_extra = field.json_schema_extra or {}
236
+ field.json_schema_extra["deprecated"] = True
243
237
 
244
238
  # Patch the model's init method
245
239
  model_cls.__init__ = __init__
@@ -278,106 +272,3 @@ def register_renamed_module(old_name: str, new_name: str, start_date: str):
278
272
  DEPRECATED_MODULE_ALIASES.append(
279
273
  AliasedModuleDefinition(old_name, new_name, callback)
280
274
  )
281
-
282
-
283
- class DeprecatedInfraOverridesField(BaseModel):
284
- """
285
- A model mixin that handles the deprecated `infra_overrides` field.
286
-
287
- The `infra_overrides` field has been renamed to `job_variables`. This mixin maintains
288
- backwards compatibility with users of the `infra_overrides` field while presenting
289
- `job_variables` as the user-facing field.
290
-
291
- When we remove support for `infra_overrides`, we can remove this class as a parent of
292
- all schemas that use it, leaving them with only the `job_variables` field.
293
- """
294
-
295
- infra_overrides: Optional[Dict[str, Any]] = Field(
296
- default_factory=dict,
297
- description="Deprecated field. Use `job_variables` instead.",
298
- )
299
-
300
- @root_validator(pre=True)
301
- def _job_variables_from_infra_overrides(
302
- cls, values: Dict[str, Any]
303
- ) -> Dict[str, Any]:
304
- """
305
- Validate that only one of `infra_overrides` or `job_variables` is used
306
- and keep them in sync during init.
307
- """
308
- job_variables = values.get("job_variables")
309
- infra_overrides = values.get("infra_overrides")
310
-
311
- if job_variables is not None and infra_overrides is not None:
312
- if job_variables != infra_overrides:
313
- raise ValueError(
314
- "The `infra_overrides` field has been renamed to `job_variables`."
315
- "Use one of these fields, but not both."
316
- )
317
- return values
318
- elif job_variables is not None and infra_overrides is None:
319
- values["infra_overrides"] = job_variables
320
- elif job_variables is None and infra_overrides is not None:
321
- values["job_variables"] = infra_overrides
322
- return values
323
-
324
- def __setattr__(self, key: str, value: Any) -> None:
325
- """
326
- Override the default __setattr__ to ensure that setting `infra_overrides` or
327
- `job_variables` will update both fields.
328
- """
329
- if key == "infra_overrides" or key == "job_variables":
330
- updates = {"infra_overrides": value, "job_variables": value}
331
- self.__dict__.update(updates)
332
- return
333
- super().__setattr__(key, value)
334
-
335
- def dict(self, **kwargs) -> Dict[str, Any]:
336
- """
337
- Override the default dict method to ensure only `infra_overrides` is serialized.
338
- This preserves backwards compatibility for newer clients talking to older servers.
339
- """
340
- exclude: Union[set, Dict[str, Any]] = kwargs.pop("exclude", set())
341
- exclude_type = type(exclude)
342
-
343
- if exclude_type is set:
344
- exclude.add("job_variables")
345
- elif exclude_type is dict:
346
- exclude["job_variables"] = True
347
- else:
348
- exclude = {"job_variables"}
349
- kwargs["exclude"] = exclude
350
-
351
- return super().dict(**kwargs)
352
-
353
- @classmethod
354
- def schema(
355
- cls, by_alias: bool = True, ref_template: str = default_ref_template
356
- ) -> Dict[str, Any]:
357
- """
358
- Don't use the mixin docstring as the description if this class is missing a
359
- docstring.
360
- """
361
- schema = super().schema(by_alias=by_alias, ref_template=ref_template)
362
-
363
- if not cls.__doc__:
364
- schema.pop("description", None)
365
-
366
- return schema
367
-
368
-
369
- def handle_deprecated_infra_overrides_parameter(
370
- job_variables: Dict[str, Any], infra_overrides: Dict[str, Any]
371
- ) -> Optional[Dict[str, Any]]:
372
- if infra_overrides is not None and job_variables is not None:
373
- raise RuntimeError(
374
- "The `infra_overrides` argument has been renamed to `job_variables`."
375
- "Use one or the other, but not both."
376
- )
377
- elif infra_overrides is not None and job_variables is None:
378
- jv = infra_overrides
379
- elif job_variables is not None and infra_overrides is None:
380
- jv = job_variables
381
- else:
382
- jv = None
383
- return jv
@@ -13,21 +13,11 @@ Some experimental features require opt-in to enable any usage. These require the
13
13
 
14
14
  import functools
15
15
  import warnings
16
- from typing import Any, Callable, Optional, Set, Type, TypeVar
16
+ from typing import Any, Callable, Optional, Set, TypeVar
17
17
 
18
- from prefect._internal.pydantic import HAS_PYDANTIC_V2
18
+ import pydantic
19
19
 
20
- if HAS_PYDANTIC_V2:
21
- import pydantic.v1 as pydantic
22
- else:
23
- import pydantic
24
-
25
- from prefect.settings import (
26
- PREFECT_EXPERIMENTAL_WARN,
27
- SETTING_VARIABLES,
28
- Setting,
29
- automation_settings_enabled,
30
- )
20
+ from prefect.settings import PREFECT_EXPERIMENTAL_WARN, SETTING_VARIABLES, Setting
31
21
  from prefect.utilities.callables import get_call_parameters
32
22
 
33
23
  T = TypeVar("T", bound=Callable[..., Any])
@@ -194,77 +184,12 @@ def experimental_parameter(
194
184
  return decorator
195
185
 
196
186
 
197
- def experimental_field(
198
- name: str,
199
- *,
200
- group: str,
201
- help: str = "",
202
- stacklevel: int = 2,
203
- opt_in: bool = False,
204
- when: Optional[Callable[[Any], bool]] = None,
205
- ):
206
- """
207
- Mark a field in a Pydantic model as experimental.
208
-
209
- Raises warning only if the field is specified during init.
210
-
211
- Example:
212
-
213
- ```python
214
-
215
- @experimental_parameter("y", group="example", when=lambda y: y is not None)
216
- def foo(x, y = None):
217
- return x + 1 + (y or 0)
218
- ```
219
- """
220
-
221
- when = when or (lambda _: True)
222
-
223
- @experimental(
224
- group=group,
225
- feature=f"The field {name!r}",
226
- help=help,
227
- opt_in=opt_in,
228
- stacklevel=stacklevel + 2,
229
- )
230
- def experimental_check():
231
- """Utility function for performing a warning check for the specified group"""
232
-
233
- # Replaces the model's __init__ method with one that performs an additional warning
234
- # check
235
- def decorator(model_cls: Type[M]) -> Type[M]:
236
- cls_init = model_cls.__init__
237
-
238
- @functools.wraps(model_cls.__init__)
239
- def __init__(__pydantic_self__, **data: Any) -> None:
240
- # Call the original init
241
- cls_init(__pydantic_self__, **data)
242
- # Perform warning check
243
- if name in data.keys() and when(data[name]):
244
- experimental_check()
245
- field = __pydantic_self__.__fields__.get(name)
246
- if field is not None:
247
- field.field_info.extra["experimental"] = True
248
- field.field_info.extra["experimental-group"] = group
249
-
250
- # Patch the model's init method
251
- model_cls.__init__ = __init__
252
-
253
- return model_cls
254
-
255
- return decorator
256
-
257
-
258
187
  def enabled_experiments() -> Set[str]:
259
188
  """
260
189
  Return the set of all enabled experiments.
261
190
  """
262
- enabled_experimental_settings = {
191
+ return {
263
192
  name[len("PREFECT_EXPERIMENTAL_ENABLE_") :].lower()
264
193
  for name, setting in SETTING_VARIABLES.items()
265
194
  if name.startswith("PREFECT_EXPERIMENTAL_ENABLE_") and setting.value()
266
195
  }
267
- if automation_settings_enabled():
268
- enabled_experimental_settings.add("automations")
269
-
270
- return enabled_experimental_settings
@@ -6,7 +6,6 @@ import abc
6
6
  import asyncio
7
7
  import concurrent.futures
8
8
  import contextlib
9
- import threading
10
9
  from typing import (
11
10
  Awaitable,
12
11
  Callable,
@@ -19,7 +18,6 @@ from typing import (
19
18
 
20
19
  from typing_extensions import ParamSpec
21
20
 
22
- from prefect._internal.concurrency.calls import get_current_call
23
21
  from prefect._internal.concurrency.threads import (
24
22
  WorkerThread,
25
23
  get_global_loop,
@@ -29,7 +27,6 @@ from prefect._internal.concurrency.waiters import (
29
27
  AsyncWaiter,
30
28
  Call,
31
29
  SyncWaiter,
32
- get_waiter_for_thread,
33
30
  )
34
31
 
35
32
  P = ParamSpec("P")
@@ -163,22 +160,6 @@ class from_async(_base):
163
160
  await waiter.wait()
164
161
  return call.result()
165
162
 
166
- @staticmethod
167
- def call_soon_in_waiting_thread(
168
- __call: Union[Callable[[], T], Call[T]],
169
- thread: threading.Thread,
170
- timeout: Optional[float] = None,
171
- ) -> Call[T]:
172
- call = _cast_to_call(__call)
173
- parent_call = get_current_call()
174
- waiter = get_waiter_for_thread(thread, parent_call)
175
- if waiter is None:
176
- raise RuntimeError(f"No waiter found for thread {thread}.")
177
-
178
- call.set_timeout(timeout)
179
- waiter.submit(call)
180
- return call
181
-
182
163
  @staticmethod
183
164
  def call_in_new_thread(
184
165
  __call: Union[Callable[[], T], Call[T]], timeout: Optional[float] = None
@@ -231,21 +212,6 @@ class from_sync(_base):
231
212
  waiter.wait()
232
213
  return call.result()
233
214
 
234
- @staticmethod
235
- def call_soon_in_waiting_thread(
236
- __call: Union[Callable[[], T], Call[T]],
237
- thread: threading.Thread,
238
- timeout: Optional[float] = None,
239
- ) -> Call[T]:
240
- call = _cast_to_call(__call)
241
- waiter = get_waiter_for_thread(thread)
242
- if waiter is None:
243
- raise RuntimeError(f"No waiter found for thread {thread}.")
244
-
245
- call.set_timeout(timeout)
246
- waiter.submit(call)
247
- return call
248
-
249
215
  @staticmethod
250
216
  def call_in_new_thread(
251
217
  __call: Union[Callable[[], T], Call[T]], timeout: Optional[float] = None
@@ -49,12 +49,6 @@ current_call: contextvars.ContextVar["weakref.ref[Call]"] = ( # novm
49
49
  _ASYNC_TASK_REFS = set()
50
50
 
51
51
 
52
- def get_current_call() -> Optional["Call"]:
53
- call_ref = current_call.get(None)
54
- if call_ref:
55
- return call_ref()
56
-
57
-
58
52
  @contextlib.contextmanager
59
53
  def set_current_call(call: "Call"):
60
54
  token = current_call.set(weakref.ref(call))
@@ -76,9 +76,6 @@ class ThreadShield:
76
76
 
77
77
 
78
78
  class CancelledError(asyncio.CancelledError):
79
- # In Python 3.7, `asyncio.CancelledError` is identical to `concurrent.futures.CancelledError`
80
- # but in 3.8+ it is a separate class that inherits from `BaseException` instead
81
- # See https://bugs.python.org/issue32528
82
79
  # We want our `CancelledError` to be treated as a `BaseException` and defining it
83
80
  # here simplifies downstream logic that needs to know "which" cancelled error to
84
81
  # handle.
@@ -25,26 +25,6 @@ def get_running_loop() -> Optional[asyncio.BaseEventLoop]:
25
25
  return None
26
26
 
27
27
 
28
- def call_in_loop(
29
- __loop: asyncio.AbstractEventLoop,
30
- __fn: Callable[P, T],
31
- *args: P.args,
32
- **kwargs: P.kwargs,
33
- ) -> T:
34
- """
35
- Run a synchronous call in event loop's thread from another thread.
36
-
37
- This function is blocking and not safe to call from an asynchronous context.
38
-
39
- Returns the result of the call.
40
- """
41
- if __loop is get_running_loop():
42
- return __fn(*args, **kwargs)
43
- else:
44
- future = call_soon_in_loop(__loop, __fn, *args, **kwargs)
45
- return future.result()
46
-
47
-
48
28
  def call_soon_in_loop(
49
29
  __loop: asyncio.AbstractEventLoop,
50
30
  __fn: Callable[P, T],
@@ -7,10 +7,10 @@ import linecache
7
7
  import sys
8
8
  import threading
9
9
  from types import FrameType
10
- from typing import List
10
+ from typing import List, Optional
11
11
 
12
12
  """
13
- The following functions are derived from dask/distributed which is licensed under the
13
+ The following functions are derived from dask/distributed which is licensed under the
14
14
  BSD 3-Clause License.
15
15
 
16
16
  Copyright (c) 2015, Anaconda, Inc. and contributors
@@ -75,7 +75,7 @@ def repr_frame(frame: FrameType) -> str:
75
75
  def call_stack(frame: FrameType) -> List[str]:
76
76
  """Create a call text stack from a frame"""
77
77
  L = []
78
- cur_frame: FrameType | None = frame
78
+ cur_frame: Optional[FrameType] = frame
79
79
  while cur_frame:
80
80
  L.append(repr_frame(cur_frame))
81
81
  cur_frame = cur_frame.f_back
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Utilities for managing worker threads.
3
3
  """
4
+
4
5
  import asyncio
5
6
  import atexit
6
7
  import concurrent.futures
@@ -233,7 +234,10 @@ class EventLoopThread(Portal):
233
234
  self.shutdown()
234
235
 
235
236
 
237
+ # the GLOBAL LOOP is used for background services, like logs
236
238
  GLOBAL_LOOP: Optional[EventLoopThread] = None
239
+ # the RUN SYNC LOOP is used exclusively for running async functions in a sync context via asyncutils.run_sync
240
+ RUN_SYNC_LOOP: Optional[EventLoopThread] = None
237
241
 
238
242
 
239
243
  def get_global_loop() -> EventLoopThread:
@@ -267,6 +271,37 @@ def in_global_loop() -> bool:
267
271
  return get_global_loop()._loop == get_running_loop()
268
272
 
269
273
 
274
+ def get_run_sync_loop() -> EventLoopThread:
275
+ """
276
+ Get the run_sync loop thread.
277
+
278
+ Creates a new one if there is not one available.
279
+ """
280
+ global RUN_SYNC_LOOP
281
+
282
+ # Create a new worker on first call or if the existing worker is dead
283
+ if (
284
+ RUN_SYNC_LOOP is None
285
+ or not RUN_SYNC_LOOP.thread.is_alive()
286
+ or RUN_SYNC_LOOP._shutdown_event.is_set()
287
+ ):
288
+ RUN_SYNC_LOOP = EventLoopThread(daemon=True, name="RunSyncEventLoopThread")
289
+ RUN_SYNC_LOOP.start()
290
+
291
+ return RUN_SYNC_LOOP
292
+
293
+
294
+ def in_run_sync_loop() -> bool:
295
+ """
296
+ Check if called from the global loop.
297
+ """
298
+ if RUN_SYNC_LOOP is None:
299
+ # Avoid creating a global loop if there isn't one
300
+ return False
301
+
302
+ return get_run_sync_loop()._loop == get_running_loop()
303
+
304
+
270
305
  def wait_for_global_loop_exit(timeout: Optional[float] = None) -> None:
271
306
  """
272
307
  Shutdown the global loop and wait for it to exit.
@@ -29,34 +29,6 @@ _WAITERS_BY_THREAD: "WeakKeyDictionary[threading.Thread, deque[Waiter]]" = (
29
29
  )
30
30
 
31
31
 
32
- def get_waiter_for_thread(
33
- thread: threading.Thread, parent_call: Optional[Call] = None
34
- ) -> Optional["Waiter"]:
35
- """
36
- Get the current waiter for a thread and an optional parent call.
37
-
38
- To avoid assigning outer callbacks to inner waiters in the case of nested calls,
39
- the parent call is used to determine which waiter to return. If a parent call is
40
- not provided, we return the most recently created waiter (last in the stack).
41
-
42
- see https://github.com/PrefectHQ/prefect/issues/12036
43
-
44
- Returns `None` if no active waiter is found for the thread.
45
- """
46
-
47
- waiters: "Optional[deque[Waiter]]" = _WAITERS_BY_THREAD.get(thread)
48
-
49
- if waiters and (active_waiters := [w for w in waiters if not w.call_is_done()]):
50
- if parent_call and (
51
- matching_waiter := next(
52
- (w for w in active_waiters if w._call == parent_call), None
53
- )
54
- ): # if exists an active waiter responsible for the parent call, return it
55
- return matching_waiter
56
- else: # otherwise, return the most recently created waiter
57
- return active_waiters[-1]
58
-
59
-
60
32
  def add_waiter_for_thread(waiter: "Waiter", thread: threading.Thread):
61
33
  """
62
34
  Add a waiter for a thread.
@@ -1,46 +1 @@
1
- ### A convenience module to allow for easy switching between pydantic versions.
2
1
 
3
- ### Note this introduces a marginally worse import time, since
4
- ### the import of any one of these symbols will import all of them.
5
-
6
- ### This is a tradeoff we're willing to make for now until pydantic v1 is
7
- ### no longer supported.
8
-
9
-
10
- from ._flags import HAS_PYDANTIC_V2
11
-
12
- from ._compat import (
13
- model_dump,
14
- model_json_schema,
15
- model_validate,
16
- model_dump_json,
17
- model_copy,
18
- model_validate_json,
19
- TypeAdapter,
20
- validate_python,
21
- BaseModel,
22
- Field,
23
- FieldInfo,
24
- field_validator,
25
- model_validator,
26
- )
27
-
28
- from ._types import IncEx
29
-
30
- __all__ = [
31
- "model_dump",
32
- "model_json_schema",
33
- "model_validate",
34
- "IncEx",
35
- "model_dump_json",
36
- "model_copy",
37
- "model_validate_json",
38
- "TypeAdapter",
39
- "validate_python",
40
- "BaseModel",
41
- "HAS_PYDANTIC_V2",
42
- "Field",
43
- "FieldInfo",
44
- "field_validator",
45
- "model_validator",
46
- ]