prefect-client 3.2.13__py3-none-any.whl → 3.2.14__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/_build_info.py +3 -3
- prefect/client/orchestration/_flow_runs/client.py +34 -4
- prefect/client/schemas/actions.py +12 -0
- prefect/client/schemas/objects.py +18 -0
- prefect/deployments/runner.py +1 -9
- prefect/docker/docker_image.py +2 -1
- prefect/flow_engine.py +11 -5
- prefect/flow_runs.py +1 -1
- prefect/results.py +9 -3
- prefect/runner/__init__.py +2 -0
- prefect/runner/runner.py +1 -1
- prefect/runner/server.py +12 -7
- prefect/runner/storage.py +37 -37
- prefect/runner/submit.py +36 -25
- prefect/runner/utils.py +9 -5
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +4 -4
- prefect/server/api/flow_runs.py +21 -0
- prefect/server/api/task_runs.py +52 -1
- prefect/settings/models/tasks.py +5 -0
- prefect/tasks.py +6 -2
- prefect/transactions.py +5 -0
- prefect/utilities/engine.py +2 -2
- prefect/utilities/importtools.py +6 -9
- prefect/workers/base.py +7 -3
- {prefect_client-3.2.13.dist-info → prefect_client-3.2.14.dist-info}/METADATA +1 -1
- {prefect_client-3.2.13.dist-info → prefect_client-3.2.14.dist-info}/RECORD +28 -28
- {prefect_client-3.2.13.dist-info → prefect_client-3.2.14.dist-info}/WHEEL +0 -0
- {prefect_client-3.2.13.dist-info → prefect_client-3.2.14.dist-info}/licenses/LICENSE +0 -0
prefect/_build_info.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Generated by versioningit
|
2
|
-
__version__ = "3.2.
|
3
|
-
__build_date__ = "2025-03-
|
4
|
-
__git_commit__ = "
|
2
|
+
__version__ = "3.2.14"
|
3
|
+
__build_date__ = "2025-03-21 15:55:26.682402+00:00"
|
4
|
+
__git_commit__ = "775b957d124ecd8cc3f0005e45019f1f9e855973"
|
5
5
|
__dirty__ = False
|
@@ -46,6 +46,9 @@ class FlowRunClient(BaseClient):
|
|
46
46
|
tags: "Iterable[str] | None" = None,
|
47
47
|
parent_task_run_id: "UUID | None" = None,
|
48
48
|
state: "State[R] | None" = None,
|
49
|
+
work_pool_name: str | None = None,
|
50
|
+
work_queue_name: str | None = None,
|
51
|
+
job_variables: dict[str, Any] | None = None,
|
49
52
|
) -> "FlowRun":
|
50
53
|
"""
|
51
54
|
Create a flow run for a flow.
|
@@ -59,7 +62,10 @@ class FlowRunClient(BaseClient):
|
|
59
62
|
parent_task_run_id: if a subflow run is being created, the placeholder task
|
60
63
|
run identifier in the parent flow
|
61
64
|
state: The initial state for the run. If not provided, defaults to
|
62
|
-
`
|
65
|
+
`Pending`.
|
66
|
+
work_pool_name: The name of the work pool to run the flow run in.
|
67
|
+
work_queue_name: The name of the work queue to place the flow run in.
|
68
|
+
job_variables: The job variables to use when setting up flow run infrastructure.
|
63
69
|
|
64
70
|
Raises:
|
65
71
|
httpx.RequestError: if the Prefect API does not successfully create a run for any reason
|
@@ -100,7 +106,16 @@ class FlowRunClient(BaseClient):
|
|
100
106
|
),
|
101
107
|
)
|
102
108
|
|
103
|
-
|
109
|
+
if work_pool_name is not None:
|
110
|
+
flow_run_create.work_pool_name = work_pool_name
|
111
|
+
if work_queue_name is not None:
|
112
|
+
flow_run_create.work_queue_name = work_queue_name
|
113
|
+
if job_variables is not None:
|
114
|
+
flow_run_create.job_variables = job_variables
|
115
|
+
|
116
|
+
flow_run_create_json = flow_run_create.model_dump(
|
117
|
+
mode="json", exclude_unset=True
|
118
|
+
)
|
104
119
|
response = self.request("POST", "/flow_runs/", json=flow_run_create_json)
|
105
120
|
|
106
121
|
flow_run = FlowRun.model_validate(response.json())
|
@@ -480,6 +495,9 @@ class FlowRunAsyncClient(BaseAsyncClient):
|
|
480
495
|
tags: "Iterable[str] | None" = None,
|
481
496
|
parent_task_run_id: "UUID | None" = None,
|
482
497
|
state: "State[R] | None" = None,
|
498
|
+
work_pool_name: str | None = None,
|
499
|
+
work_queue_name: str | None = None,
|
500
|
+
job_variables: dict[str, Any] | None = None,
|
483
501
|
) -> "FlowRun":
|
484
502
|
"""
|
485
503
|
Create a flow run for a flow.
|
@@ -493,7 +511,10 @@ class FlowRunAsyncClient(BaseAsyncClient):
|
|
493
511
|
parent_task_run_id: if a subflow run is being created, the placeholder task
|
494
512
|
run identifier in the parent flow
|
495
513
|
state: The initial state for the run. If not provided, defaults to
|
496
|
-
`
|
514
|
+
`Pending`.
|
515
|
+
work_pool_name: The name of the work pool to run the flow run in.
|
516
|
+
work_queue_name: The name of the work queue to place the flow run in.
|
517
|
+
job_variables: The job variables to use when setting up flow run infrastructure.
|
497
518
|
|
498
519
|
Raises:
|
499
520
|
httpx.RequestError: if the Prefect API does not successfully create a run for any reason
|
@@ -534,7 +555,16 @@ class FlowRunAsyncClient(BaseAsyncClient):
|
|
534
555
|
),
|
535
556
|
)
|
536
557
|
|
537
|
-
|
558
|
+
if work_pool_name is not None:
|
559
|
+
flow_run_create.work_pool_name = work_pool_name
|
560
|
+
if work_queue_name is not None:
|
561
|
+
flow_run_create.work_queue_name = work_queue_name
|
562
|
+
if job_variables is not None:
|
563
|
+
flow_run_create.job_variables = job_variables
|
564
|
+
|
565
|
+
flow_run_create_json = flow_run_create.model_dump(
|
566
|
+
mode="json", exclude_unset=True
|
567
|
+
)
|
538
568
|
response = await self.request("POST", "/flow_runs/", json=flow_run_create_json)
|
539
569
|
|
540
570
|
flow_run = FlowRun.model_validate(response.json())
|
@@ -23,6 +23,7 @@ from prefect._internal.schemas.validators import (
|
|
23
23
|
from prefect.client.schemas.objects import (
|
24
24
|
StateDetails,
|
25
25
|
StateType,
|
26
|
+
WorkPoolStorageConfiguration,
|
26
27
|
)
|
27
28
|
from prefect.client.schemas.schedules import (
|
28
29
|
SCHEDULE_TYPES,
|
@@ -443,6 +444,9 @@ class FlowRunCreate(ActionBaseModel):
|
|
443
444
|
idempotency_key: Optional[str] = Field(default=None)
|
444
445
|
|
445
446
|
labels: KeyValueLabelsField = Field(default_factory=dict)
|
447
|
+
work_pool_name: Optional[str] = Field(default=None)
|
448
|
+
work_queue_name: Optional[str] = Field(default=None)
|
449
|
+
job_variables: Optional[dict[str, Any]] = Field(default=None)
|
446
450
|
|
447
451
|
|
448
452
|
class DeploymentFlowRunCreate(ActionBaseModel):
|
@@ -684,6 +688,10 @@ class WorkPoolCreate(ActionBaseModel):
|
|
684
688
|
concurrency_limit: Optional[NonNegativeInteger] = Field(
|
685
689
|
default=None, description="A concurrency limit for the work pool."
|
686
690
|
)
|
691
|
+
storage_configuration: WorkPoolStorageConfiguration = Field(
|
692
|
+
default_factory=WorkPoolStorageConfiguration,
|
693
|
+
description="A storage configuration for the work pool.",
|
694
|
+
)
|
687
695
|
|
688
696
|
|
689
697
|
class WorkPoolUpdate(ActionBaseModel):
|
@@ -693,6 +701,10 @@ class WorkPoolUpdate(ActionBaseModel):
|
|
693
701
|
is_paused: Optional[bool] = Field(default=None)
|
694
702
|
base_job_template: Optional[dict[str, Any]] = Field(default=None)
|
695
703
|
concurrency_limit: Optional[int] = Field(default=None)
|
704
|
+
storage_configuration: Optional[WorkPoolStorageConfiguration] = Field(
|
705
|
+
default=None,
|
706
|
+
description="A storage configuration for the work pool.",
|
707
|
+
)
|
696
708
|
|
697
709
|
|
698
710
|
class WorkQueueCreate(ActionBaseModel):
|
@@ -1445,6 +1445,19 @@ class Agent(ObjectBaseModel):
|
|
1445
1445
|
)
|
1446
1446
|
|
1447
1447
|
|
1448
|
+
class WorkPoolStorageConfiguration(PrefectBaseModel):
|
1449
|
+
"""A work pool storage configuration"""
|
1450
|
+
|
1451
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
|
1452
|
+
|
1453
|
+
bundle_upload_step: Optional[dict[str, Any]] = Field(
|
1454
|
+
default=None, description="The bundle upload step for the work pool."
|
1455
|
+
)
|
1456
|
+
bundle_execution_step: Optional[dict[str, Any]] = Field(
|
1457
|
+
default=None, description="The bundle execution step for the work pool."
|
1458
|
+
)
|
1459
|
+
|
1460
|
+
|
1448
1461
|
class WorkPool(ObjectBaseModel):
|
1449
1462
|
"""An ORM representation of a work pool"""
|
1450
1463
|
|
@@ -1469,6 +1482,11 @@ class WorkPool(ObjectBaseModel):
|
|
1469
1482
|
default=None, description="The current status of the work pool."
|
1470
1483
|
)
|
1471
1484
|
|
1485
|
+
storage_configuration: WorkPoolStorageConfiguration = Field(
|
1486
|
+
default_factory=WorkPoolStorageConfiguration,
|
1487
|
+
description="The storage configuration for the work pool.",
|
1488
|
+
)
|
1489
|
+
|
1472
1490
|
# this required field has a default of None so that the custom validator
|
1473
1491
|
# below will be called and produce a more helpful error message. Because
|
1474
1492
|
# the field metadata is attached via an annotation, the default is hidden
|
prefect/deployments/runner.py
CHANGED
@@ -676,15 +676,7 @@ class RunnerDeployment(BaseModel):
|
|
676
676
|
try:
|
677
677
|
module = importlib.import_module(mod_name)
|
678
678
|
flow_file = getattr(module, "__file__", None)
|
679
|
-
except ModuleNotFoundError
|
680
|
-
# 16458 adds an identifier to the module name, so checking
|
681
|
-
# for "__prefect_loader__" (2 underscores) will not match
|
682
|
-
if "__prefect_loader_" in str(exc):
|
683
|
-
raise ValueError(
|
684
|
-
"Cannot create a RunnerDeployment from a flow that has been"
|
685
|
-
" loaded from an entrypoint. To deploy a flow via"
|
686
|
-
" entrypoint, use RunnerDeployment.from_entrypoint instead."
|
687
|
-
)
|
679
|
+
except ModuleNotFoundError:
|
688
680
|
raise ValueError(no_file_location_error)
|
689
681
|
if not flow_file:
|
690
682
|
raise ValueError(no_file_location_error)
|
prefect/docker/docker_image.py
CHANGED
@@ -64,7 +64,8 @@ class DockerImage:
|
|
64
64
|
def build(self) -> None:
|
65
65
|
full_image_name = self.reference
|
66
66
|
build_kwargs = self.build_kwargs.copy()
|
67
|
-
|
67
|
+
if "context" not in build_kwargs:
|
68
|
+
build_kwargs["context"] = Path.cwd()
|
68
69
|
build_kwargs["tag"] = full_image_name
|
69
70
|
build_kwargs["pull"] = build_kwargs.get("pull", True)
|
70
71
|
|
prefect/flow_engine.py
CHANGED
@@ -707,7 +707,11 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
707
707
|
except Exception:
|
708
708
|
# regular exceptions are caught and re-raised to the user
|
709
709
|
raise
|
710
|
-
except (Abort, Pause):
|
710
|
+
except (Abort, Pause) as exc:
|
711
|
+
if getattr(exc, "state", None):
|
712
|
+
# we set attribute explicitly because
|
713
|
+
# internals will have already called the state change API
|
714
|
+
self.flow_run.state = exc.state
|
711
715
|
raise
|
712
716
|
except GeneratorExit:
|
713
717
|
# Do not capture generator exits as crashes
|
@@ -722,9 +726,7 @@ class FlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
722
726
|
repr(self.state) if PREFECT_DEBUG_MODE else str(self.state)
|
723
727
|
)
|
724
728
|
self.logger.log(
|
725
|
-
level=logging.INFO
|
726
|
-
if self.state.is_completed()
|
727
|
-
else logging.ERROR,
|
729
|
+
level=logging.INFO,
|
728
730
|
msg=f"Finished in state {display_state}",
|
729
731
|
)
|
730
732
|
|
@@ -1277,7 +1279,11 @@ class AsyncFlowRunEngine(BaseFlowRunEngine[P, R]):
|
|
1277
1279
|
except Exception:
|
1278
1280
|
# regular exceptions are caught and re-raised to the user
|
1279
1281
|
raise
|
1280
|
-
except (Abort, Pause):
|
1282
|
+
except (Abort, Pause) as exc:
|
1283
|
+
if getattr(exc, "state", None):
|
1284
|
+
# we set attribute explicitly because
|
1285
|
+
# internals will have already called the state change API
|
1286
|
+
self.flow_run.state = exc.state
|
1281
1287
|
raise
|
1282
1288
|
except GeneratorExit:
|
1283
1289
|
# Do not capture generator exits as crashes
|
prefect/flow_runs.py
CHANGED
prefect/results.py
CHANGED
@@ -552,7 +552,11 @@ class ResultStore(BaseModel):
|
|
552
552
|
if self.result_storage_block_id is None and (
|
553
553
|
_resolve_path := getattr(self.result_storage, "_resolve_path", None)
|
554
554
|
):
|
555
|
-
|
555
|
+
path_key = _resolve_path(key)
|
556
|
+
if path_key is not None:
|
557
|
+
return str(_resolve_path(key))
|
558
|
+
else:
|
559
|
+
return key
|
556
560
|
return key
|
557
561
|
|
558
562
|
@sync_compatible
|
@@ -684,7 +688,9 @@ class ResultStore(BaseModel):
|
|
684
688
|
|
685
689
|
if self.result_storage_block_id is None:
|
686
690
|
if _resolve_path := getattr(self.result_storage, "_resolve_path", None):
|
687
|
-
|
691
|
+
path_key = _resolve_path(key)
|
692
|
+
if path_key is not None:
|
693
|
+
key = str(_resolve_path(key))
|
688
694
|
|
689
695
|
return ResultRecord(
|
690
696
|
result=obj,
|
@@ -773,7 +779,7 @@ class ResultStore(BaseModel):
|
|
773
779
|
)
|
774
780
|
else Path(".").resolve()
|
775
781
|
)
|
776
|
-
base_key = str(Path(key).relative_to(basepath))
|
782
|
+
base_key = key if basepath is None else str(Path(key).relative_to(basepath))
|
777
783
|
else:
|
778
784
|
base_key = key
|
779
785
|
if (
|
prefect/runner/__init__.py
CHANGED
prefect/runner/runner.py
CHANGED
@@ -1425,7 +1425,7 @@ class Runner:
|
|
1425
1425
|
)
|
1426
1426
|
status_code = process.returncode
|
1427
1427
|
except Exception as exc:
|
1428
|
-
if not task_status._future.done():
|
1428
|
+
if not task_status._future.done(): # type: ignore
|
1429
1429
|
# This flow run was being submitted and did not start successfully
|
1430
1430
|
run_logger.exception(
|
1431
1431
|
f"Failed to start process for flow run '{flow_run.id}'."
|
prefect/runner/server.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import uuid
|
2
|
-
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Hashable, Optional
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Hashable, Optional
|
3
5
|
|
4
6
|
import uvicorn
|
5
7
|
from fastapi import APIRouter, FastAPI, HTTPException, status
|
@@ -33,7 +35,7 @@ if TYPE_CHECKING:
|
|
33
35
|
|
34
36
|
from pydantic import BaseModel
|
35
37
|
|
36
|
-
logger: "logging.Logger" = get_logger("webserver")
|
38
|
+
logger: "logging.Logger" = get_logger("runner.webserver")
|
37
39
|
|
38
40
|
RunnableEndpoint = Literal["deployment", "flow", "task"]
|
39
41
|
|
@@ -45,7 +47,7 @@ class RunnerGenericFlowRunRequest(BaseModel):
|
|
45
47
|
|
46
48
|
|
47
49
|
def perform_health_check(
|
48
|
-
runner: "Runner", delay_threshold:
|
50
|
+
runner: "Runner", delay_threshold: int | None = None
|
49
51
|
) -> Callable[..., JSONResponse]:
|
50
52
|
if delay_threshold is None:
|
51
53
|
delay_threshold = (
|
@@ -57,6 +59,9 @@ def perform_health_check(
|
|
57
59
|
now = DateTime.now("utc")
|
58
60
|
poll_delay = (now - runner.last_polled).total_seconds()
|
59
61
|
|
62
|
+
if TYPE_CHECKING:
|
63
|
+
assert delay_threshold is not None
|
64
|
+
|
60
65
|
if poll_delay > delay_threshold:
|
61
66
|
return JSONResponse(
|
62
67
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
@@ -120,7 +125,7 @@ async def _build_endpoint_for_deployment(
|
|
120
125
|
|
121
126
|
async def get_deployment_router(
|
122
127
|
runner: "Runner",
|
123
|
-
) ->
|
128
|
+
) -> tuple[APIRouter, dict[Hashable, Any]]:
|
124
129
|
router = APIRouter()
|
125
130
|
schemas: dict[Hashable, Any] = {}
|
126
131
|
async with get_client() as client:
|
@@ -216,14 +221,14 @@ def _build_generic_endpoint_for_flows(
|
|
216
221
|
# Verify that the flow we're loading is a subflow this runner is
|
217
222
|
# managing
|
218
223
|
if not _flow_in_schemas(flow, schemas):
|
219
|
-
|
224
|
+
logger.warning(
|
220
225
|
f"Flow {flow.name} is not directly managed by the runner. Please "
|
221
226
|
"include it in the runner's served flows' import namespace."
|
222
227
|
)
|
223
228
|
# Verify that the flow we're loading hasn't changed since the webserver
|
224
229
|
# was started
|
225
230
|
if _flow_schema_changed(flow, schemas):
|
226
|
-
|
231
|
+
logger.warning(
|
227
232
|
"A change in flow parameters has been detected. Please "
|
228
233
|
"restart the runner."
|
229
234
|
)
|
@@ -291,7 +296,7 @@ async def build_server(runner: "Runner") -> FastAPI:
|
|
291
296
|
return webserver
|
292
297
|
|
293
298
|
|
294
|
-
def start_webserver(runner: "Runner", log_level:
|
299
|
+
def start_webserver(runner: "Runner", log_level: str | None = None) -> None:
|
295
300
|
"""
|
296
301
|
Run a FastAPI server for a runner.
|
297
302
|
|
prefect/runner/storage.py
CHANGED
@@ -6,7 +6,6 @@ from copy import deepcopy
|
|
6
6
|
from pathlib import Path
|
7
7
|
from typing import (
|
8
8
|
Any,
|
9
|
-
Dict,
|
10
9
|
Optional,
|
11
10
|
Protocol,
|
12
11
|
TypedDict,
|
@@ -16,7 +15,7 @@ from typing import (
|
|
16
15
|
from urllib.parse import urlparse, urlsplit, urlunparse
|
17
16
|
from uuid import uuid4
|
18
17
|
|
19
|
-
import fsspec
|
18
|
+
import fsspec # pyright: ignore[reportMissingTypeStubs]
|
20
19
|
from anyio import run_process
|
21
20
|
from pydantic import SecretStr
|
22
21
|
|
@@ -79,7 +78,7 @@ class RunnerStorage(Protocol):
|
|
79
78
|
|
80
79
|
class GitCredentials(TypedDict, total=False):
|
81
80
|
username: str
|
82
|
-
access_token:
|
81
|
+
access_token: str | Secret[str]
|
83
82
|
|
84
83
|
|
85
84
|
class GitRepository:
|
@@ -117,12 +116,12 @@ class GitRepository:
|
|
117
116
|
def __init__(
|
118
117
|
self,
|
119
118
|
url: str,
|
120
|
-
credentials: Union[GitCredentials, Block,
|
121
|
-
name:
|
122
|
-
branch:
|
119
|
+
credentials: Union[GitCredentials, Block, dict[str, Any], None] = None,
|
120
|
+
name: str | None = None,
|
121
|
+
branch: str | None = None,
|
123
122
|
include_submodules: bool = False,
|
124
|
-
pull_interval:
|
125
|
-
directories:
|
123
|
+
pull_interval: int | None = 60,
|
124
|
+
directories: list[str] | None = None,
|
126
125
|
):
|
127
126
|
if credentials is None:
|
128
127
|
credentials = {}
|
@@ -198,7 +197,7 @@ class GitRepository:
|
|
198
197
|
@property
|
199
198
|
def _git_config(self) -> list[str]:
|
200
199
|
"""Build a git configuration to use when running git commands."""
|
201
|
-
config = {}
|
200
|
+
config: dict[str, str] = {}
|
202
201
|
|
203
202
|
# Submodules can be private. The url in .gitmodules
|
204
203
|
# will not include the credentials, we need to
|
@@ -220,7 +219,7 @@ class GitRepository:
|
|
220
219
|
result = await run_process(
|
221
220
|
["git", "config", "--get", "core.sparseCheckout"], cwd=self.destination
|
222
221
|
)
|
223
|
-
return result.strip().lower() == "true"
|
222
|
+
return result.stdout.decode().strip().lower() == "true"
|
224
223
|
except Exception:
|
225
224
|
return False
|
226
225
|
|
@@ -243,8 +242,7 @@ class GitRepository:
|
|
243
242
|
cwd=str(self.destination),
|
244
243
|
)
|
245
244
|
existing_repo_url = None
|
246
|
-
|
247
|
-
existing_repo_url = _strip_auth_from_url(result.stdout.decode().strip())
|
245
|
+
existing_repo_url = _strip_auth_from_url(result.stdout.decode().strip())
|
248
246
|
|
249
247
|
if existing_repo_url != self._url:
|
250
248
|
raise ValueError(
|
@@ -255,7 +253,7 @@ class GitRepository:
|
|
255
253
|
# Sparsely checkout the repository if directories are specified and the repo is not in sparse-checkout mode already
|
256
254
|
if self._directories and not await self.is_sparsely_checked_out():
|
257
255
|
await run_process(
|
258
|
-
["git", "sparse-checkout", "set"
|
256
|
+
["git", "sparse-checkout", "set", *self._directories],
|
259
257
|
cwd=self.destination,
|
260
258
|
)
|
261
259
|
|
@@ -323,7 +321,7 @@ class GitRepository:
|
|
323
321
|
if self._directories:
|
324
322
|
self._logger.debug("Will add %s", self._directories)
|
325
323
|
await run_process(
|
326
|
-
["git", "sparse-checkout", "set"
|
324
|
+
["git", "sparse-checkout", "set", *self._directories],
|
327
325
|
cwd=self.destination,
|
328
326
|
)
|
329
327
|
|
@@ -343,7 +341,7 @@ class GitRepository:
|
|
343
341
|
)
|
344
342
|
|
345
343
|
def to_pull_step(self) -> dict[str, Any]:
|
346
|
-
pull_step = {
|
344
|
+
pull_step: dict[str, Any] = {
|
347
345
|
"prefect.deployments.steps.git_clone": {
|
348
346
|
"repository": self._url,
|
349
347
|
"branch": self._branch,
|
@@ -357,13 +355,14 @@ class GitRepository:
|
|
357
355
|
pull_step["prefect.deployments.steps.git_clone"]["credentials"] = (
|
358
356
|
f"{{{{ {self._credentials.get_block_placeholder()} }}}}"
|
359
357
|
)
|
360
|
-
elif isinstance(self._credentials, dict):
|
361
|
-
if isinstance(
|
358
|
+
elif isinstance(self._credentials, dict): # pyright: ignore[reportUnnecessaryIsInstance]
|
359
|
+
if isinstance(
|
360
|
+
access_token := self._credentials.get("access_token"), Secret
|
361
|
+
):
|
362
362
|
pull_step["prefect.deployments.steps.git_clone"]["credentials"] = {
|
363
363
|
**self._credentials,
|
364
364
|
"access_token": (
|
365
|
-
"{{"
|
366
|
-
f" {self._credentials['access_token'].get_block_placeholder()} }}}}"
|
365
|
+
f"{{{{ {access_token.get_block_placeholder()} }}}}"
|
367
366
|
),
|
368
367
|
}
|
369
368
|
elif self._credentials.get("access_token") is not None:
|
@@ -455,10 +454,10 @@ class RemoteStorage:
|
|
455
454
|
|
456
455
|
def replace_blocks_with_values(obj: Any) -> Any:
|
457
456
|
if isinstance(obj, Block):
|
458
|
-
if
|
459
|
-
return
|
457
|
+
if get := getattr(obj, "get", None):
|
458
|
+
return get()
|
460
459
|
if hasattr(obj, "value"):
|
461
|
-
return obj
|
460
|
+
return getattr(obj, "value")
|
462
461
|
else:
|
463
462
|
return obj.model_dump()
|
464
463
|
return obj
|
@@ -467,7 +466,7 @@ class RemoteStorage:
|
|
467
466
|
self._settings, replace_blocks_with_values, return_data=True
|
468
467
|
)
|
469
468
|
|
470
|
-
return fsspec.filesystem(scheme, **settings_with_block_values)
|
469
|
+
return fsspec.filesystem(scheme, **settings_with_block_values) # pyright: ignore[reportUnknownMemberType] missing type stubs
|
471
470
|
|
472
471
|
def set_base_path(self, path: Path) -> None:
|
473
472
|
self._storage_base_path = path
|
@@ -513,7 +512,7 @@ class RemoteStorage:
|
|
513
512
|
try:
|
514
513
|
await from_async.wait_for_call_in_new_thread(
|
515
514
|
create_call(
|
516
|
-
self._filesystem.get,
|
515
|
+
self._filesystem.get, # pyright: ignore[reportUnknownArgumentType, reportUnknownMemberType] missing type stubs
|
517
516
|
remote_path,
|
518
517
|
str(self.destination),
|
519
518
|
recursive=True,
|
@@ -580,18 +579,14 @@ class BlockStorageAdapter:
|
|
580
579
|
self._block = block
|
581
580
|
self._pull_interval = pull_interval
|
582
581
|
self._storage_base_path = Path.cwd()
|
583
|
-
if not isinstance(block, Block):
|
582
|
+
if not isinstance(block, Block): # pyright: ignore[reportUnnecessaryIsInstance]
|
584
583
|
raise TypeError(
|
585
584
|
f"Expected a block object. Received a {type(block).__name__!r} object."
|
586
585
|
)
|
587
586
|
if not hasattr(block, "get_directory"):
|
588
587
|
raise ValueError("Provided block must have a `get_directory` method.")
|
589
588
|
|
590
|
-
self._name = (
|
591
|
-
f"{block.get_block_type_slug()}-{block._block_document_name}"
|
592
|
-
if block._block_document_name
|
593
|
-
else str(uuid4())
|
594
|
-
)
|
589
|
+
self._name = f"{block.get_block_type_slug()}-{getattr(block, '_block_document_name', uuid4())}"
|
595
590
|
|
596
591
|
def set_base_path(self, path: Path) -> None:
|
597
592
|
self._storage_base_path = path
|
@@ -610,11 +605,11 @@ class BlockStorageAdapter:
|
|
610
605
|
await self._block.get_directory(local_path=str(self.destination))
|
611
606
|
|
612
607
|
def to_pull_step(self) -> dict[str, Any]:
|
613
|
-
# Give blocks the
|
608
|
+
# Give blocks the chance to implement their own pull step
|
614
609
|
if hasattr(self._block, "get_pull_step"):
|
615
|
-
return self._block
|
610
|
+
return getattr(self._block, "get_pull_step")()
|
616
611
|
else:
|
617
|
-
if
|
612
|
+
if getattr(self._block, "_block_document_name", None) is None:
|
618
613
|
raise BlockNotSavedError(
|
619
614
|
"Block must be saved with `.save()` before it can be converted to a"
|
620
615
|
" pull step."
|
@@ -622,7 +617,7 @@ class BlockStorageAdapter:
|
|
622
617
|
return {
|
623
618
|
"prefect.deployments.steps.pull_with_block": {
|
624
619
|
"block_type_slug": self._block.get_block_type_slug(),
|
625
|
-
"block_document_name": self._block
|
620
|
+
"block_document_name": getattr(self._block, "_block_document_name"),
|
626
621
|
}
|
627
622
|
}
|
628
623
|
|
@@ -723,7 +718,9 @@ def create_storage_from_source(
|
|
723
718
|
return LocalStorage(path=source, pull_interval=pull_interval)
|
724
719
|
|
725
720
|
|
726
|
-
def _format_token_from_credentials(
|
721
|
+
def _format_token_from_credentials(
|
722
|
+
netloc: str, credentials: dict[str, Any] | GitCredentials
|
723
|
+
) -> str:
|
727
724
|
"""
|
728
725
|
Formats the credentials block for the git provider.
|
729
726
|
|
@@ -736,7 +733,10 @@ def _format_token_from_credentials(netloc: str, credentials: dict) -> str:
|
|
736
733
|
token = credentials.get("token") if credentials else None
|
737
734
|
access_token = credentials.get("access_token") if credentials else None
|
738
735
|
|
739
|
-
user_provided_token = access_token or token or password
|
736
|
+
user_provided_token: str | Secret[str] | None = access_token or token or password
|
737
|
+
|
738
|
+
if isinstance(user_provided_token, Secret):
|
739
|
+
user_provided_token = user_provided_token.get()
|
740
740
|
|
741
741
|
if not user_provided_token:
|
742
742
|
raise ValueError(
|
@@ -787,7 +787,7 @@ def _strip_auth_from_url(url: str) -> str:
|
|
787
787
|
|
788
788
|
# Construct a new netloc without the auth info
|
789
789
|
netloc = parsed.hostname
|
790
|
-
if parsed.port:
|
790
|
+
if parsed.port and netloc:
|
791
791
|
netloc += f":{parsed.port}"
|
792
792
|
|
793
793
|
# Build the sanitized URL
|
prefect/runner/submit.py
CHANGED
@@ -3,15 +3,19 @@ from __future__ import annotations
|
|
3
3
|
import asyncio
|
4
4
|
import inspect
|
5
5
|
import uuid
|
6
|
-
from typing import TYPE_CHECKING, Any,
|
6
|
+
from typing import TYPE_CHECKING, Any, Union, overload
|
7
7
|
|
8
8
|
import anyio
|
9
9
|
import httpx
|
10
10
|
from typing_extensions import Literal, TypeAlias
|
11
11
|
|
12
12
|
from prefect.client.orchestration import get_client
|
13
|
-
from prefect.client.schemas.filters import
|
14
|
-
|
13
|
+
from prefect.client.schemas.filters import (
|
14
|
+
FlowRunFilter,
|
15
|
+
FlowRunFilterParentFlowRunId,
|
16
|
+
TaskRunFilter,
|
17
|
+
)
|
18
|
+
from prefect.client.schemas.objects import Constant, FlowRun, Parameter, TaskRunResult
|
15
19
|
from prefect.context import FlowRunContext
|
16
20
|
from prefect.flows import Flow
|
17
21
|
from prefect.logging import get_logger
|
@@ -60,18 +64,20 @@ async def _submit_flow_to_runner(
|
|
60
64
|
|
61
65
|
parent_flow_run_context = FlowRunContext.get()
|
62
66
|
|
63
|
-
task_inputs = {
|
64
|
-
k: await collect_task_run_inputs(v) for k, v in parameters.items()
|
67
|
+
task_inputs: dict[str, list[TaskRunResult | Parameter | Constant]] = {
|
68
|
+
k: list(await collect_task_run_inputs(v)) for k, v in parameters.items()
|
65
69
|
}
|
66
70
|
parameters = await resolve_inputs(parameters)
|
67
71
|
dummy_task = Task(name=flow.name, fn=flow.fn, version=flow.version)
|
68
72
|
parent_task_run = await client.create_task_run(
|
69
73
|
task=dummy_task,
|
70
74
|
flow_run_id=(
|
71
|
-
parent_flow_run_context.flow_run.id
|
75
|
+
parent_flow_run_context.flow_run.id
|
76
|
+
if parent_flow_run_context and parent_flow_run_context.flow_run
|
77
|
+
else None
|
72
78
|
),
|
73
79
|
dynamic_key=(
|
74
|
-
dynamic_key_for_task_run(parent_flow_run_context, dummy_task)
|
80
|
+
str(dynamic_key_for_task_run(parent_flow_run_context, dummy_task))
|
75
81
|
if parent_flow_run_context
|
76
82
|
else str(uuid.uuid4())
|
77
83
|
),
|
@@ -79,14 +85,15 @@ async def _submit_flow_to_runner(
|
|
79
85
|
state=Pending(),
|
80
86
|
)
|
81
87
|
|
82
|
-
|
88
|
+
httpx_client = getattr(client, "_client")
|
89
|
+
response = await httpx_client.post(
|
83
90
|
(
|
84
91
|
f"http://{PREFECT_RUNNER_SERVER_HOST.value()}"
|
85
92
|
f":{PREFECT_RUNNER_SERVER_PORT.value()}"
|
86
93
|
"/flow/run"
|
87
94
|
),
|
88
95
|
json={
|
89
|
-
"entrypoint": flow
|
96
|
+
"entrypoint": getattr(flow, "_entrypoint"),
|
90
97
|
"parameters": flow.serialize_parameters(parameters),
|
91
98
|
"parent_task_run_id": str(parent_task_run.id),
|
92
99
|
},
|
@@ -98,15 +105,15 @@ async def _submit_flow_to_runner(
|
|
98
105
|
|
99
106
|
@overload
|
100
107
|
def submit_to_runner(
|
101
|
-
prefect_callable:
|
102
|
-
parameters:
|
108
|
+
prefect_callable: Flow[Any, Any] | Task[Any, Any],
|
109
|
+
parameters: dict[str, Any],
|
103
110
|
retry_failed_submissions: bool = True,
|
104
111
|
) -> FlowRun: ...
|
105
112
|
|
106
113
|
|
107
114
|
@overload
|
108
115
|
def submit_to_runner(
|
109
|
-
prefect_callable:
|
116
|
+
prefect_callable: Flow[Any, Any] | Task[Any, Any],
|
110
117
|
parameters: list[dict[str, Any]],
|
111
118
|
retry_failed_submissions: bool = True,
|
112
119
|
) -> list[FlowRun]: ...
|
@@ -114,10 +121,10 @@ def submit_to_runner(
|
|
114
121
|
|
115
122
|
@sync_compatible
|
116
123
|
async def submit_to_runner(
|
117
|
-
prefect_callable:
|
118
|
-
parameters:
|
124
|
+
prefect_callable: Flow[Any, Any],
|
125
|
+
parameters: dict[str, Any] | list[dict[str, Any]] | None = None,
|
119
126
|
retry_failed_submissions: bool = True,
|
120
|
-
) ->
|
127
|
+
) -> FlowRun | list[FlowRun]:
|
121
128
|
"""
|
122
129
|
Submit a callable in the background via the runner webserver one or more times.
|
123
130
|
|
@@ -127,22 +134,22 @@ async def submit_to_runner(
|
|
127
134
|
each dictionary represents a discrete invocation of the callable
|
128
135
|
retry_failed_submissions: Whether to retry failed submissions to the runner webserver.
|
129
136
|
"""
|
130
|
-
if not isinstance(prefect_callable,
|
137
|
+
if not isinstance(prefect_callable, Flow): # pyright: ignore[reportUnnecessaryIsInstance]
|
131
138
|
raise TypeError(
|
132
139
|
"The `submit_to_runner` utility only supports submitting flows and tasks."
|
133
140
|
)
|
134
141
|
|
135
142
|
parameters = parameters or {}
|
136
|
-
if isinstance(parameters,
|
143
|
+
if isinstance(parameters, list):
|
137
144
|
return_single = False
|
138
|
-
elif isinstance(parameters, dict):
|
145
|
+
elif isinstance(parameters, dict): # pyright: ignore[reportUnnecessaryIsInstance]
|
139
146
|
parameters = [parameters]
|
140
147
|
return_single = True
|
141
148
|
else:
|
142
149
|
raise TypeError("Parameters must be a dictionary or a list of dictionaries.")
|
143
150
|
|
144
|
-
submitted_runs = []
|
145
|
-
unsubmitted_parameters = []
|
151
|
+
submitted_runs: list[FlowRun] = []
|
152
|
+
unsubmitted_parameters: list[dict[str, Any]] = []
|
146
153
|
|
147
154
|
for p in parameters:
|
148
155
|
try:
|
@@ -181,9 +188,9 @@ async def submit_to_runner(
|
|
181
188
|
|
182
189
|
@sync_compatible
|
183
190
|
async def wait_for_submitted_runs(
|
184
|
-
flow_run_filter:
|
185
|
-
task_run_filter:
|
186
|
-
timeout:
|
191
|
+
flow_run_filter: FlowRunFilter | None = None,
|
192
|
+
task_run_filter: TaskRunFilter | None = None,
|
193
|
+
timeout: float | None = None,
|
187
194
|
poll_interval: float = 3.0,
|
188
195
|
):
|
189
196
|
"""
|
@@ -197,7 +204,9 @@ async def wait_for_submitted_runs(
|
|
197
204
|
poll_interval: How long to wait between polling each run's state (seconds).
|
198
205
|
"""
|
199
206
|
|
200
|
-
parent_flow_run_id =
|
207
|
+
parent_flow_run_id = (
|
208
|
+
ctx.flow_run.id if ((ctx := FlowRunContext.get()) and ctx.flow_run) else None
|
209
|
+
)
|
201
210
|
|
202
211
|
if task_run_filter:
|
203
212
|
raise NotImplementedError("Waiting for task runs is not yet supported.")
|
@@ -223,7 +232,9 @@ async def wait_for_submitted_runs(
|
|
223
232
|
if parent_flow_run_id is not None:
|
224
233
|
subflow_runs = await client.read_flow_runs(
|
225
234
|
flow_run_filter=FlowRunFilter(
|
226
|
-
parent_flow_run_id=
|
235
|
+
parent_flow_run_id=FlowRunFilterParentFlowRunId(
|
236
|
+
any_=[parent_flow_run_id]
|
237
|
+
)
|
227
238
|
)
|
228
239
|
)
|
229
240
|
|
prefect/runner/utils.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from copy import deepcopy
|
2
|
-
from typing import Any
|
4
|
+
from typing import Any, Hashable
|
3
5
|
|
4
6
|
from fastapi import FastAPI
|
5
7
|
from fastapi.openapi.utils import get_openapi
|
@@ -8,7 +10,7 @@ from prefect import __version__ as PREFECT_VERSION
|
|
8
10
|
|
9
11
|
|
10
12
|
def inject_schemas_into_openapi(
|
11
|
-
webserver: FastAPI, schemas_to_inject: dict[
|
13
|
+
webserver: FastAPI, schemas_to_inject: dict[Hashable, Any]
|
12
14
|
) -> dict[str, Any]:
|
13
15
|
"""
|
14
16
|
Augments the webserver's OpenAPI schema with additional schemas from deployments / flows / tasks.
|
@@ -29,7 +31,7 @@ def inject_schemas_into_openapi(
|
|
29
31
|
|
30
32
|
|
31
33
|
def merge_definitions(
|
32
|
-
injected_schemas: dict[
|
34
|
+
injected_schemas: dict[Hashable, Any], openapi_schema: dict[str, Any]
|
33
35
|
) -> dict[str, Any]:
|
34
36
|
"""
|
35
37
|
Integrates definitions from injected schemas into the OpenAPI components.
|
@@ -51,7 +53,9 @@ def merge_definitions(
|
|
51
53
|
return openapi_schema_copy
|
52
54
|
|
53
55
|
|
54
|
-
def update_refs_in_schema(
|
56
|
+
def update_refs_in_schema(
|
57
|
+
schema_item: dict[str, Any] | list[Any], new_ref: str
|
58
|
+
) -> None:
|
55
59
|
"""
|
56
60
|
Recursively replaces `$ref` with a new reference base in a schema item.
|
57
61
|
|
@@ -64,7 +68,7 @@ def update_refs_in_schema(schema_item: Any, new_ref: str) -> None:
|
|
64
68
|
schema_item["$ref"] = schema_item["$ref"].replace("#/definitions/", new_ref)
|
65
69
|
for value in schema_item.values():
|
66
70
|
update_refs_in_schema(value, new_ref)
|
67
|
-
elif isinstance(schema_item, list):
|
71
|
+
elif isinstance(schema_item, list): # pyright: ignore[reportUnnecessaryIsInstance]
|
68
72
|
for item in schema_item:
|
69
73
|
update_refs_in_schema(item, new_ref)
|
70
74
|
|
@@ -559,7 +559,7 @@
|
|
559
559
|
"description": "To use any private container registry with a username and password, choose DockerRegistry. To use a private Azure Container Registry with a managed identity, choose ACRManagedIdentity.",
|
560
560
|
"anyOf": [
|
561
561
|
{
|
562
|
-
"$ref": "#/definitions/
|
562
|
+
"$ref": "#/definitions/DockerRegistryCredentials"
|
563
563
|
},
|
564
564
|
{
|
565
565
|
"$ref": "#/definitions/ACRManagedIdentity"
|
@@ -637,8 +637,8 @@
|
|
637
637
|
"subscription_id"
|
638
638
|
],
|
639
639
|
"definitions": {
|
640
|
-
"
|
641
|
-
"title": "
|
640
|
+
"DockerRegistryCredentials": {
|
641
|
+
"title": "DockerRegistryCredentials",
|
642
642
|
"description": "Connects to a Docker registry.\n\nRequires a Docker Engine to be connectable.",
|
643
643
|
"type": "object",
|
644
644
|
"properties": {
|
@@ -671,7 +671,7 @@
|
|
671
671
|
"password",
|
672
672
|
"registry_url"
|
673
673
|
],
|
674
|
-
"block_type_slug": "docker-registry",
|
674
|
+
"block_type_slug": "docker-registry-credentials",
|
675
675
|
"secret_fields": [
|
676
676
|
"password"
|
677
677
|
],
|
prefect/server/api/flow_runs.py
CHANGED
@@ -29,6 +29,7 @@ import prefect.server.schemas as schemas
|
|
29
29
|
from prefect.logging import get_logger
|
30
30
|
from prefect.server.api.run_history import run_history
|
31
31
|
from prefect.server.api.validation import validate_job_variables_for_deployment_flow_run
|
32
|
+
from prefect.server.api.workers import WorkerLookups
|
32
33
|
from prefect.server.database import PrefectDBInterface, provide_database_interface
|
33
34
|
from prefect.server.exceptions import FlowRunGraphTooLarge
|
34
35
|
from prefect.server.models.flow_runs import (
|
@@ -68,6 +69,7 @@ async def create_flow_run(
|
|
68
69
|
orchestration_dependencies.provide_flow_orchestration_parameters
|
69
70
|
),
|
70
71
|
api_version: str = Depends(dependencies.provide_request_api_version),
|
72
|
+
worker_lookups: WorkerLookups = Depends(WorkerLookups),
|
71
73
|
) -> schemas.responses.FlowRunResponse:
|
72
74
|
"""
|
73
75
|
Create a flow run. If a flow run with the same flow_id and
|
@@ -91,6 +93,25 @@ async def create_flow_run(
|
|
91
93
|
right_now = now("UTC")
|
92
94
|
|
93
95
|
async with db.session_context(begin_transaction=True) as session:
|
96
|
+
if flow_run.work_pool_name:
|
97
|
+
if flow_run.work_queue_name:
|
98
|
+
work_queue_id = await worker_lookups._get_work_queue_id_from_name(
|
99
|
+
session=session,
|
100
|
+
work_pool_name=flow_run.work_pool_name,
|
101
|
+
work_queue_name=flow_run.work_queue_name,
|
102
|
+
)
|
103
|
+
else:
|
104
|
+
work_queue_id = (
|
105
|
+
await worker_lookups._get_default_work_queue_id_from_work_pool_name(
|
106
|
+
session=session,
|
107
|
+
work_pool_name=flow_run.work_pool_name,
|
108
|
+
)
|
109
|
+
)
|
110
|
+
else:
|
111
|
+
work_queue_id = None
|
112
|
+
|
113
|
+
flow_run_object.work_queue_id = work_queue_id
|
114
|
+
|
94
115
|
model = await models.flow_runs.create_flow_run(
|
95
116
|
session=session,
|
96
117
|
flow_run=flow_run_object,
|
prefect/server/api/task_runs.py
CHANGED
@@ -16,6 +16,7 @@ from fastapi import (
|
|
16
16
|
WebSocket,
|
17
17
|
status,
|
18
18
|
)
|
19
|
+
from fastapi.responses import ORJSONResponse
|
19
20
|
from starlette.websockets import WebSocketDisconnect
|
20
21
|
|
21
22
|
import prefect.server.api.dependencies as dependencies
|
@@ -27,7 +28,10 @@ from prefect.server.database import PrefectDBInterface, provide_database_interfa
|
|
27
28
|
from prefect.server.orchestration import dependencies as orchestration_dependencies
|
28
29
|
from prefect.server.orchestration.core_policy import CoreTaskPolicy
|
29
30
|
from prefect.server.orchestration.policies import TaskRunOrchestrationPolicy
|
30
|
-
from prefect.server.schemas.responses import
|
31
|
+
from prefect.server.schemas.responses import (
|
32
|
+
OrchestrationResult,
|
33
|
+
TaskRunPaginationResponse,
|
34
|
+
)
|
31
35
|
from prefect.server.task_queue import MultiQueue, TaskQueue
|
32
36
|
from prefect.server.utilities import subscriptions
|
33
37
|
from prefect.server.utilities.server import PrefectRouter
|
@@ -214,6 +218,53 @@ async def read_task_runs(
|
|
214
218
|
)
|
215
219
|
|
216
220
|
|
221
|
+
@router.post("/paginate", response_class=ORJSONResponse)
|
222
|
+
async def paginate_task_runs(
|
223
|
+
sort: schemas.sorting.TaskRunSort = Body(schemas.sorting.TaskRunSort.ID_DESC),
|
224
|
+
limit: int = dependencies.LimitBody(),
|
225
|
+
page: int = Body(1, ge=1),
|
226
|
+
flows: Optional[schemas.filters.FlowFilter] = None,
|
227
|
+
flow_runs: Optional[schemas.filters.FlowRunFilter] = None,
|
228
|
+
task_runs: Optional[schemas.filters.TaskRunFilter] = None,
|
229
|
+
deployments: Optional[schemas.filters.DeploymentFilter] = None,
|
230
|
+
db: PrefectDBInterface = Depends(provide_database_interface),
|
231
|
+
) -> TaskRunPaginationResponse:
|
232
|
+
"""
|
233
|
+
Pagination query for task runs.
|
234
|
+
"""
|
235
|
+
offset = (page - 1) * limit
|
236
|
+
|
237
|
+
async with db.session_context() as session:
|
238
|
+
runs = await models.task_runs.read_task_runs(
|
239
|
+
session=session,
|
240
|
+
flow_filter=flows,
|
241
|
+
flow_run_filter=flow_runs,
|
242
|
+
task_run_filter=task_runs,
|
243
|
+
deployment_filter=deployments,
|
244
|
+
offset=offset,
|
245
|
+
limit=limit,
|
246
|
+
sort=sort,
|
247
|
+
)
|
248
|
+
|
249
|
+
total_count = await models.task_runs.count_task_runs(
|
250
|
+
session=session,
|
251
|
+
flow_filter=flows,
|
252
|
+
flow_run_filter=flow_runs,
|
253
|
+
task_run_filter=task_runs,
|
254
|
+
deployment_filter=deployments,
|
255
|
+
)
|
256
|
+
|
257
|
+
return TaskRunPaginationResponse.model_validate(
|
258
|
+
dict(
|
259
|
+
results=runs,
|
260
|
+
count=total_count,
|
261
|
+
limit=limit,
|
262
|
+
pages=(total_count + limit - 1) // limit,
|
263
|
+
page=page,
|
264
|
+
)
|
265
|
+
)
|
266
|
+
|
267
|
+
|
217
268
|
@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
|
218
269
|
async def delete_task_run(
|
219
270
|
task_run_id: UUID = Path(..., description="The task run id", alias="id"),
|
prefect/settings/models/tasks.py
CHANGED
@@ -57,6 +57,11 @@ class TasksSettings(PrefectBaseSettings):
|
|
57
57
|
description="If `True`, enables a refresh of cached results: re-executing the task will refresh the cached results.",
|
58
58
|
)
|
59
59
|
|
60
|
+
default_no_cache: bool = Field(
|
61
|
+
default=False,
|
62
|
+
description="If `True`, sets the default cache policy on all tasks to `NO_CACHE`.",
|
63
|
+
)
|
64
|
+
|
60
65
|
default_retries: int = Field(
|
61
66
|
default=0,
|
62
67
|
ge=0,
|
prefect/tasks.py
CHANGED
@@ -422,6 +422,11 @@ class Task(Generic[P, R]):
|
|
422
422
|
|
423
423
|
self.task_key: str = _generate_task_key(self.fn)
|
424
424
|
|
425
|
+
# determine cache and result configuration
|
426
|
+
settings = get_current_settings()
|
427
|
+
if settings.tasks.default_no_cache and cache_policy is NotSet:
|
428
|
+
cache_policy = NO_CACHE
|
429
|
+
|
425
430
|
if cache_policy is not NotSet and cache_key_fn is not None:
|
426
431
|
logger.warning(
|
427
432
|
f"Both `cache_policy` and `cache_key_fn` are set on task {self}. `cache_key_fn` will be used."
|
@@ -458,7 +463,7 @@ class Task(Generic[P, R]):
|
|
458
463
|
)
|
459
464
|
elif cache_policy is NotSet and result_storage_key is None:
|
460
465
|
self.cache_policy = DEFAULT
|
461
|
-
elif result_storage_key:
|
466
|
+
elif cache_policy != NO_CACHE and result_storage_key:
|
462
467
|
# TODO: handle this situation with double storage
|
463
468
|
self.cache_policy = None
|
464
469
|
else:
|
@@ -468,7 +473,6 @@ class Task(Generic[P, R]):
|
|
468
473
|
# TODO: We can instantiate a `TaskRunPolicy` and add Pydantic bound checks to
|
469
474
|
# validate that the user passes positive numbers here
|
470
475
|
|
471
|
-
settings = get_current_settings()
|
472
476
|
self.retries: int = (
|
473
477
|
retries if retries is not None else settings.tasks.default_retries
|
474
478
|
)
|
prefect/transactions.py
CHANGED
@@ -23,6 +23,7 @@ from prefect.exceptions import (
|
|
23
23
|
MissingContextError,
|
24
24
|
SerializationError,
|
25
25
|
)
|
26
|
+
from prefect.filesystems import NullFileSystem
|
26
27
|
from prefect.logging.loggers import LoggingAdapter, get_logger, get_run_logger
|
27
28
|
from prefect.results import (
|
28
29
|
ResultRecord,
|
@@ -453,6 +454,10 @@ def transaction(
|
|
453
454
|
if key and not store:
|
454
455
|
store = get_result_store()
|
455
456
|
|
457
|
+
# Avoid inheriting a NullFileSystem for metadata_storage from a flow's result store
|
458
|
+
if store and isinstance(store.metadata_storage, NullFileSystem):
|
459
|
+
store = store.model_copy(update={"metadata_storage": None})
|
460
|
+
|
456
461
|
try:
|
457
462
|
_logger: Union[logging.Logger, LoggingAdapter] = logger or get_run_logger()
|
458
463
|
except MissingContextError:
|
prefect/utilities/engine.py
CHANGED
@@ -63,7 +63,7 @@ engine_logger: Logger = get_logger("engine")
|
|
63
63
|
T = TypeVar("T")
|
64
64
|
|
65
65
|
|
66
|
-
async def collect_task_run_inputs(expr: Any, max_depth: int = -1) -> set[
|
66
|
+
async def collect_task_run_inputs(expr: Any, max_depth: int = -1) -> set[TaskRunResult]:
|
67
67
|
"""
|
68
68
|
This function recurses through an expression to generate a set of any discernible
|
69
69
|
task run inputs it finds in the data structure. It produces a set of all inputs
|
@@ -76,7 +76,7 @@ async def collect_task_run_inputs(expr: Any, max_depth: int = -1) -> set[TaskRun
|
|
76
76
|
"""
|
77
77
|
# TODO: This function needs to be updated to detect parameters and constants
|
78
78
|
|
79
|
-
inputs: set[
|
79
|
+
inputs: set[TaskRunResult] = set()
|
80
80
|
|
81
81
|
def add_futures_and_states_to_inputs(obj: Any) -> None:
|
82
82
|
if isinstance(obj, PrefectFuture):
|
prefect/utilities/importtools.py
CHANGED
@@ -93,8 +93,11 @@ def load_script_as_module(path: str) -> ModuleType:
|
|
93
93
|
parent_path = str(Path(path).resolve().parent)
|
94
94
|
working_directory = os.getcwd()
|
95
95
|
|
96
|
-
|
97
|
-
|
96
|
+
module_name = os.path.splitext(Path(path).name)[0]
|
97
|
+
|
98
|
+
# fall back in case of filenames with the same names as modules
|
99
|
+
if module_name in sys.modules:
|
100
|
+
module_name = f"__prefect_loader_{id(path)}__"
|
98
101
|
|
99
102
|
spec = importlib.util.spec_from_file_location(
|
100
103
|
module_name,
|
@@ -112,15 +115,9 @@ def load_script_as_module(path: str) -> ModuleType:
|
|
112
115
|
with _get_sys_path_lock():
|
113
116
|
sys.path.insert(0, working_directory)
|
114
117
|
sys.path.insert(0, parent_path)
|
115
|
-
|
116
|
-
spec.loader.exec_module(module)
|
117
|
-
finally:
|
118
|
-
sys.path.remove(parent_path)
|
119
|
-
sys.path.remove(working_directory)
|
118
|
+
spec.loader.exec_module(module)
|
120
119
|
except Exception as exc:
|
121
120
|
raise ScriptError(user_exc=exc, path=path) from exc
|
122
|
-
finally:
|
123
|
-
sys.modules.pop(module_name)
|
124
121
|
|
125
122
|
return module
|
126
123
|
|
prefect/workers/base.py
CHANGED
@@ -60,6 +60,7 @@ from prefect.settings import (
|
|
60
60
|
get_current_settings,
|
61
61
|
)
|
62
62
|
from prefect.states import (
|
63
|
+
Cancelled,
|
63
64
|
Crashed,
|
64
65
|
Pending,
|
65
66
|
exception_to_failed_state,
|
@@ -1250,9 +1251,12 @@ class BaseWorker(abc.ABC, Generic[C, V, R]):
|
|
1250
1251
|
state_updates = state_updates or {}
|
1251
1252
|
state_updates.setdefault("name", "Cancelled")
|
1252
1253
|
state_updates.setdefault("type", StateType.CANCELLED)
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1254
|
+
|
1255
|
+
if flow_run.state:
|
1256
|
+
state = flow_run.state.model_copy(update=state_updates)
|
1257
|
+
else:
|
1258
|
+
# Unexpectedly when flow run does not have a state, create a new one
|
1259
|
+
state = Cancelled(**state_updates)
|
1256
1260
|
|
1257
1261
|
await self.client.set_flow_run_state(flow_run.id, state, force=True)
|
1258
1262
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
prefect/.prefectignore,sha256=awSprvKT0vI8a64mEOLrMxhxqcO-b0ERQeYpA2rNKVQ,390
|
2
2
|
prefect/__init__.py,sha256=iCdcC5ZmeewikCdnPEP6YBAjPNV5dvfxpYCTpw30Hkw,3685
|
3
3
|
prefect/__main__.py,sha256=WFjw3kaYJY6pOTA7WDOgqjsz8zUEUZHCcj3P5wyVa-g,66
|
4
|
-
prefect/_build_info.py,sha256=
|
4
|
+
prefect/_build_info.py,sha256=CVmFj0Mmllfz-aWbB-Deuyvgq5sfaVi0SeP84j9cUT4,181
|
5
5
|
prefect/_result_records.py,sha256=S6QmsODkehGVSzbMm6ig022PYbI6gNKz671p_8kBYx4,7789
|
6
6
|
prefect/_waiters.py,sha256=Ia2ITaXdHzevtyWIgJoOg95lrEXQqNEOquHvw3T33UQ,9026
|
7
7
|
prefect/agent.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
@@ -12,14 +12,14 @@ prefect/context.py,sha256=iJe4pkFqX6lz8ax1Mde_YqVmBVWmzeBe0ca2_nT6KPQ,23673
|
|
12
12
|
prefect/engine.py,sha256=uB5JN4l045i5JTlRQNT1x7MwlSiGQ5Bop2Q6jHHOgxY,3699
|
13
13
|
prefect/exceptions.py,sha256=-nih8qqdxRm6CX-4yrqwePVh8Mcpvla_V6N_KbdJsIU,11593
|
14
14
|
prefect/filesystems.py,sha256=v5YqGB4uXf9Ew2VuB9VCSkawvYMMVvEtZf7w1VmAmr8,18036
|
15
|
-
prefect/flow_engine.py,sha256=
|
16
|
-
prefect/flow_runs.py,sha256=
|
15
|
+
prefect/flow_engine.py,sha256=rjzpFrLswQ7sMX1-ap4SDYvWUawzSD0nnL6jVLa0ku0,59389
|
16
|
+
prefect/flow_runs.py,sha256=dbHcXsOq1UsNM7vyJV9gboCTylmdUwQ_-W4NQt4R4ds,17267
|
17
17
|
prefect/flows.py,sha256=dsrV-qNP_2eUsdG409XbtNtfMkTIzcAnBbXrD9OBUgQ,108950
|
18
18
|
prefect/futures.py,sha256=ADd8ceFqX7A8Kw8aXaqvbYRG03uU82OEY30xrP5vrwY,23599
|
19
19
|
prefect/main.py,sha256=hFeTTrr01qWKcRwZVEHVipyHEybS0VLTscFV6zG6GtY,2306
|
20
20
|
prefect/plugins.py,sha256=FPRLR2mWVBMuOnlzeiTD9krlHONZH2rtYLD753JQDNQ,2516
|
21
21
|
prefect/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
prefect/results.py,sha256=
|
22
|
+
prefect/results.py,sha256=_y-pBxl5Retn39pG5RE2d5lAb2ycJHhWPAoQWAzr9yQ,36633
|
23
23
|
prefect/schedules.py,sha256=9ufG4jhIA_R7vS9uXqnnZEgB7Ts922KMhNacWcveVgA,7291
|
24
24
|
prefect/serializers.py,sha256=QI0oEal_BO4HQaWSjr6ReSwT55Hn4sbSOXxGgQI1-y0,9249
|
25
25
|
prefect/states.py,sha256=tTZrN-IZKvmFcN8FR_4L-X-ZrmXi6z-cPXl6KdOy-XI,26920
|
@@ -27,8 +27,8 @@ prefect/task_engine.py,sha256=nbiaDyTNN89zP_ibJbe_Zrw2kLGZ4QqoeN221iIc5y0,61526
|
|
27
27
|
prefect/task_runners.py,sha256=Ce_ngocfq_X-NA5zhPj13IdVmzZ5h6gXlmfxYWs2AXA,15828
|
28
28
|
prefect/task_runs.py,sha256=7LIzfo3fondCyEUpU05sYFN5IfpZigBDXrhG5yc-8t0,9039
|
29
29
|
prefect/task_worker.py,sha256=mihWOZ3IpZCupqBboB_T1XhLm-0ApwwptTgUH-I3nKo,17794
|
30
|
-
prefect/tasks.py,sha256=
|
31
|
-
prefect/transactions.py,sha256=
|
30
|
+
prefect/tasks.py,sha256=wtDcBmmsAsmVCJy4SVQqcRdLQUtJjgMRyB_YhkddMcY,74268
|
31
|
+
prefect/transactions.py,sha256=BYvxr4ZSFmYDCODPhH8DO1_51inH35oJ75ZZOd_GI_w,16341
|
32
32
|
prefect/variables.py,sha256=dCK3vX7TbkqXZhnNT_v7rcGh3ISRqoR6pJVLpoll3Js,8342
|
33
33
|
prefect/_experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
prefect/_experimental/bundles.py,sha256=cxfUFdvBjd42imrimPG2MF3zJoyi1vGeYOVSiyjLC8Y,6245
|
@@ -102,7 +102,7 @@ prefect/client/orchestration/_concurrency_limits/client.py,sha256=ss73wg8W_dYNTy
|
|
102
102
|
prefect/client/orchestration/_deployments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
103
103
|
prefect/client/orchestration/_deployments/client.py,sha256=DfL6eiMaPkYBwCmkMcjKnyVIvE1qC8Xo14h2YqJhFsI,40769
|
104
104
|
prefect/client/orchestration/_flow_runs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
105
|
-
prefect/client/orchestration/_flow_runs/client.py,sha256=
|
105
|
+
prefect/client/orchestration/_flow_runs/client.py,sha256=fjh5J-LG8tsny7BGYEvynbuGuHDAudYHpx-PamL0GYQ,32220
|
106
106
|
prefect/client/orchestration/_flows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
107
107
|
prefect/client/orchestration/_flows/client.py,sha256=21rqVFm-AsqFK1S-vK2TyXKZ_oL65SN0_hiiddi6vIo,11006
|
108
108
|
prefect/client/orchestration/_logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -112,9 +112,9 @@ prefect/client/orchestration/_variables/client.py,sha256=wKBbZBLGgs5feDCil-xxKt3
|
|
112
112
|
prefect/client/orchestration/_work_pools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
113
113
|
prefect/client/orchestration/_work_pools/client.py,sha256=s1DfUQQBgB2sLiVVPhLNTlkueUDE6uFsh4mAzcSA1OE,19881
|
114
114
|
prefect/client/schemas/__init__.py,sha256=InZcDzdeWA2oaV0TlyvoMcyLcbi_aaqU1U9D6Gx-eoU,2747
|
115
|
-
prefect/client/schemas/actions.py,sha256=
|
115
|
+
prefect/client/schemas/actions.py,sha256=8kGnzpKGa7M9z5D10zoj9KfN42dZTqmmfVu0ELZjnRo,33007
|
116
116
|
prefect/client/schemas/filters.py,sha256=zaiDkalrIpKjd38V4aP1GHlqD24KTPCZiKtPyX69ZWE,36607
|
117
|
-
prefect/client/schemas/objects.py,sha256=
|
117
|
+
prefect/client/schemas/objects.py,sha256=7175pnyPFmGJeqvGrDDuSk7Jitl9h4uGLdDejkzdTy8,57688
|
118
118
|
prefect/client/schemas/responses.py,sha256=iTXTiUhdRL7PxNyJXMZ4ngT7C8SepT_z7g_pnUnVlzo,15629
|
119
119
|
prefect/client/schemas/schedules.py,sha256=4a1lGun448em33zrc0ZUOAew3jB8yqJ7Cxoni3HKR3I,14721
|
120
120
|
prefect/client/schemas/sorting.py,sha256=L-2Mx-igZPtsUoRUguTcG3nIEstMEMPD97NwPM2Ox5s,2579
|
@@ -138,14 +138,14 @@ prefect/deployments/__init__.py,sha256=_wb7NxDKhq11z9MjYsPckmT3o6MRhGLRgCV9TmvYt
|
|
138
138
|
prefect/deployments/base.py,sha256=KEc07W35yyzGJcV6GIZry8bKcNfvQk6JjJ99KKB6XpQ,11729
|
139
139
|
prefect/deployments/deployments.py,sha256=K3Rgnpjxo_T8I8LMwlq24OKqZiZBTE8-YnPg-YGUStM,171
|
140
140
|
prefect/deployments/flow_runs.py,sha256=NYe-Bphsy6ENLqSSfywQuX5cRZt-uVgzqGmOsf3Sqw4,7643
|
141
|
-
prefect/deployments/runner.py,sha256=
|
141
|
+
prefect/deployments/runner.py,sha256=QNKdKsLEzx3TE7T_3dJcK7bGvTCvNLY2WCpgDxiQDno,54368
|
142
142
|
prefect/deployments/schedules.py,sha256=2eL1-w8qXtwKVkgfUK7cuamwpKK3X6tN1QYTDa_gWxU,2190
|
143
143
|
prefect/deployments/steps/__init__.py,sha256=Dlz9VqMRyG1Gal8dj8vfGpPr0LyQhZdvcciozkK8WoY,206
|
144
144
|
prefect/deployments/steps/core.py,sha256=ulSgBFSx1lhBt1fP-UxebrernkumBDlympR6IPffV1g,6900
|
145
145
|
prefect/deployments/steps/pull.py,sha256=MDN8nHklgU6MXNMsMRDLDVbIqod87ccPJdt-21dshvU,9767
|
146
146
|
prefect/deployments/steps/utility.py,sha256=Ap_p44Rwz9Lxd6pt8hDW8phF3gwI3YjbsSpWHALDyoM,8157
|
147
147
|
prefect/docker/__init__.py,sha256=z6wdc6UFfiBG2jb9Jk64uCWVM04JKVWeVyDWwuuon8M,527
|
148
|
-
prefect/docker/docker_image.py,sha256=
|
148
|
+
prefect/docker/docker_image.py,sha256=bR_pEq5-FDxlwTj8CP_7nwZ_MiGK6KxIi8v7DRjy1Kg,3138
|
149
149
|
prefect/events/__init__.py,sha256=GtKl2bE--pJduTxelH2xy7SadlLJmmis8WR1EYixhuA,2094
|
150
150
|
prefect/events/actions.py,sha256=A7jS8bo4zWGnrt3QfSoQs0uYC1xfKXio3IfU0XtTb5s,9129
|
151
151
|
prefect/events/clients.py,sha256=PiPWtqX_OSZCWD7ekCuS_toi7DQMVC7FbPmI5q8cf2I,27254
|
@@ -183,12 +183,12 @@ prefect/logging/handlers.py,sha256=pIeS6gvuVnuh3lZ-kIC4ijRMSbVPkHo-rYeLMj5P8NA,1
|
|
183
183
|
prefect/logging/highlighters.py,sha256=BCf_LNhFInIfGPqwuu8YVrGa4wVxNc4YXo2pYgftpg4,1811
|
184
184
|
prefect/logging/loggers.py,sha256=rwFJv0i3dhdKr25XX-xUkQy4Vv4dy18bTy366jrC0OQ,12741
|
185
185
|
prefect/logging/logging.yml,sha256=tT7gTyC4NmngFSqFkCdHaw7R0GPNPDDsTCGZQByiJAQ,3169
|
186
|
-
prefect/runner/__init__.py,sha256=
|
187
|
-
prefect/runner/runner.py,sha256=
|
188
|
-
prefect/runner/server.py,sha256=
|
189
|
-
prefect/runner/storage.py,sha256=
|
190
|
-
prefect/runner/submit.py,sha256=
|
191
|
-
prefect/runner/utils.py,sha256=
|
186
|
+
prefect/runner/__init__.py,sha256=pQBd9wVrUVUDUFJlgiweKSnbahoBZwqnd2O2jkhrULY,158
|
187
|
+
prefect/runner/runner.py,sha256=oAJifbhbxfVcIHYWus-VrzvVzyEBkU_tIcYyLu9F6LI,65452
|
188
|
+
prefect/runner/server.py,sha256=pyMZTWFIn8eDvekfmiXxQZVzLC8zDJORFJO4QvMf_Fg,11328
|
189
|
+
prefect/runner/storage.py,sha256=L7aSjie5L6qbXYCDqYDX3ouQ_NsNMlmfjPeaWOC-ncs,28043
|
190
|
+
prefect/runner/submit.py,sha256=MtUrEKi4XznXXkDasILYYhY2w_DC2RcAL2hPJUgkgNo,8815
|
191
|
+
prefect/runner/utils.py,sha256=19DbhyiV6nvSpTXmnWlt7qPNt1jrz1jscznYrRVGurw,3413
|
192
192
|
prefect/runtime/__init__.py,sha256=JswiTlYRup2zXOYu8AqJ7czKtgcw9Kxo0tTbS6aWCqY,407
|
193
193
|
prefect/runtime/deployment.py,sha256=0A_cUVpYiFk3ciJw2ixy95dk9xBJcjisyF69pakSCcQ,5091
|
194
194
|
prefect/runtime/flow_run.py,sha256=hBa6h99G9K5iHdDUvHoJ2Yg9h5cZVEe_OEEJ2VuJHwk,10557
|
@@ -211,7 +211,7 @@ prefect/server/api/deployments.py,sha256=2C7pCY2renhyPDfi_IuzWoEhH620ERWLmQSTAnx
|
|
211
211
|
prefect/server/api/events.py,sha256=3-Qdt6ORxFv3nLoogQqvd72zEulJSoAmcqZto2OULuk,9907
|
212
212
|
prefect/server/api/flow_run_notification_policies.py,sha256=F8xNm6bgZTC3nFe9xCUJS4NlU9tLXZ8fShtJqmhT2m4,4828
|
213
213
|
prefect/server/api/flow_run_states.py,sha256=lIdxVE9CqLgtDCuH9bTaKkzHNL81FPrr11liPzvONrw,1661
|
214
|
-
prefect/server/api/flow_runs.py,sha256=
|
214
|
+
prefect/server/api/flow_runs.py,sha256=X3PKGoqlF5tsKhwcslBynmQpi2b5DygeD2TvJqCvFgE,33511
|
215
215
|
prefect/server/api/flows.py,sha256=Bz0ISh-9oY0W1X3mqA631_8678pQ6tuRGMpSgWAfxOc,7018
|
216
216
|
prefect/server/api/logs.py,sha256=0z78tM2B5sRgJWYRWJn5lHhRoLtZB_OU3C-uALV8tOs,1571
|
217
217
|
prefect/server/api/middleware.py,sha256=WkyuyeJIfo9Q0GAIVU5gO6yIGNVwoHwuBah5AB5oUyw,2733
|
@@ -220,14 +220,14 @@ prefect/server/api/run_history.py,sha256=FHepAgo1AYFeuh7rrAVzo_o3hu8Uc8-4DeH5aD5
|
|
220
220
|
prefect/server/api/saved_searches.py,sha256=UjoqLLe245QVIs6q5Vk4vdODCOoYzciEEjhi7B8sYCE,3233
|
221
221
|
prefect/server/api/server.py,sha256=GHbHTm8qd6i0mbqhnplFNHStUXwYnOuOFc4F9OAYk1c,32940
|
222
222
|
prefect/server/api/task_run_states.py,sha256=e63OPpxPudv_CIB5oKr8Z8rfQ-Osjm9Zq0iHe8obnMo,1647
|
223
|
-
prefect/server/api/task_runs.py,sha256=
|
223
|
+
prefect/server/api/task_runs.py,sha256=86lXKGUJJSElhkVcxX-kbjctrNe98nUe3U0McDCfTMw,13904
|
224
224
|
prefect/server/api/task_workers.py,sha256=cFP9M8tsApDL_JpySn-x6fOYy9RnOeOgKiqOl_UVVQM,1042
|
225
225
|
prefect/server/api/templates.py,sha256=92bLFfcahZUp5PVNTZPjl8uJSDj4ZYRTVdmTzZXkERg,1027
|
226
226
|
prefect/server/api/validation.py,sha256=HxSNyH8yb_tI-kOfjXESRjJp6WQK6hYWBJsaBxUvY34,14490
|
227
227
|
prefect/server/api/variables.py,sha256=SJaKuqInfQIEdMlJOemptBDN43KLFhlf_u9QwupDu7A,6185
|
228
228
|
prefect/server/api/work_queues.py,sha256=wBcbmkZDaQ5Ddi9wc8tNs6kYG_FdNtYwTCR0VkhPj2o,7588
|
229
229
|
prefect/server/api/workers.py,sha256=sGQzJED7E3uMP1jMdWAyB3d44xWBRtoHcTGY0oiEbm4,22602
|
230
|
-
prefect/server/api/collections_data/views/aggregate-worker-metadata.json,sha256=
|
230
|
+
prefect/server/api/collections_data/views/aggregate-worker-metadata.json,sha256=f6t13GRkIcLqGYB3OnXluAHEFoSqZM2SQP22vpcu0Mk,79793
|
231
231
|
prefect/server/api/static/prefect-logo-mark-gradient.png,sha256=ylRjJkI_JHCw8VbQasNnXQHwZW-sH-IQiUGSD3aWP1E,73430
|
232
232
|
prefect/server/api/ui/__init__.py,sha256=TCXO4ZUZCqCbm2QoNvWNTErkzWiX2nSACuO-0Tiomvg,93
|
233
233
|
prefect/server/api/ui/flow_runs.py,sha256=ALmUFY4WrJggN1ha0z-tqXeddG2GptswbPnB7iYixUM,4172
|
@@ -255,7 +255,7 @@ prefect/settings/models/logging.py,sha256=Sj9GDNr5QMFaP6CN0WJyfpwhpOk4p1yhv45dyQ
|
|
255
255
|
prefect/settings/models/results.py,sha256=VWFplQSSJyc0LXnziw1H5b3N_PDS32QBe_q2MWwYni0,1484
|
256
256
|
prefect/settings/models/root.py,sha256=b9ZamM-BcD75Xsk0pZej3o2ix2kHkTP14hhITveFcTo,16549
|
257
257
|
prefect/settings/models/runner.py,sha256=rD8OmNLwILmqnGe9YkM1dWKsulx3clYm4LI5N9vD5yM,1991
|
258
|
-
prefect/settings/models/tasks.py,sha256=
|
258
|
+
prefect/settings/models/tasks.py,sha256=XA83-EmWv1FKvODSzvI1cvS3tGEbNs2qtdh0AbUdblQ,3640
|
259
259
|
prefect/settings/models/testing.py,sha256=j9YH_WkB14iEzOjUtTmvY978qRSbgCypFSEi_cOs8no,1820
|
260
260
|
prefect/settings/models/worker.py,sha256=zeDU71aR4CEvEOKyH-1jgEyol8XYe29PExjIC6a8Wv0,1378
|
261
261
|
prefect/settings/models/server/__init__.py,sha256=KJmffmlHb8GYnClaeYcerae-IaeNsNMucKKRRS_zG9Q,33
|
@@ -291,11 +291,11 @@ prefect/utilities/compat.py,sha256=nnPA3lf2f4Y-l645tYFFNmj5NDPaYvjqa9pbGKZ3WKE,5
|
|
291
291
|
prefect/utilities/context.py,sha256=23SDMgdt07SjmB1qShiykHfGgiv55NBzdbMXM3fE9CI,1447
|
292
292
|
prefect/utilities/dispatch.py,sha256=u6GSGSO3_6vVoIqHVc849lsKkC-I1wUl6TX134GwRBo,6310
|
293
293
|
prefect/utilities/dockerutils.py,sha256=pQ5rJTDX6xXBzr_wFcCmcPo88YPjRp54YHf39iOnkPY,20878
|
294
|
-
prefect/utilities/engine.py,sha256=
|
294
|
+
prefect/utilities/engine.py,sha256=H5NFEAlDhragIabDEJYEZbnG4pM03TRhj2Gb4YCtvvg,28973
|
295
295
|
prefect/utilities/filesystem.py,sha256=Pwesv71PGFhf3lPa1iFyMqZZprBjy9nEKCVxTkf_hXw,5710
|
296
296
|
prefect/utilities/generics.py,sha256=o77e8a5iwmrisOf42wLp2WI9YvSw2xDW4vFdpdEwr3I,543
|
297
297
|
prefect/utilities/hashing.py,sha256=7jRy26s46IJAFRmVnCnoK9ek9N4p_UfXxQQvu2tW6dM,2589
|
298
|
-
prefect/utilities/importtools.py,sha256=
|
298
|
+
prefect/utilities/importtools.py,sha256=u8kx7mzNPiM81Lyk57HLn6Z9kqA-gQ9y5KsYu4d6VhI,17734
|
299
299
|
prefect/utilities/math.py,sha256=UPIdJMP13lCU3o0Yz98o4VDw3LTkkrsOAsvAdA3Xifc,2954
|
300
300
|
prefect/utilities/names.py,sha256=PcNp3IbSoJY6P3UiJDYDjpYQw6BYWtn6OarFDCq1dUE,1744
|
301
301
|
prefect/utilities/processutils.py,sha256=k_VD41Q0EBz-DP2lN7AcOkFGpYH3ekKGk4YV_OuvQc8,16255
|
@@ -312,13 +312,13 @@ prefect/utilities/schema_tools/__init__.py,sha256=At3rMHd2g_Em2P3_dFQlFgqR_EpBwr
|
|
312
312
|
prefect/utilities/schema_tools/hydration.py,sha256=NkRhWkNfxxFmVGhNDfmxdK_xeKaEhs3a42q83Sg9cT4,9436
|
313
313
|
prefect/utilities/schema_tools/validation.py,sha256=Wix26IVR-ZJ32-6MX2pHhrwm3reB-Q4iB6_phn85OKE,10743
|
314
314
|
prefect/workers/__init__.py,sha256=EaM1F0RZ-XIJaGeTKLsXDnfOPHzVWk5bk0_c4BVS44M,64
|
315
|
-
prefect/workers/base.py,sha256=
|
315
|
+
prefect/workers/base.py,sha256=XTMuLTKf-cAA1omH374Peyk0be1G9mquYIjpx-j0W6g,53169
|
316
316
|
prefect/workers/block.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
317
317
|
prefect/workers/cloud.py,sha256=dPvG1jDGD5HSH7aM2utwtk6RaJ9qg13XjkA0lAIgQmY,287
|
318
318
|
prefect/workers/process.py,sha256=uxOwcqA2Ps-V-W6WeSdKCQMINrCxBEVx1K1Un8pb7vs,8973
|
319
319
|
prefect/workers/server.py,sha256=SEuyScZ5nGm2OotdtbHjpvqJlTRVWCh29ND7FeL_fZA,1974
|
320
320
|
prefect/workers/utilities.py,sha256=VfPfAlGtTuDj0-Kb8WlMgAuOfgXCdrGAnKMapPSBrwc,2483
|
321
|
-
prefect_client-3.2.
|
322
|
-
prefect_client-3.2.
|
323
|
-
prefect_client-3.2.
|
324
|
-
prefect_client-3.2.
|
321
|
+
prefect_client-3.2.14.dist-info/METADATA,sha256=qDbKPaNFkOv43dwCV7Uh2egkTsJM54dBUfaFjFDBbds,7193
|
322
|
+
prefect_client-3.2.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
323
|
+
prefect_client-3.2.14.dist-info/licenses/LICENSE,sha256=MCxsn8osAkzfxKC4CC_dLcUkU8DZLkyihZ8mGs3Ah3Q,11357
|
324
|
+
prefect_client-3.2.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|