prefect-client 2.17.1__py3-none-any.whl → 2.18.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/_internal/compatibility/deprecated.py +2 -0
- prefect/_internal/pydantic/_compat.py +1 -0
- prefect/_internal/pydantic/utilities/field_validator.py +25 -10
- prefect/_internal/pydantic/utilities/model_dump.py +1 -1
- prefect/_internal/pydantic/utilities/model_validate.py +1 -1
- prefect/_internal/pydantic/utilities/model_validator.py +11 -3
- prefect/_internal/schemas/fields.py +31 -12
- prefect/_internal/schemas/validators.py +0 -6
- prefect/_version.py +97 -38
- prefect/blocks/abstract.py +34 -1
- prefect/blocks/core.py +1 -1
- prefect/blocks/notifications.py +16 -7
- prefect/blocks/system.py +2 -3
- prefect/client/base.py +10 -5
- prefect/client/orchestration.py +405 -85
- prefect/client/schemas/actions.py +4 -3
- prefect/client/schemas/objects.py +6 -5
- prefect/client/schemas/schedules.py +2 -6
- prefect/client/schemas/sorting.py +9 -0
- prefect/client/utilities.py +25 -3
- prefect/concurrency/asyncio.py +11 -5
- prefect/concurrency/events.py +3 -3
- prefect/concurrency/services.py +1 -1
- prefect/concurrency/sync.py +9 -5
- prefect/deployments/__init__.py +0 -2
- prefect/deployments/base.py +2 -144
- prefect/deployments/deployments.py +29 -20
- prefect/deployments/runner.py +36 -28
- prefect/deployments/steps/core.py +3 -3
- prefect/deprecated/packaging/serializers.py +5 -4
- prefect/engine.py +3 -1
- prefect/events/__init__.py +45 -0
- prefect/events/actions.py +250 -18
- prefect/events/cli/automations.py +201 -0
- prefect/events/clients.py +179 -21
- prefect/events/filters.py +30 -3
- prefect/events/instrument.py +40 -40
- prefect/events/related.py +2 -1
- prefect/events/schemas/automations.py +126 -8
- prefect/events/schemas/deployment_triggers.py +23 -277
- prefect/events/schemas/events.py +7 -7
- prefect/events/utilities.py +3 -1
- prefect/events/worker.py +21 -8
- prefect/exceptions.py +1 -1
- prefect/flows.py +33 -18
- prefect/input/actions.py +9 -9
- prefect/input/run_input.py +49 -37
- prefect/logging/__init__.py +2 -2
- prefect/logging/loggers.py +64 -1
- prefect/new_flow_engine.py +293 -0
- prefect/new_task_engine.py +374 -0
- prefect/results.py +32 -12
- prefect/runner/runner.py +3 -2
- prefect/serializers.py +62 -31
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +44 -3
- prefect/settings.py +32 -10
- prefect/states.py +25 -19
- prefect/tasks.py +17 -0
- prefect/types/__init__.py +90 -0
- prefect/utilities/asyncutils.py +37 -0
- prefect/utilities/engine.py +6 -4
- prefect/utilities/pydantic.py +34 -15
- prefect/utilities/schema_tools/hydration.py +88 -19
- prefect/utilities/schema_tools/validation.py +1 -1
- prefect/variables.py +4 -4
- {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/METADATA +1 -1
- {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/RECORD +71 -67
- /prefect/{concurrency/common.py → events/cli/__init__.py} +0 -0
- {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/LICENSE +0 -0
- {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/WHEEL +0 -0
- {prefect_client-2.17.1.dist-info → prefect_client-2.18.1.dist-info}/top_level.txt +0 -0
prefect/blocks/system.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
|
-
import pendulum
|
4
|
-
|
5
3
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
6
4
|
|
7
5
|
if HAS_PYDANTIC_V2:
|
@@ -9,6 +7,7 @@ if HAS_PYDANTIC_V2:
|
|
9
7
|
else:
|
10
8
|
from pydantic import Field, SecretStr
|
11
9
|
|
10
|
+
from prefect._internal.schemas.fields import DateTimeTZ
|
12
11
|
from prefect.blocks.core import Block
|
13
12
|
|
14
13
|
|
@@ -76,7 +75,7 @@ class DateTime(Block):
|
|
76
75
|
_logo_url = "https://cdn.sanity.io/images/3ugk85nk/production/8b3da9a6621e92108b8e6a75b82e15374e170ff7-48x48.png"
|
77
76
|
_documentation_url = "https://docs.prefect.io/api-ref/prefect/blocks/system/#prefect.blocks.system.DateTime"
|
78
77
|
|
79
|
-
value:
|
78
|
+
value: DateTimeTZ = Field(
|
80
79
|
default=...,
|
81
80
|
description="An ISO 8601-compatible datetime value.",
|
82
81
|
)
|
prefect/client/base.py
CHANGED
@@ -193,11 +193,18 @@ class PrefectHttpxClient(httpx.AsyncClient):
|
|
193
193
|
[Configuring Cloudflare Rate Limiting](https://support.cloudflare.com/hc/en-us/articles/115001635128-Configuring-Rate-Limiting-from-UI)
|
194
194
|
"""
|
195
195
|
|
196
|
-
def __init__(
|
196
|
+
def __init__(
|
197
|
+
self,
|
198
|
+
*args,
|
199
|
+
enable_csrf_support: bool = False,
|
200
|
+
raise_on_all_errors: bool = True,
|
201
|
+
**kwargs,
|
202
|
+
):
|
197
203
|
self.enable_csrf_support: bool = enable_csrf_support
|
198
204
|
self.csrf_token: Optional[str] = None
|
199
205
|
self.csrf_token_expiration: Optional[datetime] = None
|
200
206
|
self.csrf_client_id: uuid.UUID = uuid.uuid4()
|
207
|
+
self.raise_on_all_errors: bool = raise_on_all_errors
|
201
208
|
|
202
209
|
super().__init__(*args, **kwargs)
|
203
210
|
|
@@ -345,10 +352,8 @@ class PrefectHttpxClient(httpx.AsyncClient):
|
|
345
352
|
# Convert to a Prefect response to add nicer errors messages
|
346
353
|
response = PrefectResponse.from_httpx_response(response)
|
347
354
|
|
348
|
-
|
349
|
-
|
350
|
-
# `PrefectClient`
|
351
|
-
response.raise_for_status()
|
355
|
+
if self.raise_on_all_errors:
|
356
|
+
response.raise_for_status()
|
352
357
|
|
353
358
|
return response
|
354
359
|
|
prefect/client/orchestration.py
CHANGED
@@ -8,9 +8,11 @@ from typing import (
|
|
8
8
|
Dict,
|
9
9
|
Iterable,
|
10
10
|
List,
|
11
|
+
NoReturn,
|
11
12
|
Optional,
|
12
13
|
Set,
|
13
14
|
Tuple,
|
15
|
+
TypeVar,
|
14
16
|
Union,
|
15
17
|
)
|
16
18
|
from uuid import UUID, uuid4
|
@@ -19,20 +21,19 @@ import certifi
|
|
19
21
|
import httpcore
|
20
22
|
import httpx
|
21
23
|
import pendulum
|
24
|
+
from typing_extensions import ParamSpec
|
22
25
|
|
23
26
|
from prefect._internal.compatibility.deprecated import (
|
24
27
|
handle_deprecated_infra_overrides_parameter,
|
25
28
|
)
|
26
|
-
from prefect._internal.compatibility.experimental import (
|
27
|
-
EXPERIMENTAL_WARNING,
|
28
|
-
ExperimentalFeature,
|
29
|
-
experiment_enabled,
|
30
|
-
)
|
31
29
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
30
|
+
from prefect.client.schemas import sorting
|
31
|
+
from prefect.events import filters
|
32
32
|
from prefect.settings import (
|
33
|
-
|
34
|
-
|
33
|
+
PREFECT_API_SERVICES_TRIGGERS_ENABLED,
|
34
|
+
PREFECT_EXPERIMENTAL_EVENTS,
|
35
35
|
)
|
36
|
+
from prefect.utilities.asyncutils import run_sync
|
36
37
|
|
37
38
|
if HAS_PYDANTIC_V2:
|
38
39
|
import pydantic.v1 as pydantic
|
@@ -133,7 +134,7 @@ from prefect.client.schemas.sorting import (
|
|
133
134
|
TaskRunSort,
|
134
135
|
)
|
135
136
|
from prefect.deprecated.data_documents import DataDocument
|
136
|
-
from prefect.events.schemas.automations import Automation,
|
137
|
+
from prefect.events.schemas.automations import Automation, AutomationCore
|
137
138
|
from prefect.logging import get_logger
|
138
139
|
from prefect.settings import (
|
139
140
|
PREFECT_API_DATABASE_CONNECTION_URL,
|
@@ -155,14 +156,25 @@ if TYPE_CHECKING:
|
|
155
156
|
|
156
157
|
from prefect.client.base import ASGIApp, PrefectHttpxClient, app_lifespan_context
|
157
158
|
|
159
|
+
P = ParamSpec("P")
|
160
|
+
R = TypeVar("R")
|
161
|
+
|
158
162
|
|
159
163
|
class ServerType(AutoEnum):
|
160
164
|
EPHEMERAL = AutoEnum.auto()
|
161
165
|
SERVER = AutoEnum.auto()
|
162
166
|
CLOUD = AutoEnum.auto()
|
163
167
|
|
168
|
+
def supports_automations(self) -> bool:
|
169
|
+
if self == ServerType.CLOUD:
|
170
|
+
return True
|
171
|
+
|
172
|
+
return PREFECT_EXPERIMENTAL_EVENTS and PREFECT_API_SERVICES_TRIGGERS_ENABLED
|
173
|
+
|
164
174
|
|
165
|
-
def get_client(
|
175
|
+
def get_client(
|
176
|
+
httpx_settings: Optional[Dict[str, Any]] = None, sync_client: bool = False
|
177
|
+
) -> "PrefectClient":
|
166
178
|
"""
|
167
179
|
Retrieve a HTTP client for communicating with the Prefect REST API.
|
168
180
|
|
@@ -172,6 +184,13 @@ def get_client(httpx_settings: Optional[dict] = None) -> "PrefectClient":
|
|
172
184
|
async with get_client() as client:
|
173
185
|
await client.hello()
|
174
186
|
```
|
187
|
+
|
188
|
+
To return a synchronous client, pass sync_client=True:
|
189
|
+
|
190
|
+
```python
|
191
|
+
with get_client(sync_client=True) as client:
|
192
|
+
client.hello()
|
193
|
+
```
|
175
194
|
"""
|
176
195
|
ctx = prefect.context.get_settings_context()
|
177
196
|
api = PREFECT_API_URL.value()
|
@@ -182,11 +201,18 @@ def get_client(httpx_settings: Optional[dict] = None) -> "PrefectClient":
|
|
182
201
|
|
183
202
|
api = create_app(ctx.settings, ephemeral=True)
|
184
203
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
204
|
+
if sync_client:
|
205
|
+
return SyncPrefectClient(
|
206
|
+
api,
|
207
|
+
api_key=PREFECT_API_KEY.value(),
|
208
|
+
httpx_settings=httpx_settings,
|
209
|
+
)
|
210
|
+
else:
|
211
|
+
return PrefectClient(
|
212
|
+
api,
|
213
|
+
api_key=PREFECT_API_KEY.value(),
|
214
|
+
httpx_settings=httpx_settings,
|
215
|
+
)
|
190
216
|
|
191
217
|
|
192
218
|
class PrefectClient:
|
@@ -568,21 +594,6 @@ class PrefectClient:
|
|
568
594
|
Returns:
|
569
595
|
The flow run model
|
570
596
|
"""
|
571
|
-
if job_variables is not None and experiment_enabled("flow_run_infra_overrides"):
|
572
|
-
if (
|
573
|
-
PREFECT_EXPERIMENTAL_WARN
|
574
|
-
and PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES
|
575
|
-
):
|
576
|
-
warnings.warn(
|
577
|
-
EXPERIMENTAL_WARNING.format(
|
578
|
-
feature="Flow run job variables",
|
579
|
-
group="flow_run_infra_overrides",
|
580
|
-
help="To use this feature, update your workers to Prefect 2.16.4 or later. ",
|
581
|
-
),
|
582
|
-
ExperimentalFeature,
|
583
|
-
stacklevel=3,
|
584
|
-
)
|
585
|
-
|
586
597
|
parameters = parameters or {}
|
587
598
|
context = context or {}
|
588
599
|
state = state or prefect.states.Scheduled()
|
@@ -703,21 +714,6 @@ class PrefectClient:
|
|
703
714
|
Returns:
|
704
715
|
an `httpx.Response` object from the PATCH request
|
705
716
|
"""
|
706
|
-
if job_variables is not None and experiment_enabled("flow_run_infra_overrides"):
|
707
|
-
if (
|
708
|
-
PREFECT_EXPERIMENTAL_WARN
|
709
|
-
and PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES
|
710
|
-
):
|
711
|
-
warnings.warn(
|
712
|
-
EXPERIMENTAL_WARNING.format(
|
713
|
-
feature="Flow run job variables",
|
714
|
-
group="flow_run_infra_overrides",
|
715
|
-
help="To use this feature, update your workers to Prefect 2.16.4 or later. ",
|
716
|
-
),
|
717
|
-
ExperimentalFeature,
|
718
|
-
stacklevel=3,
|
719
|
-
)
|
720
|
-
|
721
717
|
params = {}
|
722
718
|
if flow_version is not None:
|
723
719
|
params["flow_version"] = flow_version
|
@@ -2164,21 +2160,23 @@ class PrefectClient:
|
|
2164
2160
|
|
2165
2161
|
async def create_task_run(
|
2166
2162
|
self,
|
2167
|
-
task: "TaskObject",
|
2163
|
+
task: "TaskObject[P, R]",
|
2168
2164
|
flow_run_id: Optional[UUID],
|
2169
2165
|
dynamic_key: str,
|
2170
|
-
name: str = None,
|
2171
|
-
extra_tags: Iterable[str] = None,
|
2172
|
-
state: prefect.states.State = None,
|
2173
|
-
task_inputs:
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2166
|
+
name: Optional[str] = None,
|
2167
|
+
extra_tags: Optional[Iterable[str]] = None,
|
2168
|
+
state: Optional[prefect.states.State[R]] = None,
|
2169
|
+
task_inputs: Optional[
|
2170
|
+
Dict[
|
2171
|
+
str,
|
2172
|
+
List[
|
2173
|
+
Union[
|
2174
|
+
TaskRunResult,
|
2175
|
+
Parameter,
|
2176
|
+
Constant,
|
2177
|
+
]
|
2178
|
+
],
|
2179
|
+
]
|
2182
2180
|
] = None,
|
2183
2181
|
) -> TaskRun:
|
2184
2182
|
"""
|
@@ -2998,34 +2996,6 @@ class PrefectClient:
|
|
2998
2996
|
response.raise_for_status()
|
2999
2997
|
return response.json()
|
3000
2998
|
|
3001
|
-
async def create_automation(self, automation: Automation) -> UUID:
|
3002
|
-
"""Creates an automation in Prefect Cloud."""
|
3003
|
-
if self.server_type != ServerType.CLOUD:
|
3004
|
-
raise RuntimeError("Automations are only supported for Prefect Cloud.")
|
3005
|
-
|
3006
|
-
response = await self._client.post(
|
3007
|
-
"/automations/",
|
3008
|
-
json=automation.dict(json_compatible=True),
|
3009
|
-
)
|
3010
|
-
|
3011
|
-
return UUID(response.json()["id"])
|
3012
|
-
|
3013
|
-
async def read_resource_related_automations(
|
3014
|
-
self, resource_id: str
|
3015
|
-
) -> List[ExistingAutomation]:
|
3016
|
-
if self.server_type != ServerType.CLOUD:
|
3017
|
-
raise RuntimeError("Automations are only supported for Prefect Cloud.")
|
3018
|
-
|
3019
|
-
response = await self._client.get(f"/automations/related-to/{resource_id}")
|
3020
|
-
response.raise_for_status()
|
3021
|
-
return pydantic.parse_obj_as(List[ExistingAutomation], response.json())
|
3022
|
-
|
3023
|
-
async def delete_resource_owned_automations(self, resource_id: str):
|
3024
|
-
if self.server_type != ServerType.CLOUD:
|
3025
|
-
raise RuntimeError("Automations are only supported for Prefect Cloud.")
|
3026
|
-
|
3027
|
-
await self._client.delete(f"/automations/owned-by/{resource_id}")
|
3028
|
-
|
3029
2999
|
async def increment_concurrency_slots(
|
3030
3000
|
self, names: List[str], slots: int, mode: str
|
3031
3001
|
) -> httpx.Response:
|
@@ -3165,6 +3135,147 @@ class PrefectClient:
|
|
3165
3135
|
response = await self._client.delete(f"/flow_runs/{flow_run_id}/input/{key}")
|
3166
3136
|
response.raise_for_status()
|
3167
3137
|
|
3138
|
+
def _raise_for_unsupported_automations(self) -> NoReturn:
|
3139
|
+
if not PREFECT_EXPERIMENTAL_EVENTS:
|
3140
|
+
raise RuntimeError(
|
3141
|
+
"The current server and client configuration does not support "
|
3142
|
+
"events. Enable experimental events support with the "
|
3143
|
+
"PREFECT_EXPERIMENTAL_EVENTS setting."
|
3144
|
+
)
|
3145
|
+
else:
|
3146
|
+
raise RuntimeError(
|
3147
|
+
"The current server and client configuration does not support "
|
3148
|
+
"automations. Enable experimental automations with the "
|
3149
|
+
"PREFECT_API_SERVICES_TRIGGERS_ENABLED setting."
|
3150
|
+
)
|
3151
|
+
|
3152
|
+
async def create_automation(self, automation: AutomationCore) -> UUID:
|
3153
|
+
"""Creates an automation in Prefect Cloud."""
|
3154
|
+
if not self.server_type.supports_automations():
|
3155
|
+
self._raise_for_unsupported_automations()
|
3156
|
+
|
3157
|
+
response = await self._client.post(
|
3158
|
+
"/automations/",
|
3159
|
+
json=automation.dict(json_compatible=True),
|
3160
|
+
)
|
3161
|
+
|
3162
|
+
return UUID(response.json()["id"])
|
3163
|
+
|
3164
|
+
async def read_automations(self) -> List[Automation]:
|
3165
|
+
if not self.server_type.supports_automations():
|
3166
|
+
self._raise_for_unsupported_automations()
|
3167
|
+
|
3168
|
+
response = await self._client.post("/automations/filter")
|
3169
|
+
response.raise_for_status()
|
3170
|
+
return pydantic.parse_obj_as(List[Automation], response.json())
|
3171
|
+
|
3172
|
+
async def find_automation(self, id_or_name: str) -> Optional[Automation]:
|
3173
|
+
try:
|
3174
|
+
id = UUID(id_or_name)
|
3175
|
+
except ValueError:
|
3176
|
+
id = None
|
3177
|
+
|
3178
|
+
if id:
|
3179
|
+
automation = await self.read_automation(id)
|
3180
|
+
if automation:
|
3181
|
+
return automation
|
3182
|
+
|
3183
|
+
automations = await self.read_automations()
|
3184
|
+
|
3185
|
+
# Look for it by an exact name
|
3186
|
+
for automation in automations:
|
3187
|
+
if automation.name == id_or_name:
|
3188
|
+
return automation
|
3189
|
+
|
3190
|
+
# Look for it by a case-insensitive name
|
3191
|
+
for automation in automations:
|
3192
|
+
if automation.name.lower() == id_or_name.lower():
|
3193
|
+
return automation
|
3194
|
+
|
3195
|
+
return None
|
3196
|
+
|
3197
|
+
async def read_automation(self, automation_id: UUID) -> Optional[Automation]:
|
3198
|
+
if not self.server_type.supports_automations():
|
3199
|
+
self._raise_for_unsupported_automations()
|
3200
|
+
|
3201
|
+
response = await self._client.get(f"/automations/{automation_id}")
|
3202
|
+
if response.status_code == 404:
|
3203
|
+
return None
|
3204
|
+
response.raise_for_status()
|
3205
|
+
return Automation.parse_obj(response.json())
|
3206
|
+
|
3207
|
+
async def read_automations_by_name(self, name: str) -> List[Automation]:
|
3208
|
+
"""
|
3209
|
+
Query the Prefect API for an automation by name. Only automations matching the provided name will be returned.
|
3210
|
+
|
3211
|
+
Args:
|
3212
|
+
name: the name of the automation to query
|
3213
|
+
|
3214
|
+
Returns:
|
3215
|
+
a list of Automation model representations of the automations
|
3216
|
+
"""
|
3217
|
+
if not self.server_type.supports_automations():
|
3218
|
+
self._raise_for_unsupported_automations()
|
3219
|
+
automation_filter = filters.AutomationFilter(name=dict(any_=[name]))
|
3220
|
+
|
3221
|
+
response = await self._client.post(
|
3222
|
+
"/automations/filter",
|
3223
|
+
json={
|
3224
|
+
"sort": sorting.AutomationSort.UPDATED_DESC,
|
3225
|
+
"automations": automation_filter.dict(json_compatible=True)
|
3226
|
+
if automation_filter
|
3227
|
+
else None,
|
3228
|
+
},
|
3229
|
+
)
|
3230
|
+
|
3231
|
+
response.raise_for_status()
|
3232
|
+
|
3233
|
+
return pydantic.parse_obj_as(List[Automation], response.json())
|
3234
|
+
|
3235
|
+
async def pause_automation(self, automation_id: UUID):
|
3236
|
+
if not self.server_type.supports_automations():
|
3237
|
+
self._raise_for_unsupported_automations()
|
3238
|
+
|
3239
|
+
response = await self._client.patch(
|
3240
|
+
f"/automations/{automation_id}", json={"enabled": False}
|
3241
|
+
)
|
3242
|
+
response.raise_for_status()
|
3243
|
+
|
3244
|
+
async def resume_automation(self, automation_id: UUID):
|
3245
|
+
if not self.server_type.supports_automations():
|
3246
|
+
self._raise_for_unsupported_automations()
|
3247
|
+
|
3248
|
+
response = await self._client.patch(
|
3249
|
+
f"/automations/{automation_id}", json={"enabled": True}
|
3250
|
+
)
|
3251
|
+
response.raise_for_status()
|
3252
|
+
|
3253
|
+
async def delete_automation(self, automation_id: UUID):
|
3254
|
+
if not self.server_type.supports_automations():
|
3255
|
+
self._raise_for_unsupported_automations()
|
3256
|
+
|
3257
|
+
response = await self._client.delete(f"/automations/{automation_id}")
|
3258
|
+
if response.status_code == 404:
|
3259
|
+
return
|
3260
|
+
|
3261
|
+
response.raise_for_status()
|
3262
|
+
|
3263
|
+
async def read_resource_related_automations(
|
3264
|
+
self, resource_id: str
|
3265
|
+
) -> List[Automation]:
|
3266
|
+
if not self.server_type.supports_automations():
|
3267
|
+
self._raise_for_unsupported_automations()
|
3268
|
+
|
3269
|
+
response = await self._client.get(f"/automations/related-to/{resource_id}")
|
3270
|
+
response.raise_for_status()
|
3271
|
+
return pydantic.parse_obj_as(List[Automation], response.json())
|
3272
|
+
|
3273
|
+
async def delete_resource_owned_automations(self, resource_id: str):
|
3274
|
+
if not self.server_type.supports_automations():
|
3275
|
+
self._raise_for_unsupported_automations()
|
3276
|
+
|
3277
|
+
await self._client.delete(f"/automations/owned-by/{resource_id}")
|
3278
|
+
|
3168
3279
|
async def __aenter__(self):
|
3169
3280
|
"""
|
3170
3281
|
Start the client.
|
@@ -3225,3 +3336,212 @@ class PrefectClient:
|
|
3225
3336
|
|
3226
3337
|
def __exit__(self, *_):
|
3227
3338
|
assert False, "This should never be called but must be defined for __enter__"
|
3339
|
+
|
3340
|
+
|
3341
|
+
class SyncPrefectClient:
|
3342
|
+
"""
|
3343
|
+
A synchronous client for interacting with the [Prefect REST API](/api-ref/rest-api/).
|
3344
|
+
|
3345
|
+
Args:
|
3346
|
+
api: the REST API URL or FastAPI application to connect to
|
3347
|
+
api_key: An optional API key for authentication.
|
3348
|
+
api_version: The API version this client is compatible with.
|
3349
|
+
httpx_settings: An optional dictionary of settings to pass to the underlying
|
3350
|
+
`httpx.AsyncClient`
|
3351
|
+
|
3352
|
+
Examples:
|
3353
|
+
|
3354
|
+
Say hello to a Prefect REST API
|
3355
|
+
|
3356
|
+
<div class="terminal">
|
3357
|
+
```
|
3358
|
+
>>> with get_client(sync_client=True) as client:
|
3359
|
+
>>> response = client.hello()
|
3360
|
+
>>>
|
3361
|
+
>>> print(response.json())
|
3362
|
+
👋
|
3363
|
+
```
|
3364
|
+
</div>
|
3365
|
+
"""
|
3366
|
+
|
3367
|
+
def __init__(
|
3368
|
+
self,
|
3369
|
+
api: Union[str, ASGIApp],
|
3370
|
+
*,
|
3371
|
+
api_key: Optional[str] = None,
|
3372
|
+
api_version: Optional[str] = None,
|
3373
|
+
httpx_settings: Optional[Dict[str, Any]] = None,
|
3374
|
+
) -> None:
|
3375
|
+
self._prefect_client = PrefectClient(
|
3376
|
+
api=api,
|
3377
|
+
api_key=api_key,
|
3378
|
+
api_version=api_version,
|
3379
|
+
httpx_settings=httpx_settings,
|
3380
|
+
)
|
3381
|
+
|
3382
|
+
def __enter__(self):
|
3383
|
+
run_sync(self._prefect_client.__aenter__())
|
3384
|
+
return self
|
3385
|
+
|
3386
|
+
def __exit__(self, *exc_info):
|
3387
|
+
return run_sync(self._prefect_client.__aexit__(*exc_info))
|
3388
|
+
|
3389
|
+
async def __aenter__(self):
|
3390
|
+
raise RuntimeError(
|
3391
|
+
"The `SyncPrefectClient` must be entered with a sync context. Use '"
|
3392
|
+
"with SyncPrefectClient(...)' not 'async with SyncPrefectClient(...)'"
|
3393
|
+
)
|
3394
|
+
|
3395
|
+
async def __aexit__(self, *_):
|
3396
|
+
assert False, "This should never be called but must be defined for __aenter__"
|
3397
|
+
|
3398
|
+
def hello(self) -> httpx.Response:
|
3399
|
+
"""
|
3400
|
+
Send a GET request to /hello for testing purposes.
|
3401
|
+
"""
|
3402
|
+
return run_sync(self._prefect_client.hello())
|
3403
|
+
|
3404
|
+
def create_task_run(
|
3405
|
+
self,
|
3406
|
+
task: "TaskObject[P, R]",
|
3407
|
+
flow_run_id: Optional[UUID],
|
3408
|
+
dynamic_key: str,
|
3409
|
+
name: Optional[str] = None,
|
3410
|
+
extra_tags: Optional[Iterable[str]] = None,
|
3411
|
+
state: Optional[prefect.states.State[R]] = None,
|
3412
|
+
task_inputs: Optional[
|
3413
|
+
Dict[
|
3414
|
+
str,
|
3415
|
+
List[
|
3416
|
+
Union[
|
3417
|
+
TaskRunResult,
|
3418
|
+
Parameter,
|
3419
|
+
Constant,
|
3420
|
+
]
|
3421
|
+
],
|
3422
|
+
]
|
3423
|
+
] = None,
|
3424
|
+
) -> TaskRun:
|
3425
|
+
"""
|
3426
|
+
Create a task run
|
3427
|
+
|
3428
|
+
Args:
|
3429
|
+
task: The Task to run
|
3430
|
+
flow_run_id: The flow run id with which to associate the task run
|
3431
|
+
dynamic_key: A key unique to this particular run of a Task within the flow
|
3432
|
+
name: An optional name for the task run
|
3433
|
+
extra_tags: an optional list of extra tags to apply to the task run in
|
3434
|
+
addition to `task.tags`
|
3435
|
+
state: The initial state for the run. If not provided, defaults to
|
3436
|
+
`Pending` for now. Should always be a `Scheduled` type.
|
3437
|
+
task_inputs: the set of inputs passed to the task
|
3438
|
+
|
3439
|
+
Returns:
|
3440
|
+
The created task run.
|
3441
|
+
"""
|
3442
|
+
return run_sync(
|
3443
|
+
self._prefect_client.create_task_run(
|
3444
|
+
task=task,
|
3445
|
+
flow_run_id=flow_run_id,
|
3446
|
+
dynamic_key=dynamic_key,
|
3447
|
+
name=name,
|
3448
|
+
extra_tags=extra_tags,
|
3449
|
+
state=state,
|
3450
|
+
task_inputs=task_inputs,
|
3451
|
+
)
|
3452
|
+
)
|
3453
|
+
|
3454
|
+
def set_task_run_state(
|
3455
|
+
self,
|
3456
|
+
task_run_id: UUID,
|
3457
|
+
state: prefect.states.State,
|
3458
|
+
force: bool = False,
|
3459
|
+
) -> OrchestrationResult:
|
3460
|
+
"""
|
3461
|
+
Set the state of a task run.
|
3462
|
+
|
3463
|
+
Args:
|
3464
|
+
task_run_id: the id of the task run
|
3465
|
+
state: the state to set
|
3466
|
+
force: if True, disregard orchestration logic when setting the state,
|
3467
|
+
forcing the Prefect API to accept the state
|
3468
|
+
|
3469
|
+
Returns:
|
3470
|
+
an OrchestrationResult model representation of state orchestration output
|
3471
|
+
"""
|
3472
|
+
return run_sync(
|
3473
|
+
self._prefect_client.set_task_run_state(
|
3474
|
+
task_run_id=task_run_id,
|
3475
|
+
state=state,
|
3476
|
+
force=force,
|
3477
|
+
)
|
3478
|
+
)
|
3479
|
+
|
3480
|
+
def create_flow_run(
|
3481
|
+
self,
|
3482
|
+
flow_id: UUID,
|
3483
|
+
parameters: Optional[Dict[str, Any]] = None,
|
3484
|
+
context: Optional[Dict[str, Any]] = None,
|
3485
|
+
scheduled_start_time: Optional[datetime.datetime] = None,
|
3486
|
+
run_name: Optional[str] = None,
|
3487
|
+
labels: Optional[List[str]] = None,
|
3488
|
+
parameters_json: Optional[str] = None,
|
3489
|
+
run_config: Optional[Dict[str, Any]] = None,
|
3490
|
+
idempotency_key: Optional[str] = None,
|
3491
|
+
) -> FlowRunResponse:
|
3492
|
+
"""
|
3493
|
+
Create a new flow run.
|
3494
|
+
|
3495
|
+
Args:
|
3496
|
+
- flow_id (UUID): the ID of the flow to create a run for
|
3497
|
+
- parameters (Optional[Dict[str, Any]]): a dictionary of parameter values to pass to the flow
|
3498
|
+
- context (Optional[Dict[str, Any]]): a dictionary of context values to pass to the flow
|
3499
|
+
- scheduled_start_time (Optional[datetime.datetime]): the scheduled start time for the flow run
|
3500
|
+
- run_name (Optional[str]): a name to assign to the flow run
|
3501
|
+
- labels (Optional[List[str]]): a list of labels to assign to the flow run
|
3502
|
+
- parameters_json (Optional[str]): a JSON string of parameter values to pass to the flow
|
3503
|
+
- run_config (Optional[Dict[str, Any]]): a dictionary of run configuration options
|
3504
|
+
- idempotency_key (Optional[str]): a key to ensure idempotency when creating the flow run
|
3505
|
+
|
3506
|
+
Returns:
|
3507
|
+
- FlowRunResponse: the created flow run
|
3508
|
+
"""
|
3509
|
+
return run_sync(
|
3510
|
+
self._prefect_client.create_flow_run(
|
3511
|
+
flow_id=flow_id,
|
3512
|
+
parameters=parameters,
|
3513
|
+
context=context,
|
3514
|
+
scheduled_start_time=scheduled_start_time,
|
3515
|
+
run_name=run_name,
|
3516
|
+
labels=labels,
|
3517
|
+
parameters_json=parameters_json,
|
3518
|
+
run_config=run_config,
|
3519
|
+
idempotency_key=idempotency_key,
|
3520
|
+
)
|
3521
|
+
)
|
3522
|
+
|
3523
|
+
async def set_flow_run_state(
|
3524
|
+
self,
|
3525
|
+
flow_run_id: UUID,
|
3526
|
+
state: "prefect.states.State",
|
3527
|
+
force: bool = False,
|
3528
|
+
) -> OrchestrationResult:
|
3529
|
+
"""
|
3530
|
+
Set the state of a flow run.
|
3531
|
+
|
3532
|
+
Args:
|
3533
|
+
flow_run_id: the id of the flow run
|
3534
|
+
state: the state to set
|
3535
|
+
force: if True, disregard orchestration logic when setting the state,
|
3536
|
+
forcing the Prefect API to accept the state
|
3537
|
+
|
3538
|
+
Returns:
|
3539
|
+
an OrchestrationResult model representation of state orchestration output
|
3540
|
+
"""
|
3541
|
+
return run_sync(
|
3542
|
+
self._prefect_client.set_flow_run_state(
|
3543
|
+
flow_run_id=flow_run_id,
|
3544
|
+
state=state,
|
3545
|
+
force=force,
|
3546
|
+
)
|
3547
|
+
)
|
@@ -8,9 +8,9 @@ from prefect._internal.compatibility.deprecated import DeprecatedInfraOverridesF
|
|
8
8
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
9
9
|
|
10
10
|
if HAS_PYDANTIC_V2:
|
11
|
-
from pydantic.v1 import Field,
|
11
|
+
from pydantic.v1 import Field, root_validator, validator
|
12
12
|
else:
|
13
|
-
from pydantic import Field,
|
13
|
+
from pydantic import Field, root_validator, validator
|
14
14
|
|
15
15
|
import prefect.client.schemas.objects as objects
|
16
16
|
from prefect._internal.schemas.bases import ActionBaseModel
|
@@ -26,6 +26,7 @@ from prefect._internal.schemas.validators import (
|
|
26
26
|
)
|
27
27
|
from prefect.client.schemas.objects import StateDetails, StateType
|
28
28
|
from prefect.client.schemas.schedules import SCHEDULE_TYPES
|
29
|
+
from prefect.types import NonNegativeInteger
|
29
30
|
from prefect.utilities.collections import listrepr
|
30
31
|
from prefect.utilities.pydantic import get_class_fields_only
|
31
32
|
|
@@ -525,7 +526,7 @@ class WorkPoolCreate(ActionBaseModel):
|
|
525
526
|
default=False,
|
526
527
|
description="Whether the work pool is paused.",
|
527
528
|
)
|
528
|
-
concurrency_limit: Optional[
|
529
|
+
concurrency_limit: Optional[NonNegativeInteger] = Field(
|
529
530
|
default=None, description="A concurrency limit for the work pool."
|
530
531
|
)
|
531
532
|
|