prefect-client 3.1.9__py3-none-any.whl → 3.1.11__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/_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/artifacts.py +61 -74
- prefect/automations.py +27 -7
- prefect/blocks/core.py +3 -3
- prefect/client/{orchestration.py → orchestration/__init__.py} +38 -701
- prefect/client/orchestration/_artifacts/__init__.py +0 -0
- prefect/client/orchestration/_artifacts/client.py +239 -0
- prefect/client/orchestration/_concurrency_limits/__init__.py +0 -0
- prefect/client/orchestration/_concurrency_limits/client.py +762 -0
- prefect/client/orchestration/_logs/__init__.py +0 -0
- prefect/client/orchestration/_logs/client.py +95 -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/actions.py +2 -2
- prefect/client/schemas/filters.py +5 -0
- prefect/client/schemas/objects.py +3 -10
- 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 -70
- prefect/deployments/base.py +4 -144
- prefect/deployments/flow_runs.py +12 -2
- prefect/deployments/runner.py +11 -3
- prefect/deployments/steps/pull.py +13 -0
- prefect/events/clients.py +7 -1
- prefect/events/schemas/events.py +3 -2
- prefect/flow_engine.py +54 -47
- prefect/flows.py +2 -1
- prefect/futures.py +42 -27
- prefect/input/run_input.py +2 -1
- prefect/locking/filesystem.py +8 -7
- prefect/locking/memory.py +5 -3
- prefect/locking/protocol.py +1 -1
- prefect/main.py +1 -3
- prefect/plugins.py +12 -10
- prefect/results.py +3 -308
- 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 +3 -3
- prefect/settings/models/deployments.py +3 -3
- prefect/settings/models/experiments.py +4 -2
- 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 +4 -7
- prefect/task_engine.py +54 -75
- prefect/tasks.py +84 -32
- prefect/telemetry/processors.py +6 -6
- prefect/telemetry/run_telemetry.py +13 -8
- prefect/telemetry/services.py +32 -31
- 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/workers/__init__.py +2 -0
- {prefect_client-3.1.9.dist-info → prefect_client-3.1.11.dist-info}/METADATA +1 -1
- {prefect_client-3.1.9.dist-info → prefect_client-3.1.11.dist-info}/RECORD +108 -99
- 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.9.dist-info → prefect_client-3.1.11.dist-info}/LICENSE +0 -0
- {prefect_client-3.1.9.dist-info → prefect_client-3.1.11.dist-info}/WHEEL +0 -0
- {prefect_client-3.1.9.dist-info → prefect_client-3.1.11.dist-info}/top_level.txt +0 -0
prefect/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "
|
11
|
+
"date": "2025-01-02T13:11:17-0600",
|
12
12
|
"dirty": true,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "3.1.
|
14
|
+
"full-revisionid": "e448bd3462d7c2580427624f426d81cf6e9a7ff1",
|
15
|
+
"version": "3.1.11"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
prefect/artifacts.py
CHANGED
@@ -2,19 +2,20 @@
|
|
2
2
|
Interface for creating and reading artifacts.
|
3
3
|
"""
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
import asyncio
|
7
6
|
import json # noqa: I001
|
8
7
|
import math
|
9
8
|
import warnings
|
10
|
-
from typing import TYPE_CHECKING, Any,
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
11
10
|
from uuid import UUID
|
12
11
|
|
12
|
+
from typing_extensions import Self
|
13
|
+
|
13
14
|
from prefect.client.schemas.actions import ArtifactCreate as ArtifactRequest
|
14
15
|
from prefect.client.schemas.actions import ArtifactUpdate
|
15
16
|
from prefect.client.schemas.filters import ArtifactFilter, ArtifactFilterKey
|
16
17
|
from prefect.client.schemas.sorting import ArtifactSort
|
17
|
-
from prefect.client.utilities import get_or_create_client
|
18
|
+
from prefect.client.utilities import get_or_create_client
|
18
19
|
from prefect.logging.loggers import get_logger
|
19
20
|
from prefect.utilities.asyncutils import sync_compatible
|
20
21
|
from prefect.utilities.context import get_task_and_flow_run_ids
|
@@ -22,8 +23,6 @@ from prefect.utilities.context import get_task_and_flow_run_ids
|
|
22
23
|
logger = get_logger("artifacts")
|
23
24
|
|
24
25
|
if TYPE_CHECKING:
|
25
|
-
from typing_extensions import Self
|
26
|
-
|
27
26
|
from prefect.client.orchestration import PrefectClient
|
28
27
|
from prefect.client.schemas.objects import Artifact as ArtifactResponse
|
29
28
|
|
@@ -43,7 +42,7 @@ class Artifact(ArtifactRequest):
|
|
43
42
|
|
44
43
|
@sync_compatible
|
45
44
|
async def create(
|
46
|
-
self:
|
45
|
+
self: Self,
|
47
46
|
client: Optional["PrefectClient"] = None,
|
48
47
|
) -> "ArtifactResponse":
|
49
48
|
"""
|
@@ -95,16 +94,15 @@ class Artifact(ArtifactRequest):
|
|
95
94
|
(ArtifactResponse, optional): The artifact (if found).
|
96
95
|
"""
|
97
96
|
client, _ = get_or_create_client(client)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
)
|
97
|
+
filter_key_value = None if key is None else [key]
|
98
|
+
artifacts = await client.read_artifacts(
|
99
|
+
limit=1,
|
100
|
+
sort=ArtifactSort.UPDATED_DESC,
|
101
|
+
artifact_filter=ArtifactFilter(
|
102
|
+
key=ArtifactFilterKey(any_=filter_key_value)
|
105
103
|
),
|
106
|
-
None,
|
107
104
|
)
|
105
|
+
return None if not artifacts else artifacts[0]
|
108
106
|
|
109
107
|
@classmethod
|
110
108
|
@sync_compatible
|
@@ -112,10 +110,10 @@ class Artifact(ArtifactRequest):
|
|
112
110
|
cls,
|
113
111
|
key: Optional[str] = None,
|
114
112
|
description: Optional[str] = None,
|
115
|
-
data: Optional[Union[
|
113
|
+
data: Optional[Union[dict[str, Any], Any]] = None,
|
116
114
|
client: Optional["PrefectClient"] = None,
|
117
115
|
**kwargs: Any,
|
118
|
-
) ->
|
116
|
+
) -> tuple["ArtifactResponse", bool]:
|
119
117
|
"""
|
120
118
|
A method to get or create an artifact.
|
121
119
|
|
@@ -128,18 +126,20 @@ class Artifact(ArtifactRequest):
|
|
128
126
|
Returns:
|
129
127
|
(ArtifactResponse): The artifact, either retrieved or created.
|
130
128
|
"""
|
131
|
-
|
129
|
+
artifact_coro = cls.get(key, client)
|
130
|
+
if TYPE_CHECKING:
|
131
|
+
assert asyncio.iscoroutine(artifact_coro)
|
132
|
+
artifact = await artifact_coro
|
132
133
|
if artifact:
|
133
134
|
return artifact, False
|
134
|
-
else:
|
135
|
-
return (
|
136
|
-
await cls(key=key, description=description, data=data, **kwargs).create(
|
137
|
-
client
|
138
|
-
),
|
139
|
-
True,
|
140
|
-
)
|
141
135
|
|
142
|
-
|
136
|
+
new_artifact = cls(key=key, description=description, data=data, **kwargs)
|
137
|
+
create_coro = new_artifact.create(client)
|
138
|
+
if TYPE_CHECKING:
|
139
|
+
assert asyncio.iscoroutine(create_coro)
|
140
|
+
return await create_coro, True
|
141
|
+
|
142
|
+
async def format(self) -> Optional[Union[dict[str, Any], Any]]:
|
143
143
|
return json.dumps(self.data)
|
144
144
|
|
145
145
|
|
@@ -165,13 +165,13 @@ class MarkdownArtifact(Artifact):
|
|
165
165
|
|
166
166
|
|
167
167
|
class TableArtifact(Artifact):
|
168
|
-
table: Union[
|
168
|
+
table: Union[dict[str, list[Any]], list[dict[str, Any]], list[list[Any]]]
|
169
169
|
type: Optional[str] = "table"
|
170
170
|
|
171
171
|
@classmethod
|
172
172
|
def _sanitize(
|
173
|
-
cls, item: Union[
|
174
|
-
) -> Union[
|
173
|
+
cls, item: Union[dict[str, Any], list[Any], float]
|
174
|
+
) -> Union[dict[str, Any], list[Any], int, float, None]:
|
175
175
|
"""
|
176
176
|
Sanitize NaN values in a given item.
|
177
177
|
The item can be a dict, list or float.
|
@@ -230,39 +230,6 @@ class ImageArtifact(Artifact):
|
|
230
230
|
return self.image_url
|
231
231
|
|
232
232
|
|
233
|
-
@inject_client
|
234
|
-
async def _create_artifact(
|
235
|
-
type: str,
|
236
|
-
key: Optional[str] = None,
|
237
|
-
description: Optional[str] = None,
|
238
|
-
data: Optional[Union[Dict[str, Any], Any]] = None,
|
239
|
-
client: Optional["PrefectClient"] = None,
|
240
|
-
) -> UUID:
|
241
|
-
"""
|
242
|
-
Helper function to create an artifact.
|
243
|
-
|
244
|
-
Arguments:
|
245
|
-
type: A string identifying the type of artifact.
|
246
|
-
key: A user-provided string identifier.
|
247
|
-
The key must only contain lowercase letters, numbers, and dashes.
|
248
|
-
description: A user-specified description of the artifact.
|
249
|
-
data: A JSON payload that allows for a result to be retrieved.
|
250
|
-
client: The PrefectClient
|
251
|
-
|
252
|
-
Returns:
|
253
|
-
- The table artifact ID.
|
254
|
-
"""
|
255
|
-
|
256
|
-
artifact = await Artifact(
|
257
|
-
type=type,
|
258
|
-
key=key,
|
259
|
-
description=description,
|
260
|
-
data=data,
|
261
|
-
).create(client)
|
262
|
-
|
263
|
-
return artifact.id
|
264
|
-
|
265
|
-
|
266
233
|
@sync_compatible
|
267
234
|
async def create_link_artifact(
|
268
235
|
link: str,
|
@@ -286,12 +253,16 @@ async def create_link_artifact(
|
|
286
253
|
Returns:
|
287
254
|
The table artifact ID.
|
288
255
|
"""
|
289
|
-
|
256
|
+
new_artifact = LinkArtifact(
|
290
257
|
key=key,
|
291
258
|
description=description,
|
292
259
|
link=link,
|
293
260
|
link_text=link_text,
|
294
|
-
)
|
261
|
+
)
|
262
|
+
create_coro = new_artifact.create(client)
|
263
|
+
if TYPE_CHECKING:
|
264
|
+
assert asyncio.iscoroutine(create_coro)
|
265
|
+
artifact = await create_coro
|
295
266
|
|
296
267
|
return artifact.id
|
297
268
|
|
@@ -315,18 +286,22 @@ async def create_markdown_artifact(
|
|
315
286
|
Returns:
|
316
287
|
The table artifact ID.
|
317
288
|
"""
|
318
|
-
|
289
|
+
new_artifact = MarkdownArtifact(
|
319
290
|
key=key,
|
320
291
|
description=description,
|
321
292
|
markdown=markdown,
|
322
|
-
)
|
293
|
+
)
|
294
|
+
create_coro = new_artifact.create()
|
295
|
+
if TYPE_CHECKING:
|
296
|
+
assert asyncio.iscoroutine(create_coro)
|
297
|
+
artifact = await create_coro
|
323
298
|
|
324
299
|
return artifact.id
|
325
300
|
|
326
301
|
|
327
302
|
@sync_compatible
|
328
303
|
async def create_table_artifact(
|
329
|
-
table: Union[
|
304
|
+
table: Union[dict[str, list[Any]], list[dict[str, Any]], list[list[Any]]],
|
330
305
|
key: Optional[str] = None,
|
331
306
|
description: Optional[str] = None,
|
332
307
|
) -> UUID:
|
@@ -344,11 +319,15 @@ async def create_table_artifact(
|
|
344
319
|
The table artifact ID.
|
345
320
|
"""
|
346
321
|
|
347
|
-
|
322
|
+
new_artifact = TableArtifact(
|
348
323
|
key=key,
|
349
324
|
description=description,
|
350
325
|
table=table,
|
351
|
-
)
|
326
|
+
)
|
327
|
+
create_coro = new_artifact.create()
|
328
|
+
if TYPE_CHECKING:
|
329
|
+
assert asyncio.iscoroutine(create_coro)
|
330
|
+
artifact = await create_coro
|
352
331
|
|
353
332
|
return artifact.id
|
354
333
|
|
@@ -373,11 +352,15 @@ async def create_progress_artifact(
|
|
373
352
|
The progress artifact ID.
|
374
353
|
"""
|
375
354
|
|
376
|
-
|
355
|
+
new_artifact = ProgressArtifact(
|
377
356
|
key=key,
|
378
357
|
description=description,
|
379
358
|
progress=progress,
|
380
|
-
)
|
359
|
+
)
|
360
|
+
create_coro = new_artifact.create()
|
361
|
+
if TYPE_CHECKING:
|
362
|
+
assert asyncio.iscoroutine(create_coro)
|
363
|
+
artifact = await create_coro
|
381
364
|
|
382
365
|
return artifact.id
|
383
366
|
|
@@ -387,7 +370,7 @@ async def update_progress_artifact(
|
|
387
370
|
artifact_id: UUID,
|
388
371
|
progress: float,
|
389
372
|
description: Optional[str] = None,
|
390
|
-
client: Optional[PrefectClient] = None,
|
373
|
+
client: Optional["PrefectClient"] = None,
|
391
374
|
) -> UUID:
|
392
375
|
"""
|
393
376
|
Update a progress artifact.
|
@@ -444,10 +427,14 @@ async def create_image_artifact(
|
|
444
427
|
The image artifact ID.
|
445
428
|
"""
|
446
429
|
|
447
|
-
|
430
|
+
new_artifact = ImageArtifact(
|
448
431
|
key=key,
|
449
432
|
description=description,
|
450
433
|
image_url=image_url,
|
451
|
-
)
|
434
|
+
)
|
435
|
+
create_coro = new_artifact.create()
|
436
|
+
if TYPE_CHECKING:
|
437
|
+
assert asyncio.iscoroutine(create_coro)
|
438
|
+
artifact = await create_coro
|
452
439
|
|
453
440
|
return artifact.id
|
prefect/automations.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional,
|
1
|
+
from typing import TYPE_CHECKING, Optional, overload
|
2
2
|
from uuid import UUID
|
3
3
|
|
4
4
|
from pydantic import Field
|
@@ -112,17 +112,28 @@ class Automation(AutomationCore):
|
|
112
112
|
auto.name = "new name"
|
113
113
|
auto.update()
|
114
114
|
"""
|
115
|
+
assert self.id is not None
|
115
116
|
async with get_client() as client:
|
116
117
|
automation = AutomationCore(
|
117
118
|
**self.model_dump(exclude={"id", "owner_resource"})
|
118
119
|
)
|
119
120
|
await client.update_automation(automation_id=self.id, automation=automation)
|
120
121
|
|
122
|
+
@overload
|
123
|
+
@classmethod
|
124
|
+
async def read(cls, id: UUID, name: Optional[str] = ...) -> Self:
|
125
|
+
...
|
126
|
+
|
127
|
+
@overload
|
128
|
+
@classmethod
|
129
|
+
async def read(cls, id: None = None, name: str = ...) -> Optional[Self]:
|
130
|
+
...
|
131
|
+
|
121
132
|
@classmethod
|
122
133
|
@sync_compatible
|
123
134
|
async def read(
|
124
|
-
cls
|
125
|
-
) -> Self:
|
135
|
+
cls, id: Optional[UUID] = None, name: Optional[str] = None
|
136
|
+
) -> Optional[Self]:
|
126
137
|
"""
|
127
138
|
Read an automation by ID or name.
|
128
139
|
automation = Automation.read(name="woodchonk")
|
@@ -145,13 +156,13 @@ class Automation(AutomationCore):
|
|
145
156
|
raise
|
146
157
|
if automation is None:
|
147
158
|
raise ValueError(f"Automation with ID {id!r} not found")
|
148
|
-
return
|
159
|
+
return cls(**automation.model_dump())
|
149
160
|
else:
|
161
|
+
if TYPE_CHECKING:
|
162
|
+
assert name is not None
|
150
163
|
automation = await client.read_automations_by_name(name=name)
|
151
164
|
if len(automation) > 0:
|
152
|
-
return (
|
153
|
-
Automation(**automation[0].model_dump()) if automation else None
|
154
|
-
)
|
165
|
+
return cls(**automation[0].model_dump()) if automation else None
|
155
166
|
else:
|
156
167
|
raise ValueError(f"Automation with name {name!r} not found")
|
157
168
|
|
@@ -161,6 +172,9 @@ class Automation(AutomationCore):
|
|
161
172
|
auto = Automation.read(id = 123)
|
162
173
|
auto.delete()
|
163
174
|
"""
|
175
|
+
if self.id is None:
|
176
|
+
raise ValueError("Can't delete an automation without an id")
|
177
|
+
|
164
178
|
async with get_client() as client:
|
165
179
|
try:
|
166
180
|
await client.delete_automation(self.id)
|
@@ -177,6 +191,9 @@ class Automation(AutomationCore):
|
|
177
191
|
auto = Automation.read(id = 123)
|
178
192
|
auto.disable()
|
179
193
|
"""
|
194
|
+
if self.id is None:
|
195
|
+
raise ValueError("Can't disable an automation without an id")
|
196
|
+
|
180
197
|
async with get_client() as client:
|
181
198
|
try:
|
182
199
|
await client.pause_automation(self.id)
|
@@ -193,6 +210,9 @@ class Automation(AutomationCore):
|
|
193
210
|
auto = Automation.read(id = 123)
|
194
211
|
auto.enable()
|
195
212
|
"""
|
213
|
+
if self.id is None:
|
214
|
+
raise ValueError("Can't enable an automation without an id")
|
215
|
+
|
196
216
|
async with get_client() as client:
|
197
217
|
try:
|
198
218
|
await client.resume_automation(self.id)
|
prefect/blocks/core.py
CHANGED
@@ -38,7 +38,7 @@ from pydantic import (
|
|
38
38
|
model_serializer,
|
39
39
|
)
|
40
40
|
from pydantic.json_schema import GenerateJsonSchema
|
41
|
-
from typing_extensions import Literal, ParamSpec, Self, get_args
|
41
|
+
from typing_extensions import Literal, ParamSpec, Self, TypeGuard, get_args
|
42
42
|
|
43
43
|
import prefect.exceptions
|
44
44
|
from prefect._internal.compatibility.async_dispatch import async_dispatch
|
@@ -276,7 +276,7 @@ class Block(BaseModel, ABC):
|
|
276
276
|
initialization.
|
277
277
|
"""
|
278
278
|
|
279
|
-
model_config = ConfigDict(
|
279
|
+
model_config: ClassVar[ConfigDict] = ConfigDict(
|
280
280
|
extra="allow",
|
281
281
|
json_schema_extra=schema_extra,
|
282
282
|
)
|
@@ -1163,7 +1163,7 @@ class Block(BaseModel, ABC):
|
|
1163
1163
|
) from e
|
1164
1164
|
|
1165
1165
|
@staticmethod
|
1166
|
-
def is_block_class(block) ->
|
1166
|
+
def is_block_class(block: Any) -> TypeGuard[Type["Block"]]:
|
1167
1167
|
return _is_subclass(block, Block)
|
1168
1168
|
|
1169
1169
|
@staticmethod
|