prefect-client 3.1.10__py3-none-any.whl → 3.1.12__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/_experimental/lineage.py +7 -8
- prefect/_experimental/sla/__init__.py +0 -0
- prefect/_experimental/sla/client.py +66 -0
- prefect/_experimental/sla/objects.py +53 -0
- prefect/_internal/_logging.py +15 -3
- prefect/_internal/compatibility/async_dispatch.py +22 -16
- prefect/_internal/compatibility/deprecated.py +42 -18
- prefect/_internal/compatibility/migration.py +2 -2
- prefect/_internal/concurrency/inspection.py +12 -14
- prefect/_internal/concurrency/primitives.py +2 -2
- prefect/_internal/concurrency/services.py +154 -80
- prefect/_internal/concurrency/waiters.py +13 -9
- prefect/_internal/pydantic/annotations/pendulum.py +7 -7
- prefect/_internal/pytz.py +4 -3
- prefect/_internal/retries.py +10 -5
- prefect/_internal/schemas/bases.py +19 -10
- prefect/_internal/schemas/validators.py +227 -388
- prefect/_version.py +3 -3
- prefect/automations.py +236 -30
- prefect/blocks/__init__.py +3 -3
- prefect/blocks/abstract.py +53 -30
- prefect/blocks/core.py +183 -84
- prefect/blocks/notifications.py +133 -73
- prefect/blocks/redis.py +13 -9
- prefect/blocks/system.py +24 -11
- prefect/blocks/webhook.py +7 -5
- prefect/cache_policies.py +3 -2
- prefect/client/orchestration/__init__.py +1957 -0
- prefect/client/orchestration/_artifacts/__init__.py +0 -0
- prefect/client/orchestration/_artifacts/client.py +239 -0
- prefect/client/orchestration/_automations/__init__.py +0 -0
- prefect/client/orchestration/_automations/client.py +329 -0
- prefect/client/orchestration/_blocks_documents/__init__.py +0 -0
- prefect/client/orchestration/_blocks_documents/client.py +334 -0
- prefect/client/orchestration/_blocks_schemas/__init__.py +0 -0
- prefect/client/orchestration/_blocks_schemas/client.py +200 -0
- prefect/client/orchestration/_blocks_types/__init__.py +0 -0
- prefect/client/orchestration/_blocks_types/client.py +380 -0
- prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- prefect/client/orchestration/_concurrency_limits/client.py +762 -0
- prefect/client/orchestration/_deployments/__init__.py +0 -0
- prefect/client/orchestration/_deployments/client.py +1128 -0
- prefect/client/orchestration/_flow_runs/__init__.py +0 -0
- prefect/client/orchestration/_flow_runs/client.py +903 -0
- prefect/client/orchestration/_flows/__init__.py +0 -0
- prefect/client/orchestration/_flows/client.py +343 -0
- prefect/client/orchestration/_logs/__init__.py +0 -0
- prefect/client/orchestration/_logs/client.py +97 -0
- prefect/client/orchestration/_variables/__init__.py +0 -0
- prefect/client/orchestration/_variables/client.py +157 -0
- prefect/client/orchestration/base.py +46 -0
- prefect/client/orchestration/routes.py +145 -0
- prefect/client/schemas/__init__.py +68 -28
- prefect/client/schemas/actions.py +2 -2
- prefect/client/schemas/filters.py +5 -0
- prefect/client/schemas/objects.py +8 -15
- prefect/client/schemas/schedules.py +22 -10
- prefect/concurrency/_asyncio.py +87 -0
- prefect/concurrency/{events.py → _events.py} +10 -10
- prefect/concurrency/asyncio.py +20 -104
- prefect/concurrency/context.py +6 -4
- prefect/concurrency/services.py +26 -74
- prefect/concurrency/sync.py +23 -44
- prefect/concurrency/v1/_asyncio.py +63 -0
- prefect/concurrency/v1/{events.py → _events.py} +13 -15
- prefect/concurrency/v1/asyncio.py +27 -80
- prefect/concurrency/v1/context.py +6 -4
- prefect/concurrency/v1/services.py +33 -79
- prefect/concurrency/v1/sync.py +18 -37
- prefect/context.py +66 -45
- prefect/deployments/base.py +10 -144
- prefect/deployments/flow_runs.py +12 -2
- prefect/deployments/runner.py +53 -4
- prefect/deployments/steps/pull.py +13 -0
- prefect/engine.py +17 -4
- prefect/events/clients.py +7 -1
- prefect/events/schemas/events.py +3 -2
- prefect/filesystems.py +6 -2
- prefect/flow_engine.py +101 -85
- prefect/flows.py +10 -1
- prefect/input/run_input.py +2 -1
- prefect/logging/logging.yml +1 -1
- prefect/main.py +1 -3
- prefect/results.py +2 -307
- prefect/runner/runner.py +4 -2
- prefect/runner/storage.py +87 -21
- prefect/serializers.py +32 -25
- prefect/settings/legacy.py +4 -4
- prefect/settings/models/api.py +3 -3
- prefect/settings/models/cli.py +3 -3
- prefect/settings/models/client.py +5 -3
- prefect/settings/models/cloud.py +8 -3
- prefect/settings/models/deployments.py +3 -3
- prefect/settings/models/experiments.py +4 -7
- prefect/settings/models/flows.py +3 -3
- prefect/settings/models/internal.py +4 -2
- prefect/settings/models/logging.py +4 -3
- prefect/settings/models/results.py +3 -3
- prefect/settings/models/root.py +3 -2
- prefect/settings/models/runner.py +4 -4
- prefect/settings/models/server/api.py +3 -3
- prefect/settings/models/server/database.py +11 -4
- prefect/settings/models/server/deployments.py +6 -2
- prefect/settings/models/server/ephemeral.py +4 -2
- prefect/settings/models/server/events.py +3 -2
- prefect/settings/models/server/flow_run_graph.py +6 -2
- prefect/settings/models/server/root.py +3 -3
- prefect/settings/models/server/services.py +26 -11
- prefect/settings/models/server/tasks.py +6 -3
- prefect/settings/models/server/ui.py +3 -3
- prefect/settings/models/tasks.py +5 -5
- prefect/settings/models/testing.py +3 -3
- prefect/settings/models/worker.py +5 -3
- prefect/settings/profiles.py +15 -2
- prefect/states.py +61 -45
- prefect/task_engine.py +54 -75
- prefect/task_runners.py +56 -55
- prefect/task_worker.py +2 -2
- prefect/tasks.py +90 -36
- prefect/telemetry/bootstrap.py +10 -9
- prefect/telemetry/run_telemetry.py +13 -8
- prefect/telemetry/services.py +4 -0
- prefect/transactions.py +4 -15
- prefect/utilities/_git.py +34 -0
- prefect/utilities/asyncutils.py +1 -1
- prefect/utilities/engine.py +3 -19
- prefect/utilities/generics.py +18 -0
- prefect/utilities/templating.py +25 -1
- prefect/workers/base.py +6 -3
- prefect/workers/process.py +1 -1
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/METADATA +2 -2
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/RECORD +135 -109
- prefect/client/orchestration.py +0 -4523
- prefect/records/__init__.py +0 -1
- prefect/records/base.py +0 -235
- prefect/records/filesystem.py +0 -213
- prefect/records/memory.py +0 -184
- prefect/records/result_store.py +0 -70
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.10.dist-info → prefect_client-3.1.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
from typing import Literal
|
2
|
+
|
3
|
+
ServerRoutes = Literal[
|
4
|
+
"/admin/database/clear",
|
5
|
+
"/admin/database/create",
|
6
|
+
"/admin/database/drop",
|
7
|
+
"/admin/settings",
|
8
|
+
"/admin/version",
|
9
|
+
"/artifacts/",
|
10
|
+
"/artifacts/{id}",
|
11
|
+
"/artifacts/{key}/latest",
|
12
|
+
"/artifacts/count",
|
13
|
+
"/artifacts/filter",
|
14
|
+
"/artifacts/latest/count",
|
15
|
+
"/artifacts/latest/filter",
|
16
|
+
"/automations/",
|
17
|
+
"/automations/{id}",
|
18
|
+
"/automations/count",
|
19
|
+
"/automations/filter",
|
20
|
+
"/automations/owned-by/{resource_id}",
|
21
|
+
"/automations/related-to/{resource_id}",
|
22
|
+
"/block_capabilities/",
|
23
|
+
"/block_documents/",
|
24
|
+
"/block_documents/{id}",
|
25
|
+
"/block_documents/count",
|
26
|
+
"/block_documents/filter",
|
27
|
+
"/block_schemas/",
|
28
|
+
"/block_schemas/{id}",
|
29
|
+
"/block_schemas/checksum/{checksum}",
|
30
|
+
"/block_schemas/filter",
|
31
|
+
"/block_types/",
|
32
|
+
"/block_types/{id}",
|
33
|
+
"/block_types/filter",
|
34
|
+
"/block_types/install_system_block_types",
|
35
|
+
"/block_types/slug/{slug}",
|
36
|
+
"/block_types/slug/{slug}/block_documents",
|
37
|
+
"/block_types/slug/{slug}/block_documents/name/{block_document_name}",
|
38
|
+
"/collections/views/{view}",
|
39
|
+
"/concurrency_limits/",
|
40
|
+
"/concurrency_limits/{id}",
|
41
|
+
"/concurrency_limits/decrement",
|
42
|
+
"/concurrency_limits/filter",
|
43
|
+
"/concurrency_limits/increment",
|
44
|
+
"/concurrency_limits/tag/{tag}",
|
45
|
+
"/concurrency_limits/tag/{tag}/reset",
|
46
|
+
"/csrf-token",
|
47
|
+
"/deployments/",
|
48
|
+
"/deployments/{id}",
|
49
|
+
"/deployments/{id}/create_flow_run",
|
50
|
+
"/deployments/{id}/pause_deployment",
|
51
|
+
"/deployments/{id}/resume_deployment",
|
52
|
+
"/deployments/{id}/schedule",
|
53
|
+
"/deployments/{id}/schedules",
|
54
|
+
"/deployments/{id}/schedules/{schedule_id}",
|
55
|
+
"/deployments/{id}/work_queue_check",
|
56
|
+
"/deployments/count",
|
57
|
+
"/deployments/filter",
|
58
|
+
"/deployments/get_scheduled_flow_runs",
|
59
|
+
"/deployments/name/{flow_name}/{deployment_name}",
|
60
|
+
"/deployments/paginate",
|
61
|
+
"/events",
|
62
|
+
"/events/count-by/{countable}",
|
63
|
+
"/events/filter",
|
64
|
+
"/events/filter/next",
|
65
|
+
"/flow_run_notification_policies/",
|
66
|
+
"/flow_run_notification_policies/{id}",
|
67
|
+
"/flow_run_notification_policies/filter",
|
68
|
+
"/flow_run_states/",
|
69
|
+
"/flow_run_states/{id}",
|
70
|
+
"/flow_runs/",
|
71
|
+
"/flow_runs/{id}",
|
72
|
+
"/flow_runs/{id}/graph",
|
73
|
+
"/flow_runs/{id}/graph-v2",
|
74
|
+
"/flow_runs/{id}/input",
|
75
|
+
"/flow_runs/{id}/input/{key}",
|
76
|
+
"/flow_runs/{id}/input/filter",
|
77
|
+
"/flow_runs/{id}/labels",
|
78
|
+
"/flow_runs/{id}/logs/download",
|
79
|
+
"/flow_runs/{id}/resume",
|
80
|
+
"/flow_runs/{id}/set_state",
|
81
|
+
"/flow_runs/count",
|
82
|
+
"/flow_runs/filter",
|
83
|
+
"/flow_runs/history",
|
84
|
+
"/flow_runs/lateness",
|
85
|
+
"/flow_runs/paginate",
|
86
|
+
"/flows/",
|
87
|
+
"/flows/{id}",
|
88
|
+
"/flows/count",
|
89
|
+
"/flows/filter",
|
90
|
+
"/flows/name/{name}",
|
91
|
+
"/flows/paginate",
|
92
|
+
"/health",
|
93
|
+
"/hello",
|
94
|
+
"/logs/",
|
95
|
+
"/logs/filter",
|
96
|
+
"/ready",
|
97
|
+
"/saved_searches/",
|
98
|
+
"/saved_searches/{id}",
|
99
|
+
"/saved_searches/filter",
|
100
|
+
"/task_run_states/",
|
101
|
+
"/task_run_states/{id}",
|
102
|
+
"/task_runs/",
|
103
|
+
"/task_runs/{id}",
|
104
|
+
"/task_runs/{id}/set_state",
|
105
|
+
"/task_runs/count",
|
106
|
+
"/task_runs/filter",
|
107
|
+
"/task_runs/history",
|
108
|
+
"/task_workers/filter",
|
109
|
+
"/templates/validate",
|
110
|
+
"/ui/flow_runs/count-task-runs",
|
111
|
+
"/ui/flow_runs/history",
|
112
|
+
"/ui/flows/count-deployments",
|
113
|
+
"/ui/flows/next-runs",
|
114
|
+
"/ui/schemas/validate",
|
115
|
+
"/ui/task_runs/count",
|
116
|
+
"/ui/task_runs/dashboard/counts",
|
117
|
+
"/v2/concurrency_limits/",
|
118
|
+
"/v2/concurrency_limits/{id_or_name}",
|
119
|
+
"/v2/concurrency_limits/decrement",
|
120
|
+
"/v2/concurrency_limits/filter",
|
121
|
+
"/v2/concurrency_limits/increment",
|
122
|
+
"/variables/",
|
123
|
+
"/variables/{id}",
|
124
|
+
"/variables/count",
|
125
|
+
"/variables/filter",
|
126
|
+
"/variables/name/{name}",
|
127
|
+
"/version",
|
128
|
+
"/work_pools/",
|
129
|
+
"/work_pools/{name}",
|
130
|
+
"/work_pools/{name}/get_scheduled_flow_runs",
|
131
|
+
"/work_pools/{work_pool_name}/queues",
|
132
|
+
"/work_pools/{work_pool_name}/queues/{name}",
|
133
|
+
"/work_pools/{work_pool_name}/queues/filter",
|
134
|
+
"/work_pools/{work_pool_name}/workers/{name}",
|
135
|
+
"/work_pools/{work_pool_name}/workers/filter",
|
136
|
+
"/work_pools/{work_pool_name}/workers/heartbeat",
|
137
|
+
"/work_pools/count",
|
138
|
+
"/work_pools/filter",
|
139
|
+
"/work_queues/",
|
140
|
+
"/work_queues/{id}",
|
141
|
+
"/work_queues/{id}/get_runs",
|
142
|
+
"/work_queues/{id}/status",
|
143
|
+
"/work_queues/filter",
|
144
|
+
"/work_queues/name/{name}",
|
145
|
+
]
|
@@ -1,32 +1,58 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
import importlib
|
2
|
+
import sys
|
3
|
+
from typing import Any, TYPE_CHECKING
|
3
4
|
|
4
|
-
|
5
|
-
from .
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from .actions import BlockTypeUpdate, StateCreate
|
7
|
+
from .objects import (
|
8
|
+
DEFAULT_BLOCK_SCHEMA_VERSION,
|
9
|
+
BlockDocument,
|
10
|
+
BlockSchema,
|
11
|
+
BlockType,
|
12
|
+
FlowRun,
|
13
|
+
FlowRunPolicy,
|
14
|
+
State,
|
15
|
+
StateDetails,
|
16
|
+
StateType,
|
17
|
+
TaskRun,
|
18
|
+
TaskRunInput,
|
19
|
+
TaskRunPolicy,
|
20
|
+
TaskRunResult,
|
21
|
+
Workspace,
|
22
|
+
)
|
23
|
+
from .responses import (
|
24
|
+
OrchestrationResult,
|
25
|
+
SetStateStatus,
|
26
|
+
StateAbortDetails,
|
27
|
+
StateAcceptDetails,
|
28
|
+
StateRejectDetails,
|
29
|
+
)
|
28
30
|
|
29
|
-
|
31
|
+
_public_api = {
|
32
|
+
"BlockDocument": (__package__, ".objects"),
|
33
|
+
"BlockSchema": (__package__, ".objects"),
|
34
|
+
"BlockType": (__package__, ".objects"),
|
35
|
+
"BlockTypeUpdate": (__package__, ".actions"),
|
36
|
+
"DEFAULT_BLOCK_SCHEMA_VERSION": (__package__, ".objects"),
|
37
|
+
"FlowRun": (__package__, ".objects"),
|
38
|
+
"FlowRunPolicy": (__package__, ".objects"),
|
39
|
+
"OrchestrationResult": (__package__, ".responses"),
|
40
|
+
"SetStateStatus": (__package__, ".responses"),
|
41
|
+
"State": (__package__, ".objects"),
|
42
|
+
"StateAbortDetails": (__package__, ".responses"),
|
43
|
+
"StateAcceptDetails": (__package__, ".responses"),
|
44
|
+
"StateCreate": (__package__, ".actions"),
|
45
|
+
"StateDetails": (__package__, ".objects"),
|
46
|
+
"StateRejectDetails": (__package__, ".responses"),
|
47
|
+
"StateType": (__package__, ".objects"),
|
48
|
+
"TaskRun": (__package__, ".objects"),
|
49
|
+
"TaskRunInput": (__package__, ".objects"),
|
50
|
+
"TaskRunPolicy": (__package__, ".objects"),
|
51
|
+
"TaskRunResult": (__package__, ".objects"),
|
52
|
+
"Workspace": (__package__, ".objects"),
|
53
|
+
}
|
54
|
+
|
55
|
+
__all__ = [
|
30
56
|
"BlockDocument",
|
31
57
|
"BlockSchema",
|
32
58
|
"BlockType",
|
@@ -48,4 +74,18 @@ __all__ = (
|
|
48
74
|
"TaskRunPolicy",
|
49
75
|
"TaskRunResult",
|
50
76
|
"Workspace",
|
51
|
-
|
77
|
+
]
|
78
|
+
|
79
|
+
|
80
|
+
def __getattr__(attr_name: str) -> Any:
|
81
|
+
try:
|
82
|
+
if (dynamic_attr := _public_api.get(attr_name)) is None:
|
83
|
+
raise AttributeError(f"module {__name__} has no attribute {attr_name}")
|
84
|
+
|
85
|
+
package, mname = dynamic_attr
|
86
|
+
module = importlib.import_module(mname, package=package)
|
87
|
+
return getattr(module, attr_name)
|
88
|
+
except ModuleNotFoundError as ex:
|
89
|
+
mname, _, attr = (ex.name or "").rpartition(".")
|
90
|
+
ctx = {"name": mname, "obj": attr} if sys.version_info >= (3, 10) else {}
|
91
|
+
raise AttributeError(f"module {mname} has no attribute {attr}", **ctx) from ex
|
@@ -39,7 +39,7 @@ from prefect.utilities.collections import listrepr
|
|
39
39
|
from prefect.utilities.pydantic import get_class_fields_only
|
40
40
|
|
41
41
|
if TYPE_CHECKING:
|
42
|
-
from prefect.results import
|
42
|
+
from prefect.results import ResultRecordMetadata
|
43
43
|
|
44
44
|
R = TypeVar("R")
|
45
45
|
|
@@ -51,7 +51,7 @@ class StateCreate(ActionBaseModel):
|
|
51
51
|
name: Optional[str] = Field(default=None)
|
52
52
|
message: Optional[str] = Field(default=None, examples=["Run started"])
|
53
53
|
state_details: StateDetails = Field(default_factory=StateDetails)
|
54
|
-
data: Union["
|
54
|
+
data: Union["ResultRecordMetadata", Any] = Field(
|
55
55
|
default=None,
|
56
56
|
)
|
57
57
|
|
@@ -505,6 +505,11 @@ class DeploymentFilterTags(PrefectBaseModel, OperatorMixin):
|
|
505
505
|
" superset of the list"
|
506
506
|
),
|
507
507
|
)
|
508
|
+
any_: Optional[list[str]] = Field(
|
509
|
+
default=None,
|
510
|
+
examples=[["tag-1", "tag-2"]],
|
511
|
+
description="A list of tags to include",
|
512
|
+
)
|
508
513
|
is_null_: Optional[bool] = Field(
|
509
514
|
default=None, description="If true, only include deployments without tags"
|
510
515
|
)
|
@@ -10,7 +10,6 @@ from typing import (
|
|
10
10
|
Generic,
|
11
11
|
Optional,
|
12
12
|
Union,
|
13
|
-
cast,
|
14
13
|
overload,
|
15
14
|
)
|
16
15
|
from uuid import UUID, uuid4
|
@@ -65,7 +64,7 @@ from prefect.utilities.pydantic import handle_secret_render
|
|
65
64
|
|
66
65
|
if TYPE_CHECKING:
|
67
66
|
from prefect.client.schemas.actions import StateCreate
|
68
|
-
from prefect.results import
|
67
|
+
from prefect.results import ResultRecordMetadata
|
69
68
|
|
70
69
|
DateTime = pendulum.DateTime
|
71
70
|
else:
|
@@ -122,7 +121,7 @@ class WorkPoolStatus(AutoEnum):
|
|
122
121
|
PAUSED = AutoEnum.auto()
|
123
122
|
|
124
123
|
@property
|
125
|
-
def display_name(self):
|
124
|
+
def display_name(self) -> str:
|
126
125
|
return self.name.replace("_", " ").capitalize()
|
127
126
|
|
128
127
|
|
@@ -195,9 +194,7 @@ class StateDetails(PrefectBaseModel):
|
|
195
194
|
|
196
195
|
|
197
196
|
def data_discriminator(x: Any) -> str:
|
198
|
-
if isinstance(x, dict) and "
|
199
|
-
return "BaseResult"
|
200
|
-
elif isinstance(x, dict) and "storage_key" in x:
|
197
|
+
if isinstance(x, dict) and "storage_key" in x:
|
201
198
|
return "ResultRecordMetadata"
|
202
199
|
return "Any"
|
203
200
|
|
@@ -214,7 +211,6 @@ class State(ObjectBaseModel, Generic[R]):
|
|
214
211
|
state_details: StateDetails = Field(default_factory=StateDetails)
|
215
212
|
data: Annotated[
|
216
213
|
Union[
|
217
|
-
Annotated["BaseResult[R]", Tag("BaseResult")],
|
218
214
|
Annotated["ResultRecordMetadata", Tag("ResultRecordMetadata")],
|
219
215
|
Annotated[Any, Tag("Any")],
|
220
216
|
],
|
@@ -347,15 +343,12 @@ class State(ObjectBaseModel, Generic[R]):
|
|
347
343
|
"""
|
348
344
|
from prefect.client.schemas.actions import StateCreate
|
349
345
|
from prefect.results import (
|
350
|
-
BaseResult,
|
351
346
|
ResultRecord,
|
352
347
|
should_persist_result,
|
353
348
|
)
|
354
349
|
|
355
|
-
if isinstance(self.data,
|
356
|
-
data =
|
357
|
-
elif isinstance(self.data, ResultRecord) and should_persist_result():
|
358
|
-
data = self.data.metadata
|
350
|
+
if isinstance(self.data, ResultRecord) and should_persist_result():
|
351
|
+
data = self.data.metadata # pyright: ignore[reportUnknownMemberType] unable to narrow ResultRecord type
|
359
352
|
else:
|
360
353
|
data = None
|
361
354
|
|
@@ -386,7 +379,7 @@ class State(ObjectBaseModel, Generic[R]):
|
|
386
379
|
|
387
380
|
@model_validator(mode="after")
|
388
381
|
def set_unpersisted_results_to_none(self) -> Self:
|
389
|
-
if isinstance(self.data, dict) and self.data.get("type") == "unpersisted":
|
382
|
+
if isinstance(self.data, dict) and self.data.get("type") == "unpersisted": # pyright: ignore[reportUnknownMemberType] unable to narrow dict type
|
390
383
|
self.data = None
|
391
384
|
return self
|
392
385
|
|
@@ -531,7 +524,7 @@ class FlowRunPolicy(PrefectBaseModel):
|
|
531
524
|
@classmethod
|
532
525
|
def populate_deprecated_fields(cls, values: Any) -> Any:
|
533
526
|
if isinstance(values, dict):
|
534
|
-
return set_run_policy_deprecated_fields(values)
|
527
|
+
return set_run_policy_deprecated_fields(values) # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType] unable to narrow dict type
|
535
528
|
return values
|
536
529
|
|
537
530
|
|
@@ -1262,7 +1255,7 @@ class BlockDocumentReference(ObjectBaseModel):
|
|
1262
1255
|
@classmethod
|
1263
1256
|
def validate_parent_and_ref_are_different(cls, values: Any) -> Any:
|
1264
1257
|
if isinstance(values, dict):
|
1265
|
-
return validate_parent_and_ref_diff(values)
|
1258
|
+
return validate_parent_and_ref_diff(values) # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType] unable to narrow dict type
|
1266
1259
|
return values
|
1267
1260
|
|
1268
1261
|
|
@@ -33,6 +33,23 @@ MAX_ITERATIONS = 1000
|
|
33
33
|
MAX_RRULE_LENGTH = 6500
|
34
34
|
|
35
35
|
|
36
|
+
def is_valid_timezone(v: str) -> bool:
|
37
|
+
"""
|
38
|
+
Validate that the provided timezone is a valid IANA timezone.
|
39
|
+
|
40
|
+
Unfortunately this list is slightly different from the list of valid
|
41
|
+
timezones in pendulum that we use for cron and interval timezone validation.
|
42
|
+
"""
|
43
|
+
from prefect._internal.pytz import HAS_PYTZ
|
44
|
+
|
45
|
+
if HAS_PYTZ:
|
46
|
+
import pytz
|
47
|
+
else:
|
48
|
+
from prefect._internal import pytz
|
49
|
+
|
50
|
+
return v in pytz.all_timezones_set
|
51
|
+
|
52
|
+
|
36
53
|
class IntervalSchedule(PrefectBaseModel):
|
37
54
|
"""
|
38
55
|
A schedule formed by adding `interval` increments to an `anchor_date`. If no
|
@@ -305,18 +322,13 @@ class RRuleSchedule(PrefectBaseModel):
|
|
305
322
|
Unfortunately this list is slightly different from the list of valid
|
306
323
|
timezones in pendulum that we use for cron and interval timezone validation.
|
307
324
|
"""
|
308
|
-
|
325
|
+
if v is None:
|
326
|
+
return "UTC"
|
309
327
|
|
310
|
-
if
|
311
|
-
|
312
|
-
else:
|
313
|
-
from prefect._internal import pytz
|
328
|
+
if is_valid_timezone(v):
|
329
|
+
return v
|
314
330
|
|
315
|
-
|
316
|
-
raise ValueError(f'Invalid timezone: "{v}"')
|
317
|
-
elif v is None:
|
318
|
-
return "UTC"
|
319
|
-
return v
|
331
|
+
raise ValueError(f'Invalid timezone: "{v}"')
|
320
332
|
|
321
333
|
|
322
334
|
class NoSchedule(PrefectBaseModel):
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Literal, Optional
|
3
|
+
|
4
|
+
import httpx
|
5
|
+
|
6
|
+
from prefect._internal.compatibility.deprecated import deprecated_parameter
|
7
|
+
from prefect.client.orchestration import get_client
|
8
|
+
from prefect.client.schemas.responses import MinimalConcurrencyLimitResponse
|
9
|
+
from prefect.logging.loggers import get_run_logger
|
10
|
+
|
11
|
+
from .services import ConcurrencySlotAcquisitionService
|
12
|
+
|
13
|
+
|
14
|
+
class ConcurrencySlotAcquisitionError(Exception):
|
15
|
+
"""Raised when an unhandlable occurs while acquiring concurrency slots."""
|
16
|
+
|
17
|
+
|
18
|
+
class AcquireConcurrencySlotTimeoutError(TimeoutError):
|
19
|
+
"""Raised when acquiring a concurrency slot times out."""
|
20
|
+
|
21
|
+
|
22
|
+
@deprecated_parameter(
|
23
|
+
name="create_if_missing",
|
24
|
+
start_date="Sep 2024",
|
25
|
+
end_date="Oct 2024",
|
26
|
+
when=lambda x: x is not None,
|
27
|
+
help="Limits must be explicitly created before acquiring concurrency slots; see `strict` if you want to enforce this behavior.",
|
28
|
+
)
|
29
|
+
async def aacquire_concurrency_slots(
|
30
|
+
names: list[str],
|
31
|
+
slots: int,
|
32
|
+
mode: Literal["concurrency", "rate_limit"] = "concurrency",
|
33
|
+
timeout_seconds: Optional[float] = None,
|
34
|
+
create_if_missing: Optional[bool] = None,
|
35
|
+
max_retries: Optional[int] = None,
|
36
|
+
strict: bool = False,
|
37
|
+
) -> list[MinimalConcurrencyLimitResponse]:
|
38
|
+
service = ConcurrencySlotAcquisitionService.instance(frozenset(names))
|
39
|
+
future = service.send(
|
40
|
+
(slots, mode, timeout_seconds, create_if_missing, max_retries)
|
41
|
+
)
|
42
|
+
try:
|
43
|
+
response = await asyncio.wrap_future(future)
|
44
|
+
except TimeoutError as timeout:
|
45
|
+
raise AcquireConcurrencySlotTimeoutError(
|
46
|
+
f"Attempt to acquire concurrency slots timed out after {timeout_seconds} second(s)"
|
47
|
+
) from timeout
|
48
|
+
except Exception as exc:
|
49
|
+
raise ConcurrencySlotAcquisitionError(
|
50
|
+
f"Unable to acquire concurrency slots on {names!r}"
|
51
|
+
) from exc
|
52
|
+
|
53
|
+
retval = _response_to_minimal_concurrency_limit_response(response)
|
54
|
+
|
55
|
+
if not retval:
|
56
|
+
if strict:
|
57
|
+
raise ConcurrencySlotAcquisitionError(
|
58
|
+
f"Concurrency limits {names!r} must be created before acquiring slots"
|
59
|
+
)
|
60
|
+
try:
|
61
|
+
logger = get_run_logger()
|
62
|
+
except Exception:
|
63
|
+
pass
|
64
|
+
else:
|
65
|
+
logger.warning(
|
66
|
+
f"Concurrency limits {names!r} do not exist - skipping acquisition."
|
67
|
+
)
|
68
|
+
|
69
|
+
return retval
|
70
|
+
|
71
|
+
|
72
|
+
async def arelease_concurrency_slots(
|
73
|
+
names: list[str], slots: int, occupancy_seconds: float
|
74
|
+
) -> list[MinimalConcurrencyLimitResponse]:
|
75
|
+
async with get_client() as client:
|
76
|
+
response = await client.release_concurrency_slots(
|
77
|
+
names=names, slots=slots, occupancy_seconds=occupancy_seconds
|
78
|
+
)
|
79
|
+
return _response_to_minimal_concurrency_limit_response(response)
|
80
|
+
|
81
|
+
|
82
|
+
def _response_to_minimal_concurrency_limit_response(
|
83
|
+
response: httpx.Response,
|
84
|
+
) -> list[MinimalConcurrencyLimitResponse]:
|
85
|
+
return [
|
86
|
+
MinimalConcurrencyLimitResponse.model_validate(obj_) for obj_ in response.json()
|
87
|
+
]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Literal, Optional, Union
|
2
2
|
from uuid import UUID
|
3
3
|
|
4
4
|
from prefect.client.schemas.responses import MinimalConcurrencyLimitResponse
|
@@ -8,11 +8,11 @@ from prefect.events import Event, RelatedResource, emit_event
|
|
8
8
|
def _emit_concurrency_event(
|
9
9
|
phase: Union[Literal["acquired"], Literal["released"]],
|
10
10
|
primary_limit: MinimalConcurrencyLimitResponse,
|
11
|
-
related_limits:
|
11
|
+
related_limits: list[MinimalConcurrencyLimitResponse],
|
12
12
|
slots: int,
|
13
13
|
follows: Union[Event, None] = None,
|
14
14
|
) -> Union[Event, None]:
|
15
|
-
resource:
|
15
|
+
resource: dict[str, str] = {
|
16
16
|
"prefect.resource.id": f"prefect.concurrency-limit.{primary_limit.id}",
|
17
17
|
"prefect.resource.name": primary_limit.name,
|
18
18
|
"slots-acquired": str(slots),
|
@@ -38,11 +38,11 @@ def _emit_concurrency_event(
|
|
38
38
|
)
|
39
39
|
|
40
40
|
|
41
|
-
def
|
42
|
-
limits:
|
41
|
+
def emit_concurrency_acquisition_events(
|
42
|
+
limits: list[MinimalConcurrencyLimitResponse],
|
43
43
|
occupy: int,
|
44
|
-
) ->
|
45
|
-
events = {}
|
44
|
+
) -> dict[UUID, Optional[Event]]:
|
45
|
+
events: dict[UUID, Optional[Event]] = {}
|
46
46
|
for limit in limits:
|
47
47
|
event = _emit_concurrency_event("acquired", limit, limits, occupy)
|
48
48
|
events[limit.id] = event
|
@@ -50,10 +50,10 @@ def _emit_concurrency_acquisition_events(
|
|
50
50
|
return events
|
51
51
|
|
52
52
|
|
53
|
-
def
|
54
|
-
limits:
|
53
|
+
def emit_concurrency_release_events(
|
54
|
+
limits: list[MinimalConcurrencyLimitResponse],
|
55
55
|
occupy: int,
|
56
|
-
events:
|
56
|
+
events: dict[UUID, Optional[Event]],
|
57
57
|
) -> None:
|
58
58
|
for limit in limits:
|
59
59
|
_emit_concurrency_event("released", limit, limits, occupy, events[limit.id])
|