prefect-client 3.1.13__py3-none-any.whl → 3.1.15__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/__main__.py +4 -0
- prefect/_experimental/lineage.py +92 -11
- prefect/_internal/concurrency/services.py +1 -1
- prefect/_version.py +3 -3
- prefect/artifacts.py +408 -105
- prefect/blocks/core.py +1 -1
- prefect/blocks/notifications.py +5 -0
- prefect/cache_policies.py +50 -2
- prefect/client/orchestration/_automations/client.py +4 -0
- prefect/client/orchestration/_deployments/client.py +3 -3
- prefect/client/schemas/actions.py +11 -1
- prefect/client/schemas/schedules.py +4 -4
- prefect/context.py +16 -6
- prefect/deployments/base.py +13 -16
- prefect/deployments/runner.py +117 -4
- prefect/events/clients.py +39 -0
- prefect/events/filters.py +34 -34
- prefect/flow_engine.py +274 -114
- prefect/flows.py +253 -10
- prefect/logging/configuration.py +2 -5
- prefect/logging/loggers.py +1 -2
- prefect/runner/runner.py +79 -58
- prefect/runtime/task_run.py +37 -9
- prefect/tasks.py +45 -7
- prefect/types/__init__.py +6 -5
- prefect/types/_datetime.py +19 -0
- prefect/utilities/render_swagger.py +1 -1
- prefect/utilities/templating.py +7 -0
- {prefect_client-3.1.13.dist-info → prefect_client-3.1.15.dist-info}/METADATA +1 -1
- {prefect_client-3.1.13.dist-info → prefect_client-3.1.15.dist-info}/RECORD +33 -31
- {prefect_client-3.1.13.dist-info → prefect_client-3.1.15.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.13.dist-info → prefect_client-3.1.15.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.13.dist-info → prefect_client-3.1.15.dist-info}/top_level.txt +0 -0
prefect/flows.py
CHANGED
@@ -82,6 +82,7 @@ from prefect.types import BANNED_CHARACTERS, WITHOUT_BANNED_CHARACTERS
|
|
82
82
|
from prefect.types.entrypoint import EntrypointType
|
83
83
|
from prefect.utilities.annotations import NotSet
|
84
84
|
from prefect.utilities.asyncutils import (
|
85
|
+
run_coro_as_sync,
|
85
86
|
run_sync_in_worker_thread,
|
86
87
|
sync_compatible,
|
87
88
|
)
|
@@ -97,7 +98,7 @@ from prefect.utilities.filesystem import relative_path_to_current_platform
|
|
97
98
|
from prefect.utilities.hashing import file_hash
|
98
99
|
from prefect.utilities.importtools import import_object, safe_load_namespace
|
99
100
|
|
100
|
-
from ._internal.compatibility.async_dispatch import is_in_async_context
|
101
|
+
from ._internal.compatibility.async_dispatch import async_dispatch, is_in_async_context
|
101
102
|
from ._internal.pydantic.v2_schema import is_v2_type
|
102
103
|
from ._internal.pydantic.v2_validated_func import V2ValidatedFunction
|
103
104
|
from ._internal.pydantic.v2_validated_func import (
|
@@ -127,9 +128,9 @@ if TYPE_CHECKING:
|
|
127
128
|
import logging
|
128
129
|
|
129
130
|
from prefect.client.orchestration import PrefectClient
|
131
|
+
from prefect.client.schemas.objects import FlowRun
|
130
132
|
from prefect.client.types.flexible_schedule_list import FlexibleScheduleList
|
131
133
|
from prefect.deployments.runner import RunnerDeployment
|
132
|
-
from prefect.flows import FlowRun
|
133
134
|
from prefect.runner.storage import RunnerStorage
|
134
135
|
|
135
136
|
logger: "logging.Logger" = get_logger("flows")
|
@@ -654,8 +655,7 @@ class Flow(Generic[P, R]):
|
|
654
655
|
serialized_parameters[key] = f"<{type(value).__name__}>"
|
655
656
|
return serialized_parameters
|
656
657
|
|
657
|
-
|
658
|
-
async def to_deployment(
|
658
|
+
async def ato_deployment(
|
659
659
|
self,
|
660
660
|
name: str,
|
661
661
|
interval: Optional[
|
@@ -684,7 +684,7 @@ class Flow(Generic[P, R]):
|
|
684
684
|
_sla: Optional[Union[SlaTypes, list[SlaTypes]]] = None, # experimental
|
685
685
|
) -> "RunnerDeployment":
|
686
686
|
"""
|
687
|
-
|
687
|
+
Asynchronously creates a runner deployment object for this flow.
|
688
688
|
|
689
689
|
Args:
|
690
690
|
name: The name to give the created deployment.
|
@@ -740,7 +740,7 @@ class Flow(Generic[P, R]):
|
|
740
740
|
_raise_on_name_with_banned_characters(name)
|
741
741
|
|
742
742
|
if self._storage and self._entrypoint:
|
743
|
-
return await RunnerDeployment.
|
743
|
+
return await RunnerDeployment.afrom_storage(
|
744
744
|
storage=self._storage,
|
745
745
|
entrypoint=self._entrypoint,
|
746
746
|
name=name,
|
@@ -761,7 +761,142 @@ class Flow(Generic[P, R]):
|
|
761
761
|
work_queue_name=work_queue_name,
|
762
762
|
job_variables=job_variables,
|
763
763
|
_sla=_sla,
|
764
|
-
)
|
764
|
+
)
|
765
|
+
else:
|
766
|
+
return RunnerDeployment.from_flow(
|
767
|
+
flow=self,
|
768
|
+
name=name,
|
769
|
+
interval=interval,
|
770
|
+
cron=cron,
|
771
|
+
rrule=rrule,
|
772
|
+
paused=paused,
|
773
|
+
schedules=schedules,
|
774
|
+
concurrency_limit=concurrency_limit,
|
775
|
+
tags=tags,
|
776
|
+
triggers=triggers,
|
777
|
+
parameters=parameters or {},
|
778
|
+
description=description,
|
779
|
+
version=version,
|
780
|
+
enforce_parameter_schema=enforce_parameter_schema,
|
781
|
+
work_pool_name=work_pool_name,
|
782
|
+
work_queue_name=work_queue_name,
|
783
|
+
job_variables=job_variables,
|
784
|
+
entrypoint_type=entrypoint_type,
|
785
|
+
_sla=_sla,
|
786
|
+
)
|
787
|
+
|
788
|
+
@async_dispatch(ato_deployment)
|
789
|
+
def to_deployment(
|
790
|
+
self,
|
791
|
+
name: str,
|
792
|
+
interval: Optional[
|
793
|
+
Union[
|
794
|
+
Iterable[Union[int, float, datetime.timedelta]],
|
795
|
+
int,
|
796
|
+
float,
|
797
|
+
datetime.timedelta,
|
798
|
+
]
|
799
|
+
] = None,
|
800
|
+
cron: Optional[Union[Iterable[str], str]] = None,
|
801
|
+
rrule: Optional[Union[Iterable[str], str]] = None,
|
802
|
+
paused: Optional[bool] = None,
|
803
|
+
schedules: Optional["FlexibleScheduleList"] = None,
|
804
|
+
concurrency_limit: Optional[Union[int, ConcurrencyLimitConfig, None]] = None,
|
805
|
+
parameters: Optional[dict[str, Any]] = None,
|
806
|
+
triggers: Optional[list[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
807
|
+
description: Optional[str] = None,
|
808
|
+
tags: Optional[list[str]] = None,
|
809
|
+
version: Optional[str] = None,
|
810
|
+
enforce_parameter_schema: bool = True,
|
811
|
+
work_pool_name: Optional[str] = None,
|
812
|
+
work_queue_name: Optional[str] = None,
|
813
|
+
job_variables: Optional[dict[str, Any]] = None,
|
814
|
+
entrypoint_type: EntrypointType = EntrypointType.FILE_PATH,
|
815
|
+
_sla: Optional[Union[SlaTypes, list[SlaTypes]]] = None, # experimental
|
816
|
+
) -> "RunnerDeployment":
|
817
|
+
"""
|
818
|
+
Creates a runner deployment object for this flow.
|
819
|
+
|
820
|
+
Args:
|
821
|
+
name: The name to give the created deployment.
|
822
|
+
interval: An interval on which to execute the new deployment. Accepts either a number
|
823
|
+
or a timedelta object. If a number is given, it will be interpreted as seconds.
|
824
|
+
cron: A cron schedule of when to execute runs of this deployment.
|
825
|
+
rrule: An rrule schedule of when to execute runs of this deployment.
|
826
|
+
paused: Whether or not to set this deployment as paused.
|
827
|
+
schedules: A list of schedule objects defining when to execute runs of this deployment.
|
828
|
+
Used to define multiple schedules or additional scheduling options such as `timezone`.
|
829
|
+
concurrency_limit: The maximum number of runs of this deployment that can run at the same time.
|
830
|
+
parameters: A dictionary of default parameter values to pass to runs of this deployment.
|
831
|
+
triggers: A list of triggers that will kick off runs of this deployment.
|
832
|
+
description: A description for the created deployment. Defaults to the flow's
|
833
|
+
description if not provided.
|
834
|
+
tags: A list of tags to associate with the created deployment for organizational
|
835
|
+
purposes.
|
836
|
+
version: A version for the created deployment. Defaults to the flow's version.
|
837
|
+
enforce_parameter_schema: Whether or not the Prefect API should enforce the
|
838
|
+
parameter schema for the created deployment.
|
839
|
+
work_pool_name: The name of the work pool to use for this deployment.
|
840
|
+
work_queue_name: The name of the work queue to use for this deployment's scheduled runs.
|
841
|
+
If not provided the default work queue for the work pool will be used.
|
842
|
+
job_variables: Settings used to override the values specified default base job template
|
843
|
+
of the chosen work pool. Refer to the base job template of the chosen work pool for
|
844
|
+
entrypoint_type: Type of entrypoint to use for the deployment. When using a module path
|
845
|
+
entrypoint, ensure that the module will be importable in the execution environment.
|
846
|
+
_sla: (Experimental) SLA configuration for the deployment. May be removed or modified at any time. Currently only supported on Prefect Cloud.
|
847
|
+
|
848
|
+
Examples:
|
849
|
+
Prepare two deployments and serve them:
|
850
|
+
|
851
|
+
```python
|
852
|
+
from prefect import flow, serve
|
853
|
+
|
854
|
+
@flow
|
855
|
+
def my_flow(name):
|
856
|
+
print(f"hello {name}")
|
857
|
+
|
858
|
+
@flow
|
859
|
+
def my_other_flow(name):
|
860
|
+
print(f"goodbye {name}")
|
861
|
+
|
862
|
+
if __name__ == "__main__":
|
863
|
+
hello_deploy = my_flow.to_deployment("hello", tags=["dev"])
|
864
|
+
bye_deploy = my_other_flow.to_deployment("goodbye", tags=["dev"])
|
865
|
+
serve(hello_deploy, bye_deploy)
|
866
|
+
```
|
867
|
+
"""
|
868
|
+
from prefect.deployments.runner import RunnerDeployment
|
869
|
+
|
870
|
+
if not name.endswith(".py"):
|
871
|
+
_raise_on_name_with_banned_characters(name)
|
872
|
+
|
873
|
+
if self._storage and self._entrypoint:
|
874
|
+
return cast(
|
875
|
+
RunnerDeployment,
|
876
|
+
RunnerDeployment.from_storage(
|
877
|
+
storage=self._storage,
|
878
|
+
entrypoint=self._entrypoint,
|
879
|
+
name=name,
|
880
|
+
flow_name=self.name,
|
881
|
+
interval=interval,
|
882
|
+
cron=cron,
|
883
|
+
rrule=rrule,
|
884
|
+
paused=paused,
|
885
|
+
schedules=schedules,
|
886
|
+
concurrency_limit=concurrency_limit,
|
887
|
+
tags=tags,
|
888
|
+
triggers=triggers,
|
889
|
+
parameters=parameters or {},
|
890
|
+
description=description,
|
891
|
+
version=version,
|
892
|
+
enforce_parameter_schema=enforce_parameter_schema,
|
893
|
+
work_pool_name=work_pool_name,
|
894
|
+
work_queue_name=work_queue_name,
|
895
|
+
job_variables=job_variables,
|
896
|
+
_sla=_sla,
|
897
|
+
_sync=True, # pyright: ignore[reportCallIssue] _sync is valid because .from_storage is decorated with async_dispatch
|
898
|
+
),
|
899
|
+
)
|
765
900
|
else:
|
766
901
|
return RunnerDeployment.from_flow(
|
767
902
|
flow=self,
|
@@ -957,14 +1092,13 @@ class Flow(Generic[P, R]):
|
|
957
1092
|
loop.stop()
|
958
1093
|
|
959
1094
|
@classmethod
|
960
|
-
|
961
|
-
async def from_source(
|
1095
|
+
async def afrom_source(
|
962
1096
|
cls,
|
963
1097
|
source: Union[str, "RunnerStorage", ReadableDeploymentStorage],
|
964
1098
|
entrypoint: str,
|
965
1099
|
) -> "Flow[..., Any]":
|
966
1100
|
"""
|
967
|
-
Loads a flow from a remote source.
|
1101
|
+
Loads a flow from a remote source asynchronously.
|
968
1102
|
|
969
1103
|
Args:
|
970
1104
|
source: Either a URL to a git repository or a storage object.
|
@@ -1070,6 +1204,115 @@ class Flow(Generic[P, R]):
|
|
1070
1204
|
|
1071
1205
|
return flow
|
1072
1206
|
|
1207
|
+
@classmethod
|
1208
|
+
@async_dispatch(afrom_source)
|
1209
|
+
def from_source(
|
1210
|
+
cls,
|
1211
|
+
source: Union[str, "RunnerStorage", ReadableDeploymentStorage],
|
1212
|
+
entrypoint: str,
|
1213
|
+
) -> "Flow[..., Any]":
|
1214
|
+
"""
|
1215
|
+
Loads a flow from a remote source.
|
1216
|
+
|
1217
|
+
Args:
|
1218
|
+
source: Either a URL to a git repository or a storage object.
|
1219
|
+
entrypoint: The path to a file containing a flow and the name of the flow function in
|
1220
|
+
the format `./path/to/file.py:flow_func_name`.
|
1221
|
+
|
1222
|
+
Returns:
|
1223
|
+
A new `Flow` instance.
|
1224
|
+
|
1225
|
+
Examples:
|
1226
|
+
Load a flow from a public git repository:
|
1227
|
+
|
1228
|
+
|
1229
|
+
```python
|
1230
|
+
from prefect import flow
|
1231
|
+
from prefect.runner.storage import GitRepository
|
1232
|
+
from prefect.blocks.system import Secret
|
1233
|
+
|
1234
|
+
my_flow = flow.from_source(
|
1235
|
+
source="https://github.com/org/repo.git",
|
1236
|
+
entrypoint="flows.py:my_flow",
|
1237
|
+
)
|
1238
|
+
|
1239
|
+
my_flow()
|
1240
|
+
```
|
1241
|
+
|
1242
|
+
Load a flow from a private git repository using an access token stored in a `Secret` block:
|
1243
|
+
|
1244
|
+
```python
|
1245
|
+
from prefect import flow
|
1246
|
+
from prefect.runner.storage import GitRepository
|
1247
|
+
from prefect.blocks.system import Secret
|
1248
|
+
|
1249
|
+
my_flow = flow.from_source(
|
1250
|
+
source=GitRepository(
|
1251
|
+
url="https://github.com/org/repo.git",
|
1252
|
+
credentials={"access_token": Secret.load("github-access-token")}
|
1253
|
+
),
|
1254
|
+
entrypoint="flows.py:my_flow",
|
1255
|
+
)
|
1256
|
+
|
1257
|
+
my_flow()
|
1258
|
+
```
|
1259
|
+
|
1260
|
+
Load a flow from a local directory:
|
1261
|
+
|
1262
|
+
``` python
|
1263
|
+
# from_local_source.py
|
1264
|
+
|
1265
|
+
from pathlib import Path
|
1266
|
+
from prefect import flow
|
1267
|
+
|
1268
|
+
@flow(log_prints=True)
|
1269
|
+
def my_flow(name: str = "world"):
|
1270
|
+
print(f"Hello {name}! I'm a flow from a Python script!")
|
1271
|
+
|
1272
|
+
if __name__ == "__main__":
|
1273
|
+
my_flow.from_source(
|
1274
|
+
source=str(Path(__file__).parent),
|
1275
|
+
entrypoint="from_local_source.py:my_flow",
|
1276
|
+
).deploy(
|
1277
|
+
name="my-deployment",
|
1278
|
+
parameters=dict(name="Marvin"),
|
1279
|
+
work_pool_name="local",
|
1280
|
+
)
|
1281
|
+
```
|
1282
|
+
"""
|
1283
|
+
|
1284
|
+
from prefect.runner.storage import (
|
1285
|
+
BlockStorageAdapter,
|
1286
|
+
LocalStorage,
|
1287
|
+
RunnerStorage,
|
1288
|
+
create_storage_from_source,
|
1289
|
+
)
|
1290
|
+
|
1291
|
+
if isinstance(source, (Path, str)):
|
1292
|
+
if isinstance(source, Path):
|
1293
|
+
source = str(source)
|
1294
|
+
storage = create_storage_from_source(source)
|
1295
|
+
elif isinstance(source, RunnerStorage):
|
1296
|
+
storage = source
|
1297
|
+
elif hasattr(source, "get_directory"):
|
1298
|
+
storage = BlockStorageAdapter(source)
|
1299
|
+
else:
|
1300
|
+
raise TypeError(
|
1301
|
+
f"Unsupported source type {type(source).__name__!r}. Please provide a"
|
1302
|
+
" URL to remote storage or a storage object."
|
1303
|
+
)
|
1304
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
1305
|
+
if not isinstance(storage, LocalStorage):
|
1306
|
+
storage.set_base_path(Path(tmpdir))
|
1307
|
+
run_coro_as_sync(storage.pull_code())
|
1308
|
+
|
1309
|
+
full_entrypoint = str(storage.destination / entrypoint)
|
1310
|
+
flow = load_flow_from_entrypoint(full_entrypoint)
|
1311
|
+
flow._storage = storage
|
1312
|
+
flow._entrypoint = entrypoint
|
1313
|
+
|
1314
|
+
return flow
|
1315
|
+
|
1073
1316
|
@sync_compatible
|
1074
1317
|
async def deploy(
|
1075
1318
|
self,
|
prefect/logging/configuration.py
CHANGED
@@ -94,12 +94,9 @@ def setup_logging(incremental: Optional[bool] = None) -> dict[str, Any]:
|
|
94
94
|
|
95
95
|
for logger_name in PREFECT_LOGGING_EXTRA_LOGGERS.value():
|
96
96
|
logger = logging.getLogger(logger_name)
|
97
|
-
|
98
|
-
|
97
|
+
if not config["incremental"]:
|
98
|
+
for handler in extra_config.handlers:
|
99
99
|
logger.addHandler(handler)
|
100
|
-
if logger.level == logging.NOTSET:
|
101
|
-
logger.setLevel(extra_config.level)
|
102
|
-
logger.propagate = extra_config.propagate
|
103
100
|
|
104
101
|
PROCESS_LOGGING_CONFIG = config
|
105
102
|
|
prefect/logging/loggers.py
CHANGED
@@ -24,7 +24,6 @@ else:
|
|
24
24
|
LoggingAdapter = logging.LoggerAdapter
|
25
25
|
|
26
26
|
if TYPE_CHECKING:
|
27
|
-
from prefect.client.schemas import FlowRun as ClientFlowRun
|
28
27
|
from prefect.client.schemas.objects import FlowRun, TaskRun
|
29
28
|
from prefect.context import RunContext
|
30
29
|
from prefect.flows import Flow
|
@@ -164,7 +163,7 @@ def get_run_logger(
|
|
164
163
|
|
165
164
|
|
166
165
|
def flow_run_logger(
|
167
|
-
flow_run:
|
166
|
+
flow_run: "FlowRun",
|
168
167
|
flow: Optional["Flow[Any, Any]"] = None,
|
169
168
|
**kwargs: str,
|
170
169
|
) -> PrefectLogAdapter:
|