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/new_task_engine.py
DELETED
@@ -1,423 +0,0 @@
|
|
1
|
-
import inspect
|
2
|
-
import logging
|
3
|
-
import time
|
4
|
-
from contextlib import contextmanager
|
5
|
-
from dataclasses import dataclass, field
|
6
|
-
from typing import (
|
7
|
-
Any,
|
8
|
-
Callable,
|
9
|
-
Coroutine,
|
10
|
-
Dict,
|
11
|
-
Generator,
|
12
|
-
Generic,
|
13
|
-
Iterable,
|
14
|
-
Literal,
|
15
|
-
Optional,
|
16
|
-
TypeVar,
|
17
|
-
Union,
|
18
|
-
cast,
|
19
|
-
)
|
20
|
-
|
21
|
-
import pendulum
|
22
|
-
from typing_extensions import ParamSpec
|
23
|
-
|
24
|
-
from prefect import Task, get_client
|
25
|
-
from prefect.client.orchestration import SyncPrefectClient
|
26
|
-
from prefect.client.schemas import TaskRun
|
27
|
-
from prefect.context import FlowRunContext, TaskRunContext
|
28
|
-
from prefect.futures import PrefectFuture, resolve_futures_to_states
|
29
|
-
from prefect.logging.loggers import get_logger, task_run_logger
|
30
|
-
from prefect.results import ResultFactory
|
31
|
-
from prefect.server.schemas.states import State
|
32
|
-
from prefect.settings import PREFECT_TASKS_REFRESH_CACHE
|
33
|
-
from prefect.states import (
|
34
|
-
Retrying,
|
35
|
-
Running,
|
36
|
-
StateDetails,
|
37
|
-
exception_to_crashed_state,
|
38
|
-
exception_to_failed_state,
|
39
|
-
return_value_to_state,
|
40
|
-
)
|
41
|
-
from prefect.utilities.asyncutils import A, Async, run_sync
|
42
|
-
from prefect.utilities.callables import parameters_to_args_kwargs
|
43
|
-
from prefect.utilities.engine import (
|
44
|
-
_get_hook_name,
|
45
|
-
propose_state_sync,
|
46
|
-
)
|
47
|
-
from prefect.utilities.timeout import timeout, timeout_async
|
48
|
-
|
49
|
-
P = ParamSpec("P")
|
50
|
-
R = TypeVar("R")
|
51
|
-
|
52
|
-
|
53
|
-
@dataclass
|
54
|
-
class TaskRunEngine(Generic[P, R]):
|
55
|
-
task: Union[Task[P, R], Task[P, Coroutine[Any, Any, R]]]
|
56
|
-
logger: logging.Logger = field(default_factory=lambda: get_logger("engine"))
|
57
|
-
parameters: Optional[Dict[str, Any]] = None
|
58
|
-
task_run: Optional[TaskRun] = None
|
59
|
-
retries: int = 0
|
60
|
-
_is_started: bool = False
|
61
|
-
_client: Optional[SyncPrefectClient] = None
|
62
|
-
|
63
|
-
def __post_init__(self):
|
64
|
-
if self.parameters is None:
|
65
|
-
self.parameters = {}
|
66
|
-
|
67
|
-
@property
|
68
|
-
def client(self) -> SyncPrefectClient:
|
69
|
-
if not self._is_started or self._client is None:
|
70
|
-
raise RuntimeError("Engine has not started.")
|
71
|
-
return self._client
|
72
|
-
|
73
|
-
@property
|
74
|
-
def state(self) -> State:
|
75
|
-
if not self.task_run:
|
76
|
-
raise ValueError("Task run is not set")
|
77
|
-
return self.task_run.state
|
78
|
-
|
79
|
-
@property
|
80
|
-
def can_retry(self) -> bool:
|
81
|
-
retry_condition: Optional[
|
82
|
-
Callable[[Task[P, Coroutine[Any, Any, R]], TaskRun, State], bool]
|
83
|
-
] = self.task.retry_condition_fn
|
84
|
-
if not self.task_run:
|
85
|
-
raise ValueError("Task run is not set")
|
86
|
-
return not retry_condition or retry_condition(
|
87
|
-
self.task, self.task_run, self.state
|
88
|
-
)
|
89
|
-
|
90
|
-
def get_hooks(self, state: State, as_async: bool = False) -> Iterable[Callable]:
|
91
|
-
task = self.task
|
92
|
-
task_run = self.task_run
|
93
|
-
|
94
|
-
if not task_run:
|
95
|
-
raise ValueError("Task run is not set")
|
96
|
-
|
97
|
-
hooks = None
|
98
|
-
if state.is_failed() and task.on_failure:
|
99
|
-
hooks = task.on_failure
|
100
|
-
elif state.is_completed() and task.on_completion:
|
101
|
-
hooks = task.on_completion
|
102
|
-
|
103
|
-
for hook in hooks or []:
|
104
|
-
hook_name = _get_hook_name(hook)
|
105
|
-
|
106
|
-
@contextmanager
|
107
|
-
def hook_context():
|
108
|
-
try:
|
109
|
-
self.logger.info(
|
110
|
-
f"Running hook {hook_name!r} in response to entering state"
|
111
|
-
f" {state.name!r}"
|
112
|
-
)
|
113
|
-
yield
|
114
|
-
except Exception:
|
115
|
-
self.logger.error(
|
116
|
-
f"An error was encountered while running hook {hook_name!r}",
|
117
|
-
exc_info=True,
|
118
|
-
)
|
119
|
-
else:
|
120
|
-
self.logger.info(
|
121
|
-
f"Hook {hook_name!r} finished running successfully"
|
122
|
-
)
|
123
|
-
|
124
|
-
if as_async:
|
125
|
-
|
126
|
-
async def _hook_fn():
|
127
|
-
with hook_context():
|
128
|
-
result = hook(task, task_run, state)
|
129
|
-
if inspect.isawaitable(result):
|
130
|
-
await result
|
131
|
-
else:
|
132
|
-
|
133
|
-
def _hook_fn():
|
134
|
-
with hook_context():
|
135
|
-
hook(task, task_run, state)
|
136
|
-
|
137
|
-
yield _hook_fn
|
138
|
-
|
139
|
-
def _compute_state_details(
|
140
|
-
self, include_cache_expiration: bool = False
|
141
|
-
) -> StateDetails:
|
142
|
-
## setup cache metadata
|
143
|
-
task_run_context = TaskRunContext.get()
|
144
|
-
cache_key = (
|
145
|
-
self.task.cache_key_fn(
|
146
|
-
task_run_context,
|
147
|
-
self.parameters or {},
|
148
|
-
)
|
149
|
-
if self.task.cache_key_fn
|
150
|
-
else None
|
151
|
-
)
|
152
|
-
# Ignore the cached results for a cache key, default = false
|
153
|
-
# Setting on task level overrules the Prefect setting (env var)
|
154
|
-
refresh_cache = (
|
155
|
-
self.task.refresh_cache
|
156
|
-
if self.task.refresh_cache is not None
|
157
|
-
else PREFECT_TASKS_REFRESH_CACHE.value()
|
158
|
-
)
|
159
|
-
|
160
|
-
if include_cache_expiration:
|
161
|
-
cache_expiration = (
|
162
|
-
(pendulum.now("utc") + self.task.cache_expiration)
|
163
|
-
if self.task.cache_expiration
|
164
|
-
else None
|
165
|
-
)
|
166
|
-
else:
|
167
|
-
cache_expiration = None
|
168
|
-
return StateDetails(
|
169
|
-
cache_key=cache_key,
|
170
|
-
refresh_cache=refresh_cache,
|
171
|
-
cache_expiration=cache_expiration,
|
172
|
-
)
|
173
|
-
|
174
|
-
def begin_run(self):
|
175
|
-
state_details = self._compute_state_details()
|
176
|
-
new_state = Running(state_details=state_details)
|
177
|
-
state = self.set_state(new_state)
|
178
|
-
while state.is_pending():
|
179
|
-
time.sleep(0.2)
|
180
|
-
state = self.set_state(new_state)
|
181
|
-
|
182
|
-
def set_state(self, state: State, force: bool = False) -> State:
|
183
|
-
if not self.task_run:
|
184
|
-
raise ValueError("Task run is not set")
|
185
|
-
new_state = propose_state_sync(
|
186
|
-
self.client, state, task_run_id=self.task_run.id, force=force
|
187
|
-
)
|
188
|
-
# type: ignore
|
189
|
-
|
190
|
-
# currently this is a hack to keep a reference to the state object
|
191
|
-
# that has an in-memory result attached to it; using the API state
|
192
|
-
# could result in losing that reference
|
193
|
-
self.task_run.state = new_state
|
194
|
-
return new_state
|
195
|
-
|
196
|
-
def result(self, raise_on_failure: bool = True) -> "Union[R, State, None]":
|
197
|
-
_result = self.state.result(raise_on_failure=raise_on_failure, fetch=True)
|
198
|
-
# state.result is a `sync_compatible` function that may or may not return an awaitable
|
199
|
-
# depending on whether the parent frame is sync or not
|
200
|
-
if inspect.isawaitable(_result):
|
201
|
-
_result = run_sync(_result)
|
202
|
-
return _result
|
203
|
-
|
204
|
-
def handle_success(self, result: R) -> R:
|
205
|
-
result_factory = getattr(TaskRunContext.get(), "result_factory", None)
|
206
|
-
if result_factory is None:
|
207
|
-
raise ValueError("Result factory is not set")
|
208
|
-
terminal_state = run_sync(
|
209
|
-
return_value_to_state(
|
210
|
-
run_sync(resolve_futures_to_states(result)),
|
211
|
-
result_factory=result_factory,
|
212
|
-
)
|
213
|
-
)
|
214
|
-
terminal_state.state_details = self._compute_state_details(
|
215
|
-
include_cache_expiration=True
|
216
|
-
)
|
217
|
-
self.set_state(terminal_state)
|
218
|
-
return result
|
219
|
-
|
220
|
-
def handle_retry(self, exc: Exception) -> bool:
|
221
|
-
"""
|
222
|
-
If the task has retries left, and the retry condition is met, set the task to retrying.
|
223
|
-
- If the task has no retries left, or the retry condition is not met, return False.
|
224
|
-
- If the task has retries left, and the retry condition is met, return True.
|
225
|
-
"""
|
226
|
-
if self.retries < self.task.retries and self.can_retry:
|
227
|
-
self.set_state(Retrying(), force=True)
|
228
|
-
self.retries = self.retries + 1
|
229
|
-
return True
|
230
|
-
return False
|
231
|
-
|
232
|
-
def handle_exception(self, exc: Exception) -> None:
|
233
|
-
# If the task fails, and we have retries left, set the task to retrying.
|
234
|
-
if not self.handle_retry(exc):
|
235
|
-
# If the task has no retries left, or the retry condition is not met, set the task to failed.
|
236
|
-
context = TaskRunContext.get()
|
237
|
-
state = run_sync(
|
238
|
-
exception_to_failed_state(
|
239
|
-
exc,
|
240
|
-
message="Task run encountered an exception",
|
241
|
-
result_factory=getattr(context, "result_factory", None),
|
242
|
-
)
|
243
|
-
)
|
244
|
-
self.set_state(state)
|
245
|
-
|
246
|
-
def handle_crash(self, exc: BaseException) -> None:
|
247
|
-
state = run_sync(exception_to_crashed_state(exc))
|
248
|
-
self.logger.error(f"Crash detected! {state.message}")
|
249
|
-
self.logger.debug("Crash details:", exc_info=exc)
|
250
|
-
self.set_state(state, force=True)
|
251
|
-
|
252
|
-
@contextmanager
|
253
|
-
def enter_run_context(self, client: Optional[SyncPrefectClient] = None):
|
254
|
-
if client is None:
|
255
|
-
client = self.client
|
256
|
-
if not self.task_run:
|
257
|
-
raise ValueError("Task run is not set")
|
258
|
-
|
259
|
-
self.task_run = client.read_task_run(self.task_run.id)
|
260
|
-
|
261
|
-
with TaskRunContext(
|
262
|
-
task=self.task,
|
263
|
-
log_prints=self.task.log_prints or False,
|
264
|
-
task_run=self.task_run,
|
265
|
-
parameters=self.parameters,
|
266
|
-
result_factory=run_sync(ResultFactory.from_autonomous_task(self.task)), # type: ignore
|
267
|
-
client=client,
|
268
|
-
):
|
269
|
-
# set the logger to the task run logger
|
270
|
-
current_logger = self.logger
|
271
|
-
try:
|
272
|
-
self.logger = task_run_logger(task_run=self.task_run, task=self.task) # type: ignore
|
273
|
-
yield
|
274
|
-
finally:
|
275
|
-
self.logger = current_logger
|
276
|
-
|
277
|
-
@contextmanager
|
278
|
-
def start(self) -> Generator["TaskRunEngine", Any, Any]:
|
279
|
-
"""
|
280
|
-
Enters a client context and creates a task run if needed.
|
281
|
-
"""
|
282
|
-
with get_client(sync_client=True) as client:
|
283
|
-
self._client = client
|
284
|
-
self._is_started = True
|
285
|
-
try:
|
286
|
-
if not self.task_run:
|
287
|
-
self.task_run = run_sync(
|
288
|
-
self.task.create_run(
|
289
|
-
client=client,
|
290
|
-
parameters=self.parameters,
|
291
|
-
flow_run_context=FlowRunContext.get(),
|
292
|
-
parent_task_run_context=TaskRunContext.get(),
|
293
|
-
)
|
294
|
-
)
|
295
|
-
|
296
|
-
yield self
|
297
|
-
except Exception:
|
298
|
-
# regular exceptions are caught and re-raised to the user
|
299
|
-
raise
|
300
|
-
except BaseException as exc:
|
301
|
-
# BaseExceptions are caught and handled as crashes
|
302
|
-
self.handle_crash(exc)
|
303
|
-
raise
|
304
|
-
finally:
|
305
|
-
self._is_started = False
|
306
|
-
self._client = None
|
307
|
-
|
308
|
-
async def get_client(self):
|
309
|
-
if not self._is_started:
|
310
|
-
raise RuntimeError("Engine has not started.")
|
311
|
-
else:
|
312
|
-
return self._client
|
313
|
-
|
314
|
-
def is_running(self) -> bool:
|
315
|
-
if getattr(self, "task_run", None) is None:
|
316
|
-
return False
|
317
|
-
return getattr(self, "task_run").state.is_running()
|
318
|
-
|
319
|
-
def is_pending(self) -> bool:
|
320
|
-
if getattr(self, "task_run", None) is None:
|
321
|
-
return False # TODO: handle this differently?
|
322
|
-
return getattr(self, "task_run").state.is_pending()
|
323
|
-
|
324
|
-
|
325
|
-
def run_task_sync(
|
326
|
-
task: Task[P, R],
|
327
|
-
task_run: Optional[TaskRun] = None,
|
328
|
-
parameters: Optional[Dict[str, Any]] = None,
|
329
|
-
wait_for: Optional[Iterable[PrefectFuture[A, Async]]] = None,
|
330
|
-
return_type: Literal["state", "result"] = "result",
|
331
|
-
) -> Union[R, State, None]:
|
332
|
-
engine = TaskRunEngine[P, R](task=task, parameters=parameters, task_run=task_run)
|
333
|
-
|
334
|
-
# This is a context manager that keeps track of the run of the task run.
|
335
|
-
with engine.start() as run:
|
336
|
-
run.begin_run()
|
337
|
-
|
338
|
-
while run.is_running():
|
339
|
-
with run.enter_run_context():
|
340
|
-
try:
|
341
|
-
# This is where the task is actually run.
|
342
|
-
with timeout(seconds=run.task.timeout_seconds):
|
343
|
-
call_args, call_kwargs = parameters_to_args_kwargs(
|
344
|
-
task.fn, run.parameters or {}
|
345
|
-
)
|
346
|
-
result = cast(R, task.fn(*call_args, **call_kwargs)) # type: ignore
|
347
|
-
|
348
|
-
# If the task run is successful, finalize it.
|
349
|
-
run.handle_success(result)
|
350
|
-
|
351
|
-
except Exception as exc:
|
352
|
-
run.handle_exception(exc)
|
353
|
-
|
354
|
-
if run.state.is_final():
|
355
|
-
for hook in run.get_hooks(run.state):
|
356
|
-
hook()
|
357
|
-
|
358
|
-
if return_type == "state":
|
359
|
-
return run.state
|
360
|
-
return run.result()
|
361
|
-
|
362
|
-
|
363
|
-
async def run_task_async(
|
364
|
-
task: Task[P, Coroutine[Any, Any, R]],
|
365
|
-
task_run: Optional[TaskRun] = None,
|
366
|
-
parameters: Optional[Dict[str, Any]] = None,
|
367
|
-
wait_for: Optional[Iterable[PrefectFuture[A, Async]]] = None,
|
368
|
-
return_type: Literal["state", "result"] = "result",
|
369
|
-
) -> Union[R, State, None]:
|
370
|
-
"""
|
371
|
-
Runs a task against the API.
|
372
|
-
|
373
|
-
We will most likely want to use this logic as a wrapper and return a coroutine for type inference.
|
374
|
-
"""
|
375
|
-
engine = TaskRunEngine[P, R](task=task, parameters=parameters, task_run=task_run)
|
376
|
-
|
377
|
-
# This is a context manager that keeps track of the run of the task run.
|
378
|
-
with engine.start() as run:
|
379
|
-
run.begin_run()
|
380
|
-
|
381
|
-
while run.is_running():
|
382
|
-
with run.enter_run_context():
|
383
|
-
try:
|
384
|
-
# This is where the task is actually run.
|
385
|
-
with timeout_async(seconds=run.task.timeout_seconds):
|
386
|
-
call_args, call_kwargs = parameters_to_args_kwargs(
|
387
|
-
task.fn, run.parameters or {}
|
388
|
-
)
|
389
|
-
result = cast(R, await task.fn(*call_args, **call_kwargs)) # type: ignore
|
390
|
-
|
391
|
-
# If the task run is successful, finalize it.
|
392
|
-
run.handle_success(result)
|
393
|
-
|
394
|
-
except Exception as exc:
|
395
|
-
run.handle_exception(exc)
|
396
|
-
|
397
|
-
if run.state.is_final():
|
398
|
-
for hook in run.get_hooks(run.state, as_async=True):
|
399
|
-
await hook()
|
400
|
-
|
401
|
-
if return_type == "state":
|
402
|
-
return run.state
|
403
|
-
return run.result()
|
404
|
-
|
405
|
-
|
406
|
-
def run_task(
|
407
|
-
task: Task[P, R],
|
408
|
-
task_run: Optional[TaskRun] = None,
|
409
|
-
parameters: Optional[Dict[str, Any]] = None,
|
410
|
-
wait_for: Optional[Iterable[PrefectFuture[A, Async]]] = None,
|
411
|
-
return_type: Literal["state", "result"] = "result",
|
412
|
-
) -> Union[R, State, None]:
|
413
|
-
kwargs = dict(
|
414
|
-
task=task,
|
415
|
-
task_run=task_run,
|
416
|
-
parameters=parameters,
|
417
|
-
wait_for=wait_for,
|
418
|
-
return_type=return_type,
|
419
|
-
)
|
420
|
-
if task.isasync:
|
421
|
-
return run_task_async(**kwargs)
|
422
|
-
else:
|
423
|
-
return run_task_sync(**kwargs)
|
prefect/pydantic/__init__.py
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This initialization file makes the `BaseModel` and `PrefectBaseModel` classes available for import from the pydantic module within Prefect. This setup allows other parts of the Prefect codebase to use these models without needing to understand the underlying compatibility layer.
|
3
|
-
"""
|
4
|
-
import typing
|
5
|
-
from prefect._internal.pydantic._flags import HAS_PYDANTIC_V2, USE_PYDANTIC_V2
|
6
|
-
|
7
|
-
if typing.TYPE_CHECKING:
|
8
|
-
# import of virtually everything is supported via `__getattr__` below,
|
9
|
-
# but we need them here for type checking and IDE support
|
10
|
-
from pydantic import validator, root_validator
|
11
|
-
from .main import (
|
12
|
-
BaseModel,
|
13
|
-
PrefectBaseModel,
|
14
|
-
FieldInfo,
|
15
|
-
Field,
|
16
|
-
PrivateAttr,
|
17
|
-
SecretStr,
|
18
|
-
field_validator,
|
19
|
-
model_validator,
|
20
|
-
ConfigDict,
|
21
|
-
ValidationError,
|
22
|
-
)
|
23
|
-
|
24
|
-
__all__ = [
|
25
|
-
"BaseModel",
|
26
|
-
"PrefectBaseModel",
|
27
|
-
"Field",
|
28
|
-
"FieldInfo",
|
29
|
-
"PrivateAttr",
|
30
|
-
"SecretStr",
|
31
|
-
"validator",
|
32
|
-
"root_validator",
|
33
|
-
"field_validator",
|
34
|
-
"model_validator",
|
35
|
-
"ConfigDict",
|
36
|
-
"ValidationError",
|
37
|
-
]
|
38
|
-
|
39
|
-
_dynamic_imports: "typing.Dict[str, typing.Tuple[str, str]]" = {
|
40
|
-
"BaseModel": ("prefect.pydantic", ".main"),
|
41
|
-
"PrefectBaseModel": ("prefect.pydantic", ".main"),
|
42
|
-
"Field": ("prefect.pydantic", ".main"),
|
43
|
-
"FieldInfo": ("prefect.pydantic", ".main"),
|
44
|
-
"PrivateAttr": ("prefect.pydantic", ".main"),
|
45
|
-
"SecretStr": ("prefect.pydantic", ".main"),
|
46
|
-
"field_validator": ("prefect.pydantic", ".main"),
|
47
|
-
"model_validator": ("prefect.pydantic", ".main"),
|
48
|
-
"ConfigDict": ("prefect.pydantic", ".main"),
|
49
|
-
"ValidationError": ("prefect.pydantic", ".main"),
|
50
|
-
}
|
51
|
-
|
52
|
-
|
53
|
-
def __getattr__(attr_name: str) -> object:
|
54
|
-
from importlib import import_module
|
55
|
-
|
56
|
-
if attr_name in _dynamic_imports:
|
57
|
-
# If the attribute is in the dynamic imports, import it from the specified module
|
58
|
-
package, module_name = _dynamic_imports[attr_name]
|
59
|
-
|
60
|
-
# Prevent recursive import
|
61
|
-
if module_name == "__module__":
|
62
|
-
return import_module(f".{attr_name}", package=package)
|
63
|
-
|
64
|
-
# Import the module and return the attribute
|
65
|
-
else:
|
66
|
-
module = import_module(module_name, package=package)
|
67
|
-
return getattr(module, attr_name)
|
68
|
-
|
69
|
-
elif HAS_PYDANTIC_V2 and not USE_PYDANTIC_V2:
|
70
|
-
# In this case, we are using Pydantic v2 but it is not enabled, so we should import from pydantic.v1
|
71
|
-
module = import_module("pydantic.v1")
|
72
|
-
return getattr(module, attr_name)
|
73
|
-
else:
|
74
|
-
# In this case, we are using either Pydantic v1 or Pydantic v2 is enabled, so we should import from pydantic
|
75
|
-
module = import_module("pydantic")
|
76
|
-
return getattr(module, attr_name)
|
prefect/pydantic/main.py
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
This file defines a `PrefectBaseModel` class that extends the `BaseModel` (imported from the internal compatibility layer).
|
3
|
-
"""
|
4
|
-
import typing
|
5
|
-
|
6
|
-
from prefect._internal.pydantic._compat import (
|
7
|
-
BaseModel,
|
8
|
-
ConfigDict,
|
9
|
-
Field,
|
10
|
-
FieldInfo,
|
11
|
-
PrivateAttr,
|
12
|
-
SecretStr,
|
13
|
-
ValidationError,
|
14
|
-
field_validator,
|
15
|
-
model_validator,
|
16
|
-
)
|
17
|
-
|
18
|
-
|
19
|
-
class PrefectBaseModel(BaseModel):
|
20
|
-
def _reset_fields(self) -> typing.Set[str]:
|
21
|
-
"""
|
22
|
-
A set of field names that are reset when the PrefectBaseModel is copied.
|
23
|
-
These fields are also disregarded for equality comparisons.
|
24
|
-
"""
|
25
|
-
return set()
|
26
|
-
|
27
|
-
|
28
|
-
__all__ = [
|
29
|
-
"BaseModel",
|
30
|
-
"PrefectBaseModel",
|
31
|
-
"Field",
|
32
|
-
"FieldInfo",
|
33
|
-
"PrivateAttr",
|
34
|
-
"SecretStr",
|
35
|
-
"field_validator",
|
36
|
-
"model_validator",
|
37
|
-
"ConfigDict",
|
38
|
-
"ValidationError",
|
39
|
-
]
|
prefect/software/__init__.py
DELETED
prefect/software/base.py
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
from typing import Iterable, List, Optional
|
2
|
-
|
3
|
-
|
4
|
-
class Requirement:
|
5
|
-
# Implementations are expected to at least contain a name attribute
|
6
|
-
name: str
|
7
|
-
|
8
|
-
@classmethod
|
9
|
-
def __get_validators__(cls):
|
10
|
-
yield cls.validate
|
11
|
-
|
12
|
-
@classmethod
|
13
|
-
def validate(cls, value):
|
14
|
-
if not isinstance(value, cls):
|
15
|
-
# Attempt to parse the string representation of the input type
|
16
|
-
return cls(str(value))
|
17
|
-
return value
|
18
|
-
|
19
|
-
def __eq__(self, other: object) -> bool:
|
20
|
-
"""
|
21
|
-
Requirements are equal if their string specification matches.
|
22
|
-
"""
|
23
|
-
if not isinstance(other, Requirement):
|
24
|
-
return NotImplemented
|
25
|
-
|
26
|
-
return str(self) == str(other)
|
27
|
-
|
28
|
-
def __repr__(self) -> str:
|
29
|
-
return f"{type(self).__name__}({str(self)!r})"
|
30
|
-
|
31
|
-
|
32
|
-
def remove_duplicate_requirements(
|
33
|
-
constant: Iterable[Requirement], to_deduplicate: Iterable[Requirement]
|
34
|
-
) -> List[Requirement]:
|
35
|
-
"""
|
36
|
-
Returns a list of requirements that excludes requirements already specified
|
37
|
-
in the first iterable.
|
38
|
-
"""
|
39
|
-
constant_names = {req.name for req in constant}
|
40
|
-
return [req for req in to_deduplicate if req.name not in constant_names]
|
41
|
-
|
42
|
-
|
43
|
-
def pop_requirement_by_name(
|
44
|
-
requirements: List[Requirement], name: str
|
45
|
-
) -> Optional[Requirement]:
|
46
|
-
for index, requirement in enumerate(requirements):
|
47
|
-
if requirement.name == name:
|
48
|
-
requirements.pop(index)
|
49
|
-
return requirement
|
50
|
-
return None
|