prefect-client 2.18.0__py3-none-any.whl → 2.18.2__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/schemas/fields.py +31 -12
- prefect/automations.py +162 -0
- prefect/blocks/core.py +1 -1
- prefect/blocks/notifications.py +2 -2
- prefect/blocks/system.py +2 -3
- prefect/client/orchestration.py +309 -30
- prefect/client/schemas/objects.py +11 -8
- 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/deployments.py +27 -18
- prefect/deployments/runner.py +34 -26
- prefect/engine.py +3 -1
- prefect/events/actions.py +2 -1
- prefect/events/cli/automations.py +207 -46
- prefect/events/clients.py +53 -20
- prefect/events/filters.py +31 -4
- prefect/events/instrument.py +40 -40
- prefect/events/related.py +2 -1
- prefect/events/schemas/automations.py +52 -7
- prefect/events/schemas/deployment_triggers.py +16 -228
- prefect/events/schemas/events.py +18 -11
- prefect/events/schemas/labelling.py +1 -1
- prefect/events/utilities.py +1 -1
- prefect/events/worker.py +10 -7
- prefect/flows.py +42 -24
- prefect/input/actions.py +9 -9
- prefect/input/run_input.py +51 -37
- prefect/new_flow_engine.py +444 -0
- prefect/new_task_engine.py +488 -0
- prefect/results.py +3 -2
- prefect/runner/runner.py +3 -2
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +45 -4
- prefect/settings.py +47 -0
- prefect/states.py +25 -19
- prefect/tasks.py +146 -19
- prefect/utilities/asyncutils.py +41 -0
- prefect/utilities/engine.py +6 -4
- prefect/utilities/schema_tools/validation.py +1 -1
- prefect/workers/process.py +2 -1
- {prefect_client-2.18.0.dist-info → prefect_client-2.18.2.dist-info}/METADATA +1 -1
- {prefect_client-2.18.0.dist-info → prefect_client-2.18.2.dist-info}/RECORD +48 -46
- prefect/concurrency/common.py +0 -0
- {prefect_client-2.18.0.dist-info → prefect_client-2.18.2.dist-info}/LICENSE +0 -0
- {prefect_client-2.18.0.dist-info → prefect_client-2.18.2.dist-info}/WHEEL +0 -0
- {prefect_client-2.18.0.dist-info → prefect_client-2.18.2.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,13 @@ import anyio
|
|
16
16
|
import pendulum
|
17
17
|
import yaml
|
18
18
|
|
19
|
+
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
20
|
+
|
21
|
+
if HAS_PYDANTIC_V2:
|
22
|
+
from pydantic.v1 import BaseModel, Field, parse_obj_as, root_validator, validator
|
23
|
+
else:
|
24
|
+
from pydantic import BaseModel, Field, parse_obj_as, root_validator, validator
|
25
|
+
|
19
26
|
from prefect._internal.compatibility.deprecated import (
|
20
27
|
DeprecatedInfraOverridesField,
|
21
28
|
deprecated_callable,
|
@@ -23,7 +30,6 @@ from prefect._internal.compatibility.deprecated import (
|
|
23
30
|
deprecated_parameter,
|
24
31
|
handle_deprecated_infra_overrides_parameter,
|
25
32
|
)
|
26
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
27
33
|
from prefect._internal.schemas.validators import (
|
28
34
|
handle_openapi_schema,
|
29
35
|
infrastructure_must_have_capabilities,
|
@@ -32,16 +38,10 @@ from prefect._internal.schemas.validators import (
|
|
32
38
|
validate_automation_names,
|
33
39
|
validate_deprecated_schedule_fields,
|
34
40
|
)
|
35
|
-
from prefect.client.schemas.actions import DeploymentScheduleCreate
|
36
|
-
|
37
|
-
if HAS_PYDANTIC_V2:
|
38
|
-
from pydantic.v1 import BaseModel, Field, parse_obj_as, root_validator, validator
|
39
|
-
else:
|
40
|
-
from pydantic import BaseModel, Field, parse_obj_as, root_validator, validator
|
41
|
-
|
42
41
|
from prefect.blocks.core import Block
|
43
42
|
from prefect.blocks.fields import SecretDict
|
44
43
|
from prefect.client.orchestration import PrefectClient, get_client
|
44
|
+
from prefect.client.schemas.actions import DeploymentScheduleCreate
|
45
45
|
from prefect.client.schemas.objects import (
|
46
46
|
FlowRun,
|
47
47
|
MinimalDeploymentSchedule,
|
@@ -53,11 +53,12 @@ from prefect.deployments.schedules import (
|
|
53
53
|
FlexibleScheduleList,
|
54
54
|
)
|
55
55
|
from prefect.deployments.steps.core import run_steps
|
56
|
-
from prefect.events import DeploymentTriggerTypes
|
56
|
+
from prefect.events import DeploymentTriggerTypes, TriggerTypes
|
57
57
|
from prefect.exceptions import (
|
58
58
|
BlockMissingCapabilities,
|
59
59
|
ObjectAlreadyExists,
|
60
60
|
ObjectNotFound,
|
61
|
+
PrefectHTTPStatusError,
|
61
62
|
)
|
62
63
|
from prefect.filesystems import LocalFileSystem
|
63
64
|
from prefect.flows import Flow, load_flow_from_entrypoint
|
@@ -609,7 +610,7 @@ class Deployment(DeprecatedInfraOverridesField, BaseModel):
|
|
609
610
|
description="The parameter schema of the flow, including defaults.",
|
610
611
|
)
|
611
612
|
timestamp: datetime = Field(default_factory=partial(pendulum.now, "UTC"))
|
612
|
-
triggers: List[DeploymentTriggerTypes] = Field(
|
613
|
+
triggers: List[Union[DeploymentTriggerTypes, TriggerTypes]] = Field(
|
613
614
|
default_factory=list,
|
614
615
|
description="The triggers that should cause this deployment to run.",
|
615
616
|
)
|
@@ -902,14 +903,22 @@ class Deployment(DeprecatedInfraOverridesField, BaseModel):
|
|
902
903
|
)
|
903
904
|
|
904
905
|
if client.server_type.supports_automations():
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
906
|
+
try:
|
907
|
+
# The triggers defined in the deployment spec are, essentially,
|
908
|
+
# anonymous and attempting truly sync them with cloud is not
|
909
|
+
# feasible. Instead, we remove all automations that are owned
|
910
|
+
# by the deployment, meaning that they were created via this
|
911
|
+
# mechanism below, and then recreate them.
|
912
|
+
await client.delete_resource_owned_automations(
|
913
|
+
f"prefect.deployment.{deployment_id}"
|
914
|
+
)
|
915
|
+
except PrefectHTTPStatusError as e:
|
916
|
+
if e.response.status_code == 404:
|
917
|
+
# This Prefect server does not support automations, so we can safely
|
918
|
+
# ignore this 404 and move on.
|
919
|
+
return deployment_id
|
920
|
+
raise e
|
921
|
+
|
913
922
|
for trigger in self.triggers:
|
914
923
|
trigger.set_deployment_id(deployment_id)
|
915
924
|
await client.create_automation(trigger.as_automation())
|
prefect/deployments/runner.py
CHANGED
@@ -42,26 +42,19 @@ from rich.console import Console
|
|
42
42
|
from rich.progress import Progress, SpinnerColumn, TextColumn, track
|
43
43
|
from rich.table import Table
|
44
44
|
|
45
|
-
from prefect._internal.concurrency.api import create_call, from_async
|
46
45
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
47
|
-
from prefect._internal.schemas.validators import (
|
48
|
-
reconcile_paused_deployment,
|
49
|
-
reconcile_schedules_runner,
|
50
|
-
validate_automation_names,
|
51
|
-
)
|
52
|
-
from prefect.runner.storage import RunnerStorage
|
53
|
-
from prefect.settings import (
|
54
|
-
PREFECT_DEFAULT_DOCKER_BUILD_NAMESPACE,
|
55
|
-
PREFECT_DEFAULT_WORK_POOL_NAME,
|
56
|
-
PREFECT_UI_URL,
|
57
|
-
)
|
58
|
-
from prefect.utilities.collections import get_from_dict, isiterable
|
59
46
|
|
60
47
|
if HAS_PYDANTIC_V2:
|
61
48
|
from pydantic.v1 import BaseModel, Field, PrivateAttr, root_validator, validator
|
62
49
|
else:
|
63
50
|
from pydantic import BaseModel, Field, PrivateAttr, root_validator, validator
|
64
51
|
|
52
|
+
from prefect._internal.concurrency.api import create_call, from_async
|
53
|
+
from prefect._internal.schemas.validators import (
|
54
|
+
reconcile_paused_deployment,
|
55
|
+
reconcile_schedules_runner,
|
56
|
+
validate_automation_names,
|
57
|
+
)
|
65
58
|
from prefect.client.orchestration import get_client
|
66
59
|
from prefect.client.schemas.objects import MinimalDeploymentSchedule
|
67
60
|
from prefect.client.schemas.schedules import (
|
@@ -72,13 +65,20 @@ from prefect.deployments.schedules import (
|
|
72
65
|
FlexibleScheduleList,
|
73
66
|
create_minimal_deployment_schedule,
|
74
67
|
)
|
75
|
-
from prefect.events import DeploymentTriggerTypes
|
68
|
+
from prefect.events import DeploymentTriggerTypes, TriggerTypes
|
76
69
|
from prefect.exceptions import (
|
77
70
|
ObjectNotFound,
|
78
71
|
PrefectHTTPStatusError,
|
79
72
|
)
|
73
|
+
from prefect.runner.storage import RunnerStorage
|
74
|
+
from prefect.settings import (
|
75
|
+
PREFECT_DEFAULT_DOCKER_BUILD_NAMESPACE,
|
76
|
+
PREFECT_DEFAULT_WORK_POOL_NAME,
|
77
|
+
PREFECT_UI_URL,
|
78
|
+
)
|
80
79
|
from prefect.utilities.asyncutils import sync_compatible
|
81
80
|
from prefect.utilities.callables import ParameterSchema, parameter_schema
|
81
|
+
from prefect.utilities.collections import get_from_dict, isiterable
|
82
82
|
from prefect.utilities.dockerutils import (
|
83
83
|
PushError,
|
84
84
|
build_image,
|
@@ -179,7 +179,7 @@ class RunnerDeployment(BaseModel):
|
|
179
179
|
"The path to the entrypoint for the workflow, relative to the `path`."
|
180
180
|
),
|
181
181
|
)
|
182
|
-
triggers: List[DeploymentTriggerTypes] = Field(
|
182
|
+
triggers: List[Union[DeploymentTriggerTypes, TriggerTypes]] = Field(
|
183
183
|
default_factory=list,
|
184
184
|
description="The triggers that should cause this deployment to run.",
|
185
185
|
)
|
@@ -326,14 +326,22 @@ class RunnerDeployment(BaseModel):
|
|
326
326
|
) from exc
|
327
327
|
|
328
328
|
if client.server_type.supports_automations():
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
329
|
+
try:
|
330
|
+
# The triggers defined in the deployment spec are, essentially,
|
331
|
+
# anonymous and attempting truly sync them with cloud is not
|
332
|
+
# feasible. Instead, we remove all automations that are owned
|
333
|
+
# by the deployment, meaning that they were created via this
|
334
|
+
# mechanism below, and then recreate them.
|
335
|
+
await client.delete_resource_owned_automations(
|
336
|
+
f"prefect.deployment.{deployment_id}"
|
337
|
+
)
|
338
|
+
except PrefectHTTPStatusError as e:
|
339
|
+
if e.response.status_code == 404:
|
340
|
+
# This Prefect server does not support automations, so we can safely
|
341
|
+
# ignore this 404 and move on.
|
342
|
+
return deployment_id
|
343
|
+
raise e
|
344
|
+
|
337
345
|
for trigger in self.triggers:
|
338
346
|
trigger.set_deployment_id(deployment_id)
|
339
347
|
await client.create_automation(trigger.as_automation())
|
@@ -446,7 +454,7 @@ class RunnerDeployment(BaseModel):
|
|
446
454
|
schedule: Optional[SCHEDULE_TYPES] = None,
|
447
455
|
is_schedule_active: Optional[bool] = None,
|
448
456
|
parameters: Optional[dict] = None,
|
449
|
-
triggers: Optional[List[DeploymentTriggerTypes]] = None,
|
457
|
+
triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
450
458
|
description: Optional[str] = None,
|
451
459
|
tags: Optional[List[str]] = None,
|
452
460
|
version: Optional[str] = None,
|
@@ -582,7 +590,7 @@ class RunnerDeployment(BaseModel):
|
|
582
590
|
schedule: Optional[SCHEDULE_TYPES] = None,
|
583
591
|
is_schedule_active: Optional[bool] = None,
|
584
592
|
parameters: Optional[dict] = None,
|
585
|
-
triggers: Optional[List[DeploymentTriggerTypes]] = None,
|
593
|
+
triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
586
594
|
description: Optional[str] = None,
|
587
595
|
tags: Optional[List[str]] = None,
|
588
596
|
version: Optional[str] = None,
|
@@ -680,7 +688,7 @@ class RunnerDeployment(BaseModel):
|
|
680
688
|
schedule: Optional[SCHEDULE_TYPES] = None,
|
681
689
|
is_schedule_active: Optional[bool] = None,
|
682
690
|
parameters: Optional[dict] = None,
|
683
|
-
triggers: Optional[List[DeploymentTriggerTypes]] = None,
|
691
|
+
triggers: Optional[List[Union[DeploymentTriggerTypes, TriggerTypes]]] = None,
|
684
692
|
description: Optional[str] = None,
|
685
693
|
tags: Optional[List[str]] = None,
|
686
694
|
version: Optional[str] = None,
|
prefect/engine.py
CHANGED
@@ -1410,7 +1410,9 @@ def enter_task_run_engine(
|
|
1410
1410
|
task_runner=task_runner,
|
1411
1411
|
)
|
1412
1412
|
|
1413
|
-
if task.isasync and
|
1413
|
+
if task.isasync and (
|
1414
|
+
flow_run_context.flow is None or flow_run_context.flow.isasync
|
1415
|
+
):
|
1414
1416
|
# return a coro for the user to await if an async task in an async flow
|
1415
1417
|
return from_async.wait_for_call_in_loop_thread(begin_run)
|
1416
1418
|
else:
|
prefect/events/actions.py
CHANGED
@@ -9,7 +9,8 @@ from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
|
9
9
|
if HAS_PYDANTIC_V2:
|
10
10
|
from pydantic.v1 import Field, root_validator
|
11
11
|
else:
|
12
|
-
from pydantic import Field, root_validator
|
12
|
+
from pydantic import Field, root_validator # type: ignore
|
13
|
+
|
13
14
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
14
15
|
from prefect.client.schemas.objects import StateType
|
15
16
|
|
@@ -3,8 +3,11 @@ Command line interface for working with automations.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import functools
|
6
|
+
from typing import Optional
|
7
|
+
from uuid import UUID
|
6
8
|
|
7
9
|
import orjson
|
10
|
+
import typer
|
8
11
|
import yaml as pyyaml
|
9
12
|
from rich.pretty import Pretty
|
10
13
|
from rich.table import Table
|
@@ -14,6 +17,8 @@ from prefect.cli._types import PrefectTyper
|
|
14
17
|
from prefect.cli._utilities import exit_with_error, exit_with_success
|
15
18
|
from prefect.cli.root import app
|
16
19
|
from prefect.client.orchestration import get_client
|
20
|
+
from prefect.events.schemas.automations import Automation
|
21
|
+
from prefect.exceptions import PrefectHTTPStatusError
|
17
22
|
|
18
23
|
automations_app = PrefectTyper(
|
19
24
|
name="automation",
|
@@ -96,68 +101,224 @@ async def ls():
|
|
96
101
|
|
97
102
|
@automations_app.command()
|
98
103
|
@requires_automations
|
99
|
-
async def inspect(
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
104
|
+
async def inspect(
|
105
|
+
name: Optional[str] = typer.Argument(None, help="An automation's name"),
|
106
|
+
id: Optional[str] = typer.Option(None, "--id", help="An automation's id"),
|
107
|
+
yaml: bool = typer.Option(False, "--yaml", help="Output as YAML"),
|
108
|
+
json: bool = typer.Option(False, "--json", help="Output as JSON"),
|
109
|
+
):
|
110
|
+
"""
|
111
|
+
Inspect an automation.
|
112
|
+
|
113
|
+
Arguments:
|
114
|
+
|
115
|
+
name: the name of the automation to inspect
|
116
|
+
|
117
|
+
id: the id of the automation to inspect
|
118
|
+
|
119
|
+
yaml: output as YAML
|
120
|
+
|
121
|
+
json: output as JSON
|
122
|
+
|
123
|
+
Examples:
|
124
|
+
|
125
|
+
$ prefect automation inspect "my-automation"
|
126
|
+
|
127
|
+
$ prefect automation inspect --id "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
128
|
+
|
129
|
+
$ prefect automation inspect "my-automation" --yaml
|
130
|
+
|
131
|
+
$ prefect automation inspect "my-automation" --json
|
132
|
+
"""
|
133
|
+
if not id and not name:
|
134
|
+
exit_with_error("Please provide either a name or an id.")
|
135
|
+
|
136
|
+
if name:
|
137
|
+
async with get_client() as client:
|
138
|
+
automation = await client.read_automations_by_name(name=name)
|
139
|
+
if not automation:
|
140
|
+
exit_with_error(f"Automation {name!r} not found.")
|
141
|
+
|
142
|
+
elif id:
|
143
|
+
async with get_client() as client:
|
144
|
+
try:
|
145
|
+
uuid_id = UUID(id)
|
146
|
+
automation = await client.read_automation(uuid_id)
|
147
|
+
except (PrefectHTTPStatusError, ValueError):
|
148
|
+
exit_with_error(f"Automation with id {id!r} not found.")
|
149
|
+
|
150
|
+
if yaml or json:
|
151
|
+
if isinstance(automation, list):
|
152
|
+
automation = [a.dict(json_compatible=True) for a in automation]
|
153
|
+
elif isinstance(automation, Automation):
|
154
|
+
automation = automation.dict(json_compatible=True)
|
155
|
+
if yaml:
|
156
|
+
app.console.print(pyyaml.dump(automation, sort_keys=False))
|
157
|
+
elif json:
|
158
|
+
app.console.print(
|
159
|
+
orjson.dumps(automation, option=orjson.OPT_INDENT_2).decode()
|
160
|
+
)
|
116
161
|
else:
|
117
162
|
app.console.print(Pretty(automation))
|
118
163
|
|
119
164
|
|
120
165
|
@automations_app.command(aliases=["enable"])
|
121
166
|
@requires_automations
|
122
|
-
async def resume(
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
167
|
+
async def resume(
|
168
|
+
name: Optional[str] = typer.Argument(None, help="An automation's name"),
|
169
|
+
id: Optional[str] = typer.Option(None, "--id", help="An automation's id"),
|
170
|
+
):
|
171
|
+
"""
|
172
|
+
Resume an automation.
|
173
|
+
|
174
|
+
Arguments:
|
175
|
+
|
176
|
+
name: the name of the automation to resume
|
177
|
+
|
178
|
+
id: the id of the automation to resume
|
179
|
+
|
180
|
+
Examples:
|
181
|
+
|
182
|
+
$ prefect automation resume "my-automation"
|
183
|
+
|
184
|
+
$ prefect automation resume --id "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
185
|
+
"""
|
186
|
+
if not id and not name:
|
187
|
+
exit_with_error("Please provide either a name or an id.")
|
188
|
+
|
189
|
+
if name:
|
190
|
+
async with get_client() as client:
|
191
|
+
automation = await client.read_automations_by_name(name=name)
|
192
|
+
if not automation:
|
193
|
+
exit_with_error(
|
194
|
+
f"Automation with name {name!r} not found. You can also specify an id with the `--id` flag."
|
195
|
+
)
|
196
|
+
if len(automation) > 1:
|
197
|
+
if not typer.confirm(
|
198
|
+
f"Multiple automations found with name {name!r}. Do you want to resume all of them?",
|
199
|
+
default=False,
|
200
|
+
):
|
201
|
+
exit_with_error("Resume aborted.")
|
202
|
+
|
203
|
+
for a in automation:
|
204
|
+
await client.resume_automation(a.id)
|
205
|
+
exit_with_success(
|
206
|
+
f"Resumed automation(s) with name {name!r} and id(s) {', '.join([repr(str(a.id)) for a in automation])}."
|
207
|
+
)
|
131
208
|
|
132
|
-
|
209
|
+
elif id:
|
210
|
+
async with get_client() as client:
|
211
|
+
try:
|
212
|
+
uuid_id = UUID(id)
|
213
|
+
automation = await client.read_automation(uuid_id)
|
214
|
+
except (PrefectHTTPStatusError, ValueError):
|
215
|
+
exit_with_error(f"Automation with id {id!r} not found.")
|
216
|
+
await client.resume_automation(automation.id)
|
217
|
+
exit_with_success(f"Resumed automation with id {str(automation.id)!r}.")
|
133
218
|
|
134
219
|
|
135
220
|
@automations_app.command(aliases=["disable"])
|
136
221
|
@requires_automations
|
137
|
-
async def pause(
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
222
|
+
async def pause(
|
223
|
+
name: Optional[str] = typer.Argument(None, help="An automation's name"),
|
224
|
+
id: Optional[str] = typer.Option(None, "--id", help="An automation's id"),
|
225
|
+
):
|
226
|
+
"""
|
227
|
+
Pause an automation.
|
228
|
+
|
229
|
+
Arguments:
|
230
|
+
|
231
|
+
name: the name of the automation to pause
|
232
|
+
|
233
|
+
id: the id of the automation to pause
|
234
|
+
|
235
|
+
Examples:
|
236
|
+
|
237
|
+
$ prefect automation pause "my-automation"
|
238
|
+
|
239
|
+
$ prefect automation pause --id "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
240
|
+
"""
|
241
|
+
if not id and not name:
|
242
|
+
exit_with_error("Please provide either a name or an id.")
|
243
|
+
|
244
|
+
if name:
|
245
|
+
async with get_client() as client:
|
246
|
+
automation = await client.read_automations_by_name(name=name)
|
247
|
+
if not automation:
|
248
|
+
exit_with_error(
|
249
|
+
f"Automation with name {name!r} not found. You can also specify an id with the `--id` flag."
|
250
|
+
)
|
251
|
+
if len(automation) > 1:
|
252
|
+
if not typer.confirm(
|
253
|
+
f"Multiple automations found with name {name!r}. Do you want to pause all of them?",
|
254
|
+
default=False,
|
255
|
+
):
|
256
|
+
exit_with_error("Pause aborted.")
|
257
|
+
|
258
|
+
for a in automation:
|
259
|
+
await client.pause_automation(a.id)
|
260
|
+
exit_with_success(
|
261
|
+
f"Paused automation(s) with name {name!r} and id(s) {', '.join([repr(str(a.id)) for a in automation])}."
|
262
|
+
)
|
146
263
|
|
147
|
-
|
264
|
+
elif id:
|
265
|
+
async with get_client() as client:
|
266
|
+
try:
|
267
|
+
uuid_id = UUID(id)
|
268
|
+
automation = await client.read_automation(uuid_id)
|
269
|
+
except (PrefectHTTPStatusError, ValueError):
|
270
|
+
exit_with_error(f"Automation with id {id!r} not found.")
|
271
|
+
await client.pause_automation(automation.id)
|
272
|
+
exit_with_success(f"Paused automation with id {str(automation.id)!r}.")
|
148
273
|
|
149
274
|
|
150
275
|
@automations_app.command()
|
151
276
|
@requires_automations
|
152
|
-
async def delete(
|
153
|
-
|
154
|
-
|
155
|
-
|
277
|
+
async def delete(
|
278
|
+
name: Optional[str] = typer.Argument(None, help="An automation's name"),
|
279
|
+
id: Optional[str] = typer.Option(None, "--id", help="An automation's id"),
|
280
|
+
):
|
281
|
+
"""Delete an automation.
|
156
282
|
|
157
|
-
|
158
|
-
|
283
|
+
Arguments:
|
284
|
+
name: the name of the automation to delete
|
285
|
+
id: the id of the automation to delete
|
159
286
|
|
160
|
-
|
161
|
-
|
287
|
+
Examples:
|
288
|
+
$ prefect automation delete "my-automation"
|
289
|
+
$ prefect automation delete --id "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
|
290
|
+
"""
|
162
291
|
|
163
|
-
|
292
|
+
async with get_client() as client:
|
293
|
+
if not id and not name:
|
294
|
+
exit_with_error("Please provide either a name or an id.")
|
295
|
+
|
296
|
+
if id:
|
297
|
+
automation = await client.read_automation(id)
|
298
|
+
if not automation:
|
299
|
+
exit_with_error(f"Automation with id {id!r} not found.")
|
300
|
+
if not typer.confirm(
|
301
|
+
(f"Are you sure you want to delete automation with id {id!r}?"),
|
302
|
+
default=False,
|
303
|
+
):
|
304
|
+
exit_with_error("Deletion aborted.")
|
305
|
+
await client.delete_automation(id)
|
306
|
+
exit_with_success(f"Deleted automation with id {id!r}")
|
307
|
+
|
308
|
+
elif name:
|
309
|
+
automation = await client.read_automations_by_name(name=name)
|
310
|
+
if not automation:
|
311
|
+
exit_with_error(
|
312
|
+
f"Automation {name!r} not found. You can also specify an id with the `--id` flag."
|
313
|
+
)
|
314
|
+
elif len(automation) > 1:
|
315
|
+
exit_with_error(
|
316
|
+
f"Multiple automations found with name {name!r}. Please specify an id with the `--id` flag instead."
|
317
|
+
)
|
318
|
+
if not typer.confirm(
|
319
|
+
(f"Are you sure you want to delete automation with name {name!r}?"),
|
320
|
+
default=False,
|
321
|
+
):
|
322
|
+
exit_with_error("Deletion aborted.")
|
323
|
+
await client.delete_automation(automation[0].id)
|
324
|
+
exit_with_success(f"Deleted automation with name {name!r}")
|