prefect-client 3.0.0rc19__py3-none-any.whl → 3.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- prefect/__init__.py +0 -3
- prefect/_internal/compatibility/migration.py +1 -1
- prefect/artifacts.py +1 -1
- prefect/blocks/core.py +8 -5
- prefect/blocks/notifications.py +10 -10
- prefect/blocks/system.py +52 -16
- prefect/blocks/webhook.py +3 -1
- prefect/client/cloud.py +57 -7
- prefect/client/collections.py +1 -1
- prefect/client/orchestration.py +68 -7
- prefect/client/schemas/objects.py +40 -2
- prefect/concurrency/asyncio.py +8 -2
- prefect/concurrency/services.py +16 -6
- prefect/concurrency/sync.py +4 -1
- prefect/context.py +7 -9
- prefect/deployments/runner.py +3 -3
- prefect/exceptions.py +12 -0
- prefect/filesystems.py +5 -3
- prefect/flow_engine.py +16 -10
- prefect/flows.py +2 -4
- prefect/futures.py +2 -1
- prefect/locking/__init__.py +0 -0
- prefect/locking/memory.py +213 -0
- prefect/locking/protocol.py +122 -0
- prefect/logging/handlers.py +4 -1
- prefect/main.py +8 -6
- prefect/records/filesystem.py +4 -2
- prefect/records/result_store.py +12 -6
- prefect/results.py +768 -363
- prefect/settings.py +24 -10
- prefect/states.py +82 -27
- prefect/task_engine.py +51 -26
- prefect/task_worker.py +6 -4
- prefect/tasks.py +24 -6
- prefect/transactions.py +57 -36
- prefect/utilities/annotations.py +4 -3
- prefect/utilities/asyncutils.py +1 -1
- prefect/utilities/callables.py +1 -3
- prefect/utilities/dispatch.py +16 -11
- prefect/utilities/schema_tools/hydration.py +13 -0
- prefect/variables.py +34 -24
- prefect/workers/base.py +78 -18
- prefect/workers/process.py +1 -3
- {prefect_client-3.0.0rc19.dist-info → prefect_client-3.0.1.dist-info}/METADATA +2 -2
- {prefect_client-3.0.0rc19.dist-info → prefect_client-3.0.1.dist-info}/RECORD +48 -46
- prefect/manifests.py +0 -21
- {prefect_client-3.0.0rc19.dist-info → prefect_client-3.0.1.dist-info}/LICENSE +0 -0
- {prefect_client-3.0.0rc19.dist-info → prefect_client-3.0.1.dist-info}/WHEEL +0 -0
- {prefect_client-3.0.0rc19.dist-info → prefect_client-3.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
from typing import Optional, Protocol, runtime_checkable
|
2
|
+
|
3
|
+
|
4
|
+
@runtime_checkable
|
5
|
+
class LockManager(Protocol):
|
6
|
+
def acquire_lock(
|
7
|
+
self,
|
8
|
+
key: str,
|
9
|
+
holder: str,
|
10
|
+
acquire_timeout: Optional[float] = None,
|
11
|
+
hold_timeout: Optional[float] = None,
|
12
|
+
) -> bool:
|
13
|
+
"""
|
14
|
+
Acquire a lock for a transaction record with the given key. Will block other
|
15
|
+
actors from updating this transaction record until the lock is
|
16
|
+
released.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
key: Unique identifier for the transaction record.
|
20
|
+
holder: Unique identifier for the holder of the lock.
|
21
|
+
acquire_timeout: Max number of seconds to wait for the record to become
|
22
|
+
available if it is locked while attempting to acquire a lock. Pass 0
|
23
|
+
to attempt to acquire a lock without waiting. Blocks indefinitely by
|
24
|
+
default.
|
25
|
+
hold_timeout: Max number of seconds to hold the lock for. Holds the lock
|
26
|
+
indefinitely by default.
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
bool: True if the lock was successfully acquired; False otherwise.
|
30
|
+
"""
|
31
|
+
...
|
32
|
+
|
33
|
+
async def aacquire_lock(
|
34
|
+
self,
|
35
|
+
key: str,
|
36
|
+
holder: str,
|
37
|
+
acquire_timeout: Optional[float] = None,
|
38
|
+
hold_timeout: Optional[float] = None,
|
39
|
+
) -> bool:
|
40
|
+
"""
|
41
|
+
Acquire a lock for a transaction record with the given key. Will block other
|
42
|
+
actors from updating this transaction record until the lock is
|
43
|
+
released.
|
44
|
+
|
45
|
+
Args:
|
46
|
+
key: Unique identifier for the transaction record.
|
47
|
+
holder: Unique identifier for the holder of the lock.
|
48
|
+
acquire_timeout: Max number of seconds to wait for the record to become
|
49
|
+
available if it is locked while attempting to acquire a lock. Pass 0
|
50
|
+
to attempt to acquire a lock without waiting. Blocks indefinitely by
|
51
|
+
default.
|
52
|
+
hold_timeout: Max number of seconds to hold the lock for. Holds the lock
|
53
|
+
indefinitely by default.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
bool: True if the lock was successfully acquired; False otherwise.
|
57
|
+
"""
|
58
|
+
...
|
59
|
+
|
60
|
+
def release_lock(self, key: str, holder: str):
|
61
|
+
"""
|
62
|
+
Releases the lock on the corresponding transaction record.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
key: Unique identifier for the transaction record.
|
66
|
+
holder: Unique identifier for the holder of the lock. Must match the
|
67
|
+
holder provided when acquiring the lock.
|
68
|
+
"""
|
69
|
+
...
|
70
|
+
|
71
|
+
def is_locked(self, key: str) -> bool:
|
72
|
+
"""
|
73
|
+
Simple check to see if the corresponding record is currently locked.
|
74
|
+
|
75
|
+
Args:
|
76
|
+
key: Unique identifier for the transaction record.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
True is the record is locked; False otherwise.
|
80
|
+
"""
|
81
|
+
...
|
82
|
+
|
83
|
+
def is_lock_holder(self, key: str, holder: str) -> bool:
|
84
|
+
"""
|
85
|
+
Check if the current holder is the lock holder for the transaction record.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
key: Unique identifier for the transaction record.
|
89
|
+
holder: Unique identifier for the holder of the lock.
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
bool: True if the current holder is the lock holder; False otherwise.
|
93
|
+
"""
|
94
|
+
...
|
95
|
+
|
96
|
+
def wait_for_lock(self, key: str, timeout: Optional[float] = None) -> bool:
|
97
|
+
"""
|
98
|
+
Wait for the corresponding transaction record to become free.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
key: Unique identifier for the transaction record.
|
102
|
+
timeout: Maximum time to wait. None means to wait indefinitely.
|
103
|
+
|
104
|
+
Returns:
|
105
|
+
bool: True if the lock becomes free within the timeout; False
|
106
|
+
otherwise.
|
107
|
+
"""
|
108
|
+
...
|
109
|
+
|
110
|
+
async def await_for_lock(self, key: str, timeout: Optional[float] = None) -> bool:
|
111
|
+
"""
|
112
|
+
Wait for the corresponding transaction record to become free.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
key: Unique identifier for the transaction record.
|
116
|
+
timeout: Maximum time to wait. None means to wait indefinitely.
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
bool: True if the lock becomes free within the timeout; False
|
120
|
+
otherwise.
|
121
|
+
"""
|
122
|
+
...
|
prefect/logging/handlers.py
CHANGED
@@ -157,7 +157,10 @@ class APILogHandler(logging.Handler):
|
|
157
157
|
if log_handling_when_missing_flow == "warn":
|
158
158
|
# Warn when a logger is used outside of a run context, the stack level here
|
159
159
|
# gets us to the user logging call
|
160
|
-
warnings.warn(
|
160
|
+
warnings.warn(
|
161
|
+
f"{exc} Set PREFECT_LOGGING_TO_API_WHEN_MISSING_FLOW=ignore to suppress this warning.",
|
162
|
+
stacklevel=8,
|
163
|
+
)
|
161
164
|
return
|
162
165
|
elif log_handling_when_missing_flow == "ignore":
|
163
166
|
return
|
prefect/main.py
CHANGED
@@ -6,7 +6,6 @@ from prefect.flows import flow, Flow, serve
|
|
6
6
|
from prefect.transactions import Transaction
|
7
7
|
from prefect.tasks import task, Task
|
8
8
|
from prefect.context import tags
|
9
|
-
from prefect.manifests import Manifest
|
10
9
|
from prefect.utilities.annotations import unmapped, allow_failure
|
11
10
|
from prefect.results import BaseResult
|
12
11
|
from prefect.flow_runs import pause_flow_run, resume_flow_run, suspend_flow_run
|
@@ -26,10 +25,14 @@ import prefect.context
|
|
26
25
|
# Perform any forward-ref updates needed for Pydantic models
|
27
26
|
import prefect.client.schemas
|
28
27
|
|
29
|
-
prefect.context.FlowRunContext.model_rebuild(
|
30
|
-
|
31
|
-
|
32
|
-
prefect.
|
28
|
+
prefect.context.FlowRunContext.model_rebuild(
|
29
|
+
_types_namespace={"Flow": Flow, "BaseResult": BaseResult}
|
30
|
+
)
|
31
|
+
prefect.context.TaskRunContext.model_rebuild(_types_namespace={"Task": Task})
|
32
|
+
prefect.client.schemas.State.model_rebuild(_types_namespace={"BaseResult": BaseResult})
|
33
|
+
prefect.client.schemas.StateCreate.model_rebuild(
|
34
|
+
_types_namespace={"BaseResult": BaseResult}
|
35
|
+
)
|
33
36
|
Transaction.model_rebuild()
|
34
37
|
|
35
38
|
# Configure logging
|
@@ -55,7 +58,6 @@ __all__ = [
|
|
55
58
|
"Flow",
|
56
59
|
"get_client",
|
57
60
|
"get_run_logger",
|
58
|
-
"Manifest",
|
59
61
|
"State",
|
60
62
|
"tags",
|
61
63
|
"task",
|
prefect/records/filesystem.py
CHANGED
@@ -76,7 +76,7 @@ class FileSystemRecordStore(RecordStore):
|
|
76
76
|
return None
|
77
77
|
|
78
78
|
def read(
|
79
|
-
self, key: str, holder: Optional[str] = None
|
79
|
+
self, key: str, holder: Optional[str] = None, timeout: Optional[float] = None
|
80
80
|
) -> Optional[TransactionRecord]:
|
81
81
|
if not self.exists(key):
|
82
82
|
return None
|
@@ -84,7 +84,9 @@ class FileSystemRecordStore(RecordStore):
|
|
84
84
|
holder = holder or self.generate_default_holder()
|
85
85
|
|
86
86
|
if self.is_locked(key) and not self.is_lock_holder(key, holder):
|
87
|
-
self.wait_for_lock(key)
|
87
|
+
unlocked = self.wait_for_lock(key, timeout=timeout)
|
88
|
+
if not unlocked:
|
89
|
+
return None
|
88
90
|
record_data = self.records_directory.joinpath(key).read_text()
|
89
91
|
return TransactionRecord(
|
90
92
|
key=key, result=BaseResult.model_validate_json(record_data)
|
prefect/records/result_store.py
CHANGED
@@ -3,7 +3,7 @@ from typing import Any, Optional
|
|
3
3
|
|
4
4
|
import pendulum
|
5
5
|
|
6
|
-
from prefect.results import BaseResult, PersistedResult,
|
6
|
+
from prefect.results import BaseResult, PersistedResult, ResultStore
|
7
7
|
from prefect.transactions import IsolationLevel
|
8
8
|
from prefect.utilities.asyncutils import run_coro_as_sync
|
9
9
|
|
@@ -11,8 +11,14 @@ from .base import RecordStore, TransactionRecord
|
|
11
11
|
|
12
12
|
|
13
13
|
@dataclass
|
14
|
-
class
|
15
|
-
|
14
|
+
class ResultRecordStore(RecordStore):
|
15
|
+
"""
|
16
|
+
A record store for result records.
|
17
|
+
|
18
|
+
Collocates result metadata with result data.
|
19
|
+
"""
|
20
|
+
|
21
|
+
result_store: ResultStore
|
16
22
|
cache: Optional[PersistedResult] = None
|
17
23
|
|
18
24
|
def exists(self, key: str) -> bool:
|
@@ -38,8 +44,8 @@ class ResultFactoryStore(RecordStore):
|
|
38
44
|
return TransactionRecord(key=key, result=self.cache)
|
39
45
|
try:
|
40
46
|
result = PersistedResult(
|
41
|
-
serializer_type=self.
|
42
|
-
storage_block_id=self.
|
47
|
+
serializer_type=self.result_store.serializer.type,
|
48
|
+
storage_block_id=self.result_store.result_storage_block_id,
|
43
49
|
storage_key=key,
|
44
50
|
)
|
45
51
|
return TransactionRecord(key=key, result=result)
|
@@ -52,7 +58,7 @@ class ResultFactoryStore(RecordStore):
|
|
52
58
|
# if the value is already a persisted result, write it
|
53
59
|
result.write(_sync=True)
|
54
60
|
elif not isinstance(result, BaseResult):
|
55
|
-
run_coro_as_sync(self.
|
61
|
+
run_coro_as_sync(self.result_store.create_result(obj=result, key=key))
|
56
62
|
|
57
63
|
def supports_isolation_level(self, isolation_level: IsolationLevel) -> bool:
|
58
64
|
return isolation_level == IsolationLevel.READ_COMMITTED
|