prefect-client 3.4.6.dev2__py3-none-any.whl → 3.4.7__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/AGENTS.md +28 -0
- prefect/_build_info.py +3 -3
- prefect/_internal/websockets.py +109 -0
- prefect/artifacts.py +51 -2
- prefect/assets/core.py +2 -2
- prefect/blocks/core.py +82 -11
- prefect/client/cloud.py +11 -1
- prefect/client/orchestration/__init__.py +21 -15
- prefect/client/orchestration/_deployments/client.py +139 -4
- prefect/client/orchestration/_flows/client.py +4 -4
- prefect/client/schemas/__init__.py +5 -2
- prefect/client/schemas/actions.py +1 -0
- prefect/client/schemas/filters.py +3 -0
- prefect/client/schemas/objects.py +27 -10
- prefect/context.py +6 -4
- prefect/events/clients.py +2 -76
- prefect/events/schemas/automations.py +4 -0
- prefect/events/schemas/labelling.py +2 -0
- prefect/flow_engine.py +6 -3
- prefect/flows.py +64 -45
- prefect/futures.py +25 -4
- prefect/locking/filesystem.py +1 -1
- prefect/logging/clients.py +347 -0
- prefect/runner/runner.py +1 -1
- prefect/runner/submit.py +10 -4
- prefect/serializers.py +8 -3
- prefect/server/api/logs.py +64 -9
- prefect/server/api/server.py +2 -0
- prefect/server/api/templates.py +8 -2
- prefect/settings/context.py +17 -14
- prefect/settings/models/server/logs.py +28 -0
- prefect/settings/models/server/root.py +5 -0
- prefect/settings/models/server/services.py +26 -0
- prefect/task_engine.py +17 -17
- prefect/task_runners.py +10 -10
- prefect/tasks.py +52 -9
- prefect/types/__init__.py +2 -0
- prefect/types/names.py +50 -0
- prefect/utilities/_ast.py +2 -2
- prefect/utilities/callables.py +1 -1
- prefect/utilities/collections.py +6 -6
- prefect/utilities/engine.py +67 -72
- prefect/utilities/pydantic.py +19 -1
- prefect/workers/base.py +2 -0
- {prefect_client-3.4.6.dev2.dist-info → prefect_client-3.4.7.dist-info}/METADATA +1 -1
- {prefect_client-3.4.6.dev2.dist-info → prefect_client-3.4.7.dist-info}/RECORD +48 -44
- {prefect_client-3.4.6.dev2.dist-info → prefect_client-3.4.7.dist-info}/WHEEL +0 -0
- {prefect_client-3.4.6.dev2.dist-info → prefect_client-3.4.7.dist-info}/licenses/LICENSE +0 -0
prefect/AGENTS.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Core Prefect SDK
|
2
|
+
|
3
|
+
The foundation for building and executing workflows with Python.
|
4
|
+
|
5
|
+
## Key Components
|
6
|
+
|
7
|
+
- **Flows & Tasks**: Workflow definition with `@flow` and `@task` decorators
|
8
|
+
- **States**: Execution status tracking (Pending, Running, Completed, Failed)
|
9
|
+
- **Context**: Runtime information and dependency injection
|
10
|
+
- **Results**: Task output persistence and retrieval
|
11
|
+
- **Deployments**: Packaging flows for scheduled/triggered execution
|
12
|
+
- **Blocks**: Reusable configuration for external systems
|
13
|
+
|
14
|
+
## Main Modules
|
15
|
+
|
16
|
+
- `flows.py` - Flow lifecycle and execution
|
17
|
+
- `tasks.py` - Task definition and dependency resolution
|
18
|
+
- `engine.py` - Core execution engine
|
19
|
+
- `client/` - Server/Cloud API communication
|
20
|
+
- `deployments/` - Deployment management
|
21
|
+
- `blocks/` - Infrastructure and storage blocks
|
22
|
+
|
23
|
+
## SDK-Specific Notes
|
24
|
+
|
25
|
+
- Async-first execution model with sync support
|
26
|
+
- Immutable flow/task definitions after creation
|
27
|
+
- State transitions handle retries and caching
|
28
|
+
- Backward compatibility required for public APIs
|
prefect/_build_info.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Generated by versioningit
|
2
|
-
__version__ = "3.4.
|
3
|
-
__build_date__ = "2025-06-
|
4
|
-
__git_commit__ = "
|
2
|
+
__version__ = "3.4.7"
|
3
|
+
__build_date__ = "2025-06-26 21:16:06.964232+00:00"
|
4
|
+
__git_commit__ = "cd81d15a41aece3a78ae7664b59a2ad841aef1f8"
|
5
5
|
__dirty__ = False
|
@@ -0,0 +1,109 @@
|
|
1
|
+
"""
|
2
|
+
Internal WebSocket proxy utilities for Prefect client connections.
|
3
|
+
|
4
|
+
This module provides shared WebSocket proxy connection logic and SSL configuration
|
5
|
+
to avoid duplication between events and logs clients.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import ssl
|
10
|
+
from typing import Any, Generator, Optional
|
11
|
+
from urllib.parse import urlparse
|
12
|
+
from urllib.request import proxy_bypass
|
13
|
+
|
14
|
+
import certifi
|
15
|
+
from python_socks.async_.asyncio import Proxy
|
16
|
+
from typing_extensions import Self
|
17
|
+
from websockets.asyncio.client import ClientConnection, connect
|
18
|
+
|
19
|
+
from prefect.settings import get_current_settings
|
20
|
+
|
21
|
+
|
22
|
+
def create_ssl_context_for_websocket(uri: str) -> Optional[ssl.SSLContext]:
|
23
|
+
"""Create SSL context for WebSocket connections based on URI scheme."""
|
24
|
+
u = urlparse(uri)
|
25
|
+
|
26
|
+
if u.scheme != "wss":
|
27
|
+
return None
|
28
|
+
|
29
|
+
if get_current_settings().api.tls_insecure_skip_verify:
|
30
|
+
# Create an unverified context for insecure connections
|
31
|
+
ctx = ssl.create_default_context()
|
32
|
+
ctx.check_hostname = False
|
33
|
+
ctx.verify_mode = ssl.CERT_NONE
|
34
|
+
return ctx
|
35
|
+
else:
|
36
|
+
# Create a verified context with the certificate file
|
37
|
+
cert_file = get_current_settings().api.ssl_cert_file
|
38
|
+
if not cert_file:
|
39
|
+
cert_file = certifi.where()
|
40
|
+
return ssl.create_default_context(cafile=cert_file)
|
41
|
+
|
42
|
+
|
43
|
+
class WebsocketProxyConnect(connect):
|
44
|
+
"""
|
45
|
+
WebSocket connection class with proxy and SSL support.
|
46
|
+
|
47
|
+
Extends the websockets.asyncio.client.connect class to add HTTP/HTTPS
|
48
|
+
proxy support via environment variables, proxy bypass logic, and SSL
|
49
|
+
certificate verification.
|
50
|
+
"""
|
51
|
+
|
52
|
+
def __init__(self: Self, uri: str, **kwargs: Any):
|
53
|
+
# super() is intentionally deferred to the _proxy_connect method
|
54
|
+
# to allow for the socket to be established first
|
55
|
+
|
56
|
+
self.uri = uri
|
57
|
+
self._kwargs = kwargs
|
58
|
+
|
59
|
+
u = urlparse(uri)
|
60
|
+
host = u.hostname
|
61
|
+
|
62
|
+
if not host:
|
63
|
+
raise ValueError(f"Invalid URI {uri}, no hostname found")
|
64
|
+
|
65
|
+
if u.scheme == "ws":
|
66
|
+
port = u.port or 80
|
67
|
+
proxy_url = os.environ.get("HTTP_PROXY")
|
68
|
+
elif u.scheme == "wss":
|
69
|
+
port = u.port or 443
|
70
|
+
proxy_url = os.environ.get("HTTPS_PROXY")
|
71
|
+
kwargs["server_hostname"] = host
|
72
|
+
else:
|
73
|
+
raise ValueError(
|
74
|
+
"Unsupported scheme %s. Expected 'ws' or 'wss'. " % u.scheme
|
75
|
+
)
|
76
|
+
|
77
|
+
# Store proxy URL for deferred creation. Creating the proxy object here
|
78
|
+
# can bind asyncio futures to the wrong event loop when multiple WebSocket
|
79
|
+
# connections are initialized at different times (e.g., events + logs clients).
|
80
|
+
self._proxy_url = proxy_url if proxy_url and not proxy_bypass(host) else None
|
81
|
+
self._host = host
|
82
|
+
self._port = port
|
83
|
+
|
84
|
+
# Configure SSL context for HTTPS connections
|
85
|
+
ssl_context = create_ssl_context_for_websocket(uri)
|
86
|
+
if ssl_context:
|
87
|
+
self._kwargs.setdefault("ssl", ssl_context)
|
88
|
+
|
89
|
+
async def _proxy_connect(self: Self) -> ClientConnection:
|
90
|
+
if self._proxy_url:
|
91
|
+
# Create proxy in the current event loop context
|
92
|
+
proxy = Proxy.from_url(self._proxy_url)
|
93
|
+
sock = await proxy.connect(
|
94
|
+
dest_host=self._host,
|
95
|
+
dest_port=self._port,
|
96
|
+
)
|
97
|
+
self._kwargs["sock"] = sock
|
98
|
+
|
99
|
+
super().__init__(self.uri, **self._kwargs)
|
100
|
+
proto = await self.__await_impl__()
|
101
|
+
return proto
|
102
|
+
|
103
|
+
def __await__(self: Self) -> Generator[Any, None, ClientConnection]:
|
104
|
+
return self._proxy_connect().__await__()
|
105
|
+
|
106
|
+
|
107
|
+
def websocket_connect(uri: str, **kwargs: Any) -> WebsocketProxyConnect:
|
108
|
+
"""Create a WebSocket connection with proxy and SSL support."""
|
109
|
+
return WebsocketProxyConnect(uri, **kwargs)
|
prefect/artifacts.py
CHANGED
@@ -55,7 +55,7 @@ class Artifact(ArtifactRequest):
|
|
55
55
|
client: The PrefectClient
|
56
56
|
|
57
57
|
Returns:
|
58
|
-
|
58
|
+
The created artifact.
|
59
59
|
"""
|
60
60
|
|
61
61
|
local_client_context = asyncnullcontext(client) if client else get_client()
|
@@ -93,7 +93,7 @@ class Artifact(ArtifactRequest):
|
|
93
93
|
client: The PrefectClient
|
94
94
|
|
95
95
|
Returns:
|
96
|
-
|
96
|
+
The created artifact.
|
97
97
|
"""
|
98
98
|
|
99
99
|
# Create sync client since this is a sync method.
|
@@ -417,6 +417,23 @@ def create_link_artifact(
|
|
417
417
|
|
418
418
|
Returns:
|
419
419
|
The table artifact ID.
|
420
|
+
|
421
|
+
Example:
|
422
|
+
```python
|
423
|
+
from prefect import flow
|
424
|
+
from prefect.artifacts import create_link_artifact
|
425
|
+
|
426
|
+
@flow
|
427
|
+
def my_flow():
|
428
|
+
create_link_artifact(
|
429
|
+
link="https://www.prefect.io",
|
430
|
+
link_text="Prefect",
|
431
|
+
key="prefect-link",
|
432
|
+
description="This is a link to the Prefect website",
|
433
|
+
)
|
434
|
+
|
435
|
+
my_flow()
|
436
|
+
```
|
420
437
|
"""
|
421
438
|
new_artifact = LinkArtifact(
|
422
439
|
key=key,
|
@@ -475,6 +492,22 @@ def create_markdown_artifact(
|
|
475
492
|
|
476
493
|
Returns:
|
477
494
|
The table artifact ID.
|
495
|
+
|
496
|
+
Example:
|
497
|
+
```python
|
498
|
+
from prefect import flow
|
499
|
+
from prefect.artifacts import create_markdown_artifact
|
500
|
+
|
501
|
+
@flow
|
502
|
+
def my_flow():
|
503
|
+
create_markdown_artifact(
|
504
|
+
markdown="## Prefect",
|
505
|
+
key="prefect-markdown",
|
506
|
+
description="This is a markdown artifact",
|
507
|
+
)
|
508
|
+
|
509
|
+
my_flow()
|
510
|
+
```
|
478
511
|
"""
|
479
512
|
new_artifact = MarkdownArtifact(
|
480
513
|
key=key,
|
@@ -533,6 +566,22 @@ def create_table_artifact(
|
|
533
566
|
|
534
567
|
Returns:
|
535
568
|
The table artifact ID.
|
569
|
+
|
570
|
+
Example:
|
571
|
+
```python
|
572
|
+
from prefect import flow
|
573
|
+
from prefect.artifacts import create_table_artifact
|
574
|
+
|
575
|
+
@flow
|
576
|
+
def my_flow():
|
577
|
+
create_table_artifact(
|
578
|
+
table=[{"name": "John", "age": 30}, {"name": "Jane", "age": 25}],
|
579
|
+
key="prefect-table",
|
580
|
+
description="This is a table artifact",
|
581
|
+
)
|
582
|
+
|
583
|
+
my_flow()
|
584
|
+
```
|
536
585
|
"""
|
537
586
|
|
538
587
|
new_artifact = TableArtifact(
|
prefect/assets/core.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Any, ClassVar, Optional
|
|
5
5
|
from pydantic import ConfigDict, Field
|
6
6
|
|
7
7
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
8
|
-
from prefect.types import
|
8
|
+
from prefect.types import ValidAssetKey
|
9
9
|
|
10
10
|
|
11
11
|
class AssetProperties(PrefectBaseModel):
|
@@ -37,7 +37,7 @@ class Asset(PrefectBaseModel):
|
|
37
37
|
|
38
38
|
model_config: ClassVar[ConfigDict] = ConfigDict(frozen=True)
|
39
39
|
|
40
|
-
key:
|
40
|
+
key: ValidAssetKey
|
41
41
|
properties: Optional[AssetProperties] = Field(
|
42
42
|
default=None,
|
43
43
|
description="Properties of the asset. "
|
prefect/blocks/core.py
CHANGED
@@ -175,11 +175,29 @@ def _collect_secret_fields(
|
|
175
175
|
)
|
176
176
|
return
|
177
177
|
|
178
|
-
if
|
178
|
+
# Check if this is a pydantic Secret type (including generic Secret[T])
|
179
|
+
is_pydantic_secret = False
|
180
|
+
|
181
|
+
# Direct check for SecretStr, SecretBytes
|
182
|
+
if type_ in (SecretStr, SecretBytes):
|
183
|
+
is_pydantic_secret = True
|
184
|
+
# Check for base Secret class
|
185
|
+
elif (
|
179
186
|
isinstance(type_, type) # type: ignore[unnecessaryIsInstance]
|
180
187
|
and getattr(type_, "__module__", None) == "pydantic.types"
|
181
188
|
and getattr(type_, "__name__", None) == "Secret"
|
182
189
|
):
|
190
|
+
is_pydantic_secret = True
|
191
|
+
# Check for generic Secret[T] (e.g., Secret[str], Secret[int])
|
192
|
+
elif get_origin(type_) is not None:
|
193
|
+
origin = get_origin(type_)
|
194
|
+
if (
|
195
|
+
getattr(origin, "__module__", None) == "pydantic.types"
|
196
|
+
and getattr(origin, "__name__", None) == "Secret"
|
197
|
+
):
|
198
|
+
is_pydantic_secret = True
|
199
|
+
|
200
|
+
if is_pydantic_secret:
|
183
201
|
secrets.append(name)
|
184
202
|
elif type_ == SecretDict:
|
185
203
|
# Append .* to field name to signify that all values under a given key are secret and should be obfuscated.
|
@@ -370,16 +388,27 @@ class Block(BaseModel, ABC):
|
|
370
388
|
) -> Any:
|
371
389
|
jsonable_self = handler(self)
|
372
390
|
if (ctx := info.context) and ctx.get("include_secrets") is True:
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
391
|
+
# Add serialization mode to context so handle_secret_render knows how to process nested models
|
392
|
+
ctx["serialization_mode"] = info.mode
|
393
|
+
|
394
|
+
for field_name in type(self).model_fields:
|
395
|
+
field_value = getattr(self, field_name)
|
396
|
+
|
397
|
+
# In JSON mode, skip fields that don't contain secrets
|
398
|
+
# as they're already properly serialized by the handler
|
399
|
+
if (
|
400
|
+
info.mode == "json"
|
401
|
+
and field_name in jsonable_self
|
402
|
+
and not self._field_has_secrets(field_name)
|
403
|
+
):
|
404
|
+
continue
|
405
|
+
|
406
|
+
# For all other fields, use visit_collection with handle_secret_render
|
407
|
+
jsonable_self[field_name] = visit_collection(
|
408
|
+
expr=field_value,
|
409
|
+
visit_fn=partial(handle_secret_render, context=ctx),
|
410
|
+
return_data=True,
|
411
|
+
)
|
383
412
|
extra_fields = {
|
384
413
|
"block_type_slug": self.get_block_type_slug(),
|
385
414
|
"_block_document_id": self._block_document_id,
|
@@ -477,6 +506,25 @@ class Block(BaseModel, ABC):
|
|
477
506
|
else:
|
478
507
|
return f"sha256:{checksum}"
|
479
508
|
|
509
|
+
def _field_has_secrets(self, field_name: str) -> bool:
|
510
|
+
"""Check if a field contains secrets based on the schema's secret_fields."""
|
511
|
+
secret_fields = self.model_json_schema().get("secret_fields", [])
|
512
|
+
|
513
|
+
# Check if field_name matches any secret field pattern
|
514
|
+
for secret_field in secret_fields:
|
515
|
+
if secret_field == field_name:
|
516
|
+
return True
|
517
|
+
elif secret_field.startswith(f"{field_name}."):
|
518
|
+
# This field contains nested secrets
|
519
|
+
return True
|
520
|
+
elif secret_field.endswith(".*"):
|
521
|
+
# Handle wildcard patterns like "field.*"
|
522
|
+
prefix = secret_field[:-2] # Remove .*
|
523
|
+
if field_name == prefix:
|
524
|
+
return True
|
525
|
+
|
526
|
+
return False
|
527
|
+
|
480
528
|
def _to_block_document(
|
481
529
|
self,
|
482
530
|
name: Optional[str] = None,
|
@@ -530,6 +578,29 @@ class Block(BaseModel, ABC):
|
|
530
578
|
context={"include_secrets": include_secrets},
|
531
579
|
)
|
532
580
|
|
581
|
+
# Ensure non-secret fields are JSON-serializable to avoid issues with types
|
582
|
+
# like SemanticVersion when the BlockDocument is later serialized
|
583
|
+
try:
|
584
|
+
json_data = self.model_dump(
|
585
|
+
mode="json",
|
586
|
+
by_alias=True,
|
587
|
+
include=data_keys,
|
588
|
+
context={"include_secrets": include_secrets},
|
589
|
+
)
|
590
|
+
# Replace non-secret, non-Block fields with their JSON representation
|
591
|
+
# We need to check the original field to determine if it's a secret or Block
|
592
|
+
for key in data_keys:
|
593
|
+
if key in block_document_data and key in json_data:
|
594
|
+
field_value = getattr(self, key)
|
595
|
+
# Only replace if the field doesn't contain secrets and is not a Block
|
596
|
+
if not self._field_has_secrets(key) and not isinstance(
|
597
|
+
field_value, Block
|
598
|
+
):
|
599
|
+
block_document_data[key] = json_data[key]
|
600
|
+
except Exception:
|
601
|
+
# If JSON serialization fails, we'll handle it later
|
602
|
+
pass
|
603
|
+
|
533
604
|
# Iterate through and find blocks that already have saved block documents to
|
534
605
|
# create references to those saved block documents.
|
535
606
|
for key in data_keys:
|
prefect/client/cloud.py
CHANGED
@@ -24,6 +24,16 @@ from prefect.settings import (
|
|
24
24
|
|
25
25
|
PARSE_API_URL_REGEX = re.compile(r"accounts/(.{36})/workspaces/(.{36})")
|
26
26
|
|
27
|
+
# Cache for TypeAdapter instances to avoid repeated instantiation
|
28
|
+
_TYPE_ADAPTER_CACHE: dict[type, pydantic.TypeAdapter[Any]] = {}
|
29
|
+
|
30
|
+
|
31
|
+
def _get_type_adapter(type_: type) -> pydantic.TypeAdapter[Any]:
|
32
|
+
"""Get or create a cached TypeAdapter for the given type."""
|
33
|
+
if type_ not in _TYPE_ADAPTER_CACHE:
|
34
|
+
_TYPE_ADAPTER_CACHE[type_] = pydantic.TypeAdapter(type_)
|
35
|
+
return _TYPE_ADAPTER_CACHE[type_]
|
36
|
+
|
27
37
|
|
28
38
|
def get_cloud_client(
|
29
39
|
host: Optional[str] = None,
|
@@ -112,7 +122,7 @@ class CloudClient:
|
|
112
122
|
await self.read_workspaces()
|
113
123
|
|
114
124
|
async def read_workspaces(self) -> list[Workspace]:
|
115
|
-
workspaces =
|
125
|
+
workspaces = _get_type_adapter(list[Workspace]).validate_python(
|
116
126
|
await self.get("/me/workspaces")
|
117
127
|
)
|
118
128
|
return workspaces
|
@@ -101,10 +101,11 @@ from prefect.client.schemas.filters import (
|
|
101
101
|
WorkQueueFilterName,
|
102
102
|
)
|
103
103
|
from prefect.client.schemas.objects import (
|
104
|
-
|
104
|
+
TaskRunResult,
|
105
|
+
FlowRunResult,
|
105
106
|
Parameter,
|
107
|
+
Constant,
|
106
108
|
TaskRunPolicy,
|
107
|
-
TaskRunResult,
|
108
109
|
WorkQueue,
|
109
110
|
WorkQueueStatusDetail,
|
110
111
|
)
|
@@ -144,6 +145,16 @@ P = ParamSpec("P")
|
|
144
145
|
R = TypeVar("R", infer_variance=True)
|
145
146
|
T = TypeVar("T")
|
146
147
|
|
148
|
+
# Cache for TypeAdapter instances to avoid repeated instantiation
|
149
|
+
_TYPE_ADAPTER_CACHE: dict[type, pydantic.TypeAdapter[Any]] = {}
|
150
|
+
|
151
|
+
|
152
|
+
def _get_type_adapter(type_: type) -> pydantic.TypeAdapter[Any]:
|
153
|
+
"""Get or create a cached TypeAdapter for the given type."""
|
154
|
+
if type_ not in _TYPE_ADAPTER_CACHE:
|
155
|
+
_TYPE_ADAPTER_CACHE[type_] = pydantic.TypeAdapter(type_)
|
156
|
+
return _TYPE_ADAPTER_CACHE[type_]
|
157
|
+
|
147
158
|
|
148
159
|
@overload
|
149
160
|
def get_client(
|
@@ -635,7 +646,7 @@ class PrefectClient(
|
|
635
646
|
raise prefect.exceptions.ObjectNotFound(http_exc=e) from e
|
636
647
|
else:
|
637
648
|
raise
|
638
|
-
return
|
649
|
+
return _get_type_adapter(list[FlowRun]).validate_python(response.json())
|
639
650
|
|
640
651
|
async def read_work_queue(
|
641
652
|
self,
|
@@ -768,13 +779,7 @@ class PrefectClient(
|
|
768
779
|
task_inputs: Optional[
|
769
780
|
dict[
|
770
781
|
str,
|
771
|
-
list[
|
772
|
-
Union[
|
773
|
-
TaskRunResult,
|
774
|
-
Parameter,
|
775
|
-
Constant,
|
776
|
-
]
|
777
|
-
],
|
782
|
+
list[Union[TaskRunResult, FlowRunResult, Parameter, Constant]],
|
778
783
|
]
|
779
784
|
] = None,
|
780
785
|
) -> TaskRun:
|
@@ -894,7 +899,7 @@ class PrefectClient(
|
|
894
899
|
"offset": offset,
|
895
900
|
}
|
896
901
|
response = await self._client.post("/task_runs/filter", json=body)
|
897
|
-
return
|
902
|
+
return _get_type_adapter(list[TaskRun]).validate_python(response.json())
|
898
903
|
|
899
904
|
async def delete_task_run(self, task_run_id: UUID) -> None:
|
900
905
|
"""
|
@@ -958,7 +963,7 @@ class PrefectClient(
|
|
958
963
|
response = await self._client.get(
|
959
964
|
"/task_run_states/", params=dict(task_run_id=str(task_run_id))
|
960
965
|
)
|
961
|
-
return
|
966
|
+
return _get_type_adapter(list[prefect.states.State]).validate_python(
|
962
967
|
response.json()
|
963
968
|
)
|
964
969
|
|
@@ -1005,7 +1010,7 @@ class PrefectClient(
|
|
1005
1010
|
else:
|
1006
1011
|
response = await self._client.post("/work_queues/filter", json=json)
|
1007
1012
|
|
1008
|
-
return
|
1013
|
+
return _get_type_adapter(list[WorkQueue]).validate_python(response.json())
|
1009
1014
|
|
1010
1015
|
async def read_worker_metadata(self) -> dict[str, Any]:
|
1011
1016
|
"""Reads worker metadata stored in Prefect collection registry."""
|
@@ -1430,6 +1435,7 @@ class SyncPrefectClient(
|
|
1430
1435
|
list[
|
1431
1436
|
Union[
|
1432
1437
|
TaskRunResult,
|
1438
|
+
FlowRunResult,
|
1433
1439
|
Parameter,
|
1434
1440
|
Constant,
|
1435
1441
|
]
|
@@ -1554,7 +1560,7 @@ class SyncPrefectClient(
|
|
1554
1560
|
"offset": offset,
|
1555
1561
|
}
|
1556
1562
|
response = self._client.post("/task_runs/filter", json=body)
|
1557
|
-
return
|
1563
|
+
return _get_type_adapter(list[TaskRun]).validate_python(response.json())
|
1558
1564
|
|
1559
1565
|
def set_task_run_state(
|
1560
1566
|
self,
|
@@ -1598,6 +1604,6 @@ class SyncPrefectClient(
|
|
1598
1604
|
response = self._client.get(
|
1599
1605
|
"/task_run_states/", params=dict(task_run_id=str(task_run_id))
|
1600
1606
|
)
|
1601
|
-
return
|
1607
|
+
return _get_type_adapter(list[prefect.states.State]).validate_python(
|
1602
1608
|
response.json()
|
1603
1609
|
)
|