prefect-client 2.19.3__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.
- prefect/__init__.py +8 -56
- prefect/_internal/compatibility/deprecated.py +6 -115
- prefect/_internal/compatibility/experimental.py +4 -79
- prefect/_internal/concurrency/api.py +0 -34
- prefect/_internal/concurrency/calls.py +0 -6
- prefect/_internal/concurrency/cancellation.py +0 -3
- prefect/_internal/concurrency/event_loop.py +0 -20
- prefect/_internal/concurrency/inspection.py +3 -3
- prefect/_internal/concurrency/threads.py +35 -0
- prefect/_internal/concurrency/waiters.py +0 -28
- prefect/_internal/pydantic/__init__.py +0 -45
- prefect/_internal/pydantic/v1_schema.py +21 -22
- prefect/_internal/pydantic/v2_schema.py +0 -2
- prefect/_internal/pydantic/v2_validated_func.py +18 -23
- prefect/_internal/schemas/bases.py +44 -177
- prefect/_internal/schemas/fields.py +1 -43
- prefect/_internal/schemas/validators.py +60 -158
- prefect/artifacts.py +161 -14
- prefect/automations.py +39 -4
- prefect/blocks/abstract.py +1 -1
- prefect/blocks/core.py +268 -148
- prefect/blocks/fields.py +2 -57
- prefect/blocks/kubernetes.py +8 -12
- prefect/blocks/notifications.py +40 -20
- prefect/blocks/system.py +22 -11
- prefect/blocks/webhook.py +2 -9
- prefect/client/base.py +4 -4
- prefect/client/cloud.py +8 -13
- prefect/client/orchestration.py +347 -341
- prefect/client/schemas/actions.py +92 -86
- prefect/client/schemas/filters.py +20 -40
- prefect/client/schemas/objects.py +147 -145
- prefect/client/schemas/responses.py +16 -24
- prefect/client/schemas/schedules.py +47 -35
- prefect/client/subscriptions.py +2 -2
- prefect/client/utilities.py +5 -2
- prefect/concurrency/asyncio.py +3 -1
- prefect/concurrency/events.py +1 -1
- prefect/concurrency/services.py +6 -3
- prefect/context.py +195 -27
- prefect/deployments/__init__.py +5 -6
- prefect/deployments/base.py +7 -5
- prefect/deployments/flow_runs.py +185 -0
- prefect/deployments/runner.py +50 -45
- prefect/deployments/schedules.py +28 -23
- prefect/deployments/steps/__init__.py +0 -1
- prefect/deployments/steps/core.py +1 -0
- prefect/deployments/steps/pull.py +7 -21
- prefect/engine.py +12 -2422
- prefect/events/actions.py +17 -23
- prefect/events/cli/automations.py +19 -6
- prefect/events/clients.py +14 -37
- prefect/events/filters.py +14 -18
- prefect/events/related.py +2 -2
- prefect/events/schemas/__init__.py +0 -5
- prefect/events/schemas/automations.py +55 -46
- prefect/events/schemas/deployment_triggers.py +7 -197
- prefect/events/schemas/events.py +34 -65
- prefect/events/schemas/labelling.py +10 -14
- prefect/events/utilities.py +2 -3
- prefect/events/worker.py +2 -3
- prefect/filesystems.py +6 -517
- prefect/{new_flow_engine.py → flow_engine.py} +313 -72
- prefect/flow_runs.py +377 -5
- prefect/flows.py +248 -165
- prefect/futures.py +186 -345
- prefect/infrastructure/__init__.py +0 -27
- prefect/infrastructure/provisioners/__init__.py +5 -3
- prefect/infrastructure/provisioners/cloud_run.py +11 -6
- prefect/infrastructure/provisioners/container_instance.py +11 -7
- prefect/infrastructure/provisioners/ecs.py +6 -4
- prefect/infrastructure/provisioners/modal.py +8 -5
- prefect/input/actions.py +2 -4
- prefect/input/run_input.py +5 -7
- prefect/logging/formatters.py +0 -2
- prefect/logging/handlers.py +3 -11
- prefect/logging/loggers.py +2 -2
- prefect/manifests.py +2 -1
- prefect/records/__init__.py +1 -0
- prefect/records/result_store.py +42 -0
- prefect/records/store.py +9 -0
- prefect/results.py +43 -39
- prefect/runner/runner.py +9 -9
- prefect/runner/server.py +6 -10
- prefect/runner/storage.py +3 -8
- prefect/runner/submit.py +2 -2
- prefect/runner/utils.py +2 -2
- prefect/serializers.py +24 -35
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
- prefect/settings.py +70 -133
- prefect/states.py +17 -47
- prefect/task_engine.py +697 -58
- prefect/task_runners.py +269 -301
- prefect/task_server.py +53 -34
- prefect/tasks.py +327 -337
- prefect/transactions.py +220 -0
- prefect/types/__init__.py +61 -82
- prefect/utilities/asyncutils.py +195 -136
- prefect/utilities/callables.py +121 -41
- prefect/utilities/collections.py +23 -38
- prefect/utilities/dispatch.py +11 -3
- prefect/utilities/dockerutils.py +4 -0
- prefect/utilities/engine.py +140 -20
- prefect/utilities/importtools.py +26 -27
- prefect/utilities/pydantic.py +128 -38
- prefect/utilities/schema_tools/hydration.py +5 -1
- prefect/utilities/templating.py +12 -2
- prefect/variables.py +78 -61
- prefect/workers/__init__.py +0 -1
- prefect/workers/base.py +15 -17
- prefect/workers/process.py +3 -8
- prefect/workers/server.py +2 -2
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/METADATA +22 -21
- prefect_client-3.0.0rc1.dist-info/RECORD +176 -0
- prefect/_internal/pydantic/_base_model.py +0 -51
- prefect/_internal/pydantic/_compat.py +0 -82
- prefect/_internal/pydantic/_flags.py +0 -20
- prefect/_internal/pydantic/_types.py +0 -8
- prefect/_internal/pydantic/utilities/__init__.py +0 -0
- prefect/_internal/pydantic/utilities/config_dict.py +0 -72
- prefect/_internal/pydantic/utilities/field_validator.py +0 -150
- prefect/_internal/pydantic/utilities/model_construct.py +0 -56
- prefect/_internal/pydantic/utilities/model_copy.py +0 -55
- prefect/_internal/pydantic/utilities/model_dump.py +0 -136
- prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
- prefect/_internal/pydantic/utilities/model_fields.py +0 -50
- prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
- prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
- prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
- prefect/_internal/pydantic/utilities/model_validate.py +0 -75
- prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
- prefect/_internal/pydantic/utilities/model_validator.py +0 -87
- prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
- prefect/_vendor/__init__.py +0 -0
- prefect/_vendor/fastapi/__init__.py +0 -25
- prefect/_vendor/fastapi/applications.py +0 -946
- prefect/_vendor/fastapi/background.py +0 -3
- prefect/_vendor/fastapi/concurrency.py +0 -44
- prefect/_vendor/fastapi/datastructures.py +0 -58
- prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
- prefect/_vendor/fastapi/dependencies/models.py +0 -64
- prefect/_vendor/fastapi/dependencies/utils.py +0 -877
- prefect/_vendor/fastapi/encoders.py +0 -177
- prefect/_vendor/fastapi/exception_handlers.py +0 -40
- prefect/_vendor/fastapi/exceptions.py +0 -46
- prefect/_vendor/fastapi/logger.py +0 -3
- prefect/_vendor/fastapi/middleware/__init__.py +0 -1
- prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
- prefect/_vendor/fastapi/middleware/cors.py +0 -3
- prefect/_vendor/fastapi/middleware/gzip.py +0 -3
- prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
- prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
- prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
- prefect/_vendor/fastapi/openapi/__init__.py +0 -0
- prefect/_vendor/fastapi/openapi/constants.py +0 -2
- prefect/_vendor/fastapi/openapi/docs.py +0 -203
- prefect/_vendor/fastapi/openapi/models.py +0 -480
- prefect/_vendor/fastapi/openapi/utils.py +0 -485
- prefect/_vendor/fastapi/param_functions.py +0 -340
- prefect/_vendor/fastapi/params.py +0 -453
- prefect/_vendor/fastapi/requests.py +0 -4
- prefect/_vendor/fastapi/responses.py +0 -40
- prefect/_vendor/fastapi/routing.py +0 -1331
- prefect/_vendor/fastapi/security/__init__.py +0 -15
- prefect/_vendor/fastapi/security/api_key.py +0 -98
- prefect/_vendor/fastapi/security/base.py +0 -6
- prefect/_vendor/fastapi/security/http.py +0 -172
- prefect/_vendor/fastapi/security/oauth2.py +0 -227
- prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
- prefect/_vendor/fastapi/security/utils.py +0 -10
- prefect/_vendor/fastapi/staticfiles.py +0 -1
- prefect/_vendor/fastapi/templating.py +0 -3
- prefect/_vendor/fastapi/testclient.py +0 -1
- prefect/_vendor/fastapi/types.py +0 -3
- prefect/_vendor/fastapi/utils.py +0 -235
- prefect/_vendor/fastapi/websockets.py +0 -7
- prefect/_vendor/starlette/__init__.py +0 -1
- prefect/_vendor/starlette/_compat.py +0 -28
- prefect/_vendor/starlette/_exception_handler.py +0 -80
- prefect/_vendor/starlette/_utils.py +0 -88
- prefect/_vendor/starlette/applications.py +0 -261
- prefect/_vendor/starlette/authentication.py +0 -159
- prefect/_vendor/starlette/background.py +0 -43
- prefect/_vendor/starlette/concurrency.py +0 -59
- prefect/_vendor/starlette/config.py +0 -151
- prefect/_vendor/starlette/convertors.py +0 -87
- prefect/_vendor/starlette/datastructures.py +0 -707
- prefect/_vendor/starlette/endpoints.py +0 -130
- prefect/_vendor/starlette/exceptions.py +0 -60
- prefect/_vendor/starlette/formparsers.py +0 -276
- prefect/_vendor/starlette/middleware/__init__.py +0 -17
- prefect/_vendor/starlette/middleware/authentication.py +0 -52
- prefect/_vendor/starlette/middleware/base.py +0 -220
- prefect/_vendor/starlette/middleware/cors.py +0 -176
- prefect/_vendor/starlette/middleware/errors.py +0 -265
- prefect/_vendor/starlette/middleware/exceptions.py +0 -74
- prefect/_vendor/starlette/middleware/gzip.py +0 -113
- prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
- prefect/_vendor/starlette/middleware/sessions.py +0 -82
- prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
- prefect/_vendor/starlette/middleware/wsgi.py +0 -147
- prefect/_vendor/starlette/requests.py +0 -328
- prefect/_vendor/starlette/responses.py +0 -347
- prefect/_vendor/starlette/routing.py +0 -933
- prefect/_vendor/starlette/schemas.py +0 -154
- prefect/_vendor/starlette/staticfiles.py +0 -248
- prefect/_vendor/starlette/status.py +0 -199
- prefect/_vendor/starlette/templating.py +0 -231
- prefect/_vendor/starlette/testclient.py +0 -804
- prefect/_vendor/starlette/types.py +0 -30
- prefect/_vendor/starlette/websockets.py +0 -193
- prefect/agent.py +0 -698
- prefect/deployments/deployments.py +0 -1042
- prefect/deprecated/__init__.py +0 -0
- prefect/deprecated/data_documents.py +0 -350
- prefect/deprecated/packaging/__init__.py +0 -12
- prefect/deprecated/packaging/base.py +0 -96
- prefect/deprecated/packaging/docker.py +0 -146
- prefect/deprecated/packaging/file.py +0 -92
- prefect/deprecated/packaging/orion.py +0 -80
- prefect/deprecated/packaging/serializers.py +0 -171
- prefect/events/instrument.py +0 -135
- prefect/infrastructure/base.py +0 -323
- prefect/infrastructure/container.py +0 -818
- prefect/infrastructure/kubernetes.py +0 -920
- prefect/infrastructure/process.py +0 -289
- prefect/new_task_engine.py +0 -423
- prefect/pydantic/__init__.py +0 -76
- prefect/pydantic/main.py +0 -39
- prefect/software/__init__.py +0 -2
- prefect/software/base.py +0 -50
- prefect/software/conda.py +0 -199
- prefect/software/pip.py +0 -122
- prefect/software/python.py +0 -52
- prefect/workers/block.py +0 -218
- prefect_client-2.19.3.dist-info/RECORD +0 -292
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/LICENSE +0 -0
- {prefect_client-2.19.3.dist-info → prefect_client-3.0.0rc1.dist-info}/WHEEL +0 -0
- {prefect_client-2.19.3.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.
|
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.
|
65
|
-
prefect.context.TaskRunContext.
|
66
|
-
prefect.client.schemas.State.
|
67
|
-
|
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,
|
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__.
|
233
|
+
field = __pydantic_self__.model_fields.get(name)
|
241
234
|
if field is not None:
|
242
|
-
field.
|
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,
|
16
|
+
from typing import Any, Callable, Optional, Set, TypeVar
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
19
|
|
20
|
-
|
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
|
-
|
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
|
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
|
-
]
|