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
@@ -1,4 +1,5 @@
|
|
1
1
|
import abc
|
2
|
+
import textwrap
|
2
3
|
from datetime import timedelta
|
3
4
|
from enum import Enum
|
4
5
|
from typing import (
|
@@ -9,23 +10,24 @@ from typing import (
|
|
9
10
|
Optional,
|
10
11
|
Set,
|
11
12
|
Union,
|
13
|
+
cast,
|
12
14
|
)
|
13
15
|
from uuid import UUID
|
14
16
|
|
15
17
|
from typing_extensions import TypeAlias
|
16
18
|
|
17
19
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
18
|
-
from prefect._internal.schemas.validators import validate_trigger_within
|
19
20
|
|
20
21
|
if HAS_PYDANTIC_V2:
|
21
|
-
from pydantic.v1 import Field, root_validator, validator
|
22
|
+
from pydantic.v1 import Field, PrivateAttr, root_validator, validator
|
22
23
|
from pydantic.v1.fields import ModelField
|
23
24
|
else:
|
24
|
-
from pydantic import Field, root_validator, validator
|
25
|
-
from pydantic.fields import ModelField
|
25
|
+
from pydantic import Field, PrivateAttr, root_validator, validator # type: ignore
|
26
|
+
from pydantic.fields import ModelField # type: ignore
|
26
27
|
|
27
28
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
28
|
-
from prefect.
|
29
|
+
from prefect._internal.schemas.validators import validate_trigger_within
|
30
|
+
from prefect.events.actions import ActionTypes, RunDeployment
|
29
31
|
from prefect.utilities.collections import AutoEnum
|
30
32
|
|
31
33
|
from .events import ResourceSpecification
|
@@ -45,6 +47,54 @@ class Trigger(PrefectBaseModel, abc.ABC, extra="ignore"):
|
|
45
47
|
|
46
48
|
type: str
|
47
49
|
|
50
|
+
@abc.abstractmethod
|
51
|
+
def describe_for_cli(self, indent: int = 0) -> str:
|
52
|
+
"""Return a human-readable description of this trigger for the CLI"""
|
53
|
+
|
54
|
+
# The following allows the regular Trigger class to be used when serving or
|
55
|
+
# deploying flows, analogous to how the Deployment*Trigger classes work
|
56
|
+
|
57
|
+
_deployment_id: Optional[UUID] = PrivateAttr(default=None)
|
58
|
+
|
59
|
+
def set_deployment_id(self, deployment_id: UUID):
|
60
|
+
self._deployment_id = deployment_id
|
61
|
+
|
62
|
+
def owner_resource(self) -> Optional[str]:
|
63
|
+
return f"prefect.deployment.{self._deployment_id}"
|
64
|
+
|
65
|
+
def actions(self) -> List[ActionTypes]:
|
66
|
+
assert self._deployment_id
|
67
|
+
return [
|
68
|
+
RunDeployment(
|
69
|
+
source="selected",
|
70
|
+
deployment_id=self._deployment_id,
|
71
|
+
parameters=getattr(self, "parameters", None),
|
72
|
+
job_variables=getattr(self, "job_variables", None),
|
73
|
+
)
|
74
|
+
]
|
75
|
+
|
76
|
+
def as_automation(self) -> "AutomationCore":
|
77
|
+
assert self._deployment_id
|
78
|
+
|
79
|
+
trigger: TriggerTypes = cast(TriggerTypes, self)
|
80
|
+
|
81
|
+
# This is one of the Deployment*Trigger classes, so translate it over to a
|
82
|
+
# plain Trigger
|
83
|
+
if hasattr(self, "trigger_type"):
|
84
|
+
trigger = self.trigger_type(**self.dict())
|
85
|
+
|
86
|
+
return AutomationCore(
|
87
|
+
name=(
|
88
|
+
getattr(self, "name", None)
|
89
|
+
or f"Automation for deployment {self._deployment_id}"
|
90
|
+
),
|
91
|
+
description="",
|
92
|
+
enabled=getattr(self, "enabled", True),
|
93
|
+
trigger=trigger,
|
94
|
+
actions=self.actions(),
|
95
|
+
owner_resource=self.owner_resource(),
|
96
|
+
)
|
97
|
+
|
48
98
|
|
49
99
|
class ResourceTrigger(Trigger, abc.ABC):
|
50
100
|
"""
|
@@ -101,7 +151,7 @@ class EventTrigger(ResourceTrigger):
|
|
101
151
|
),
|
102
152
|
)
|
103
153
|
posture: Literal[Posture.Reactive, Posture.Proactive] = Field( # type: ignore[valid-type]
|
104
|
-
|
154
|
+
Posture.Reactive,
|
105
155
|
description=(
|
106
156
|
"The posture of this trigger, either Reactive or Proactive. Reactive "
|
107
157
|
"triggers respond to the _presence_ of the expected events, while "
|
@@ -148,6 +198,28 @@ class EventTrigger(ResourceTrigger):
|
|
148
198
|
|
149
199
|
return values
|
150
200
|
|
201
|
+
def describe_for_cli(self, indent: int = 0) -> str:
|
202
|
+
"""Return a human-readable description of this trigger for the CLI"""
|
203
|
+
if self.posture == Posture.Reactive:
|
204
|
+
return textwrap.indent(
|
205
|
+
"\n".join(
|
206
|
+
[
|
207
|
+
f"Reactive: expecting {self.threshold} of {self.expect}",
|
208
|
+
],
|
209
|
+
),
|
210
|
+
prefix=" " * indent,
|
211
|
+
)
|
212
|
+
else:
|
213
|
+
return textwrap.indent(
|
214
|
+
"\n".join(
|
215
|
+
[
|
216
|
+
f"Proactive: expecting {self.threshold} {self.expect} event "
|
217
|
+
f"within {self.within}",
|
218
|
+
],
|
219
|
+
),
|
220
|
+
prefix=" " * indent,
|
221
|
+
)
|
222
|
+
|
151
223
|
|
152
224
|
class MetricTriggerOperator(Enum):
|
153
225
|
LT = "<"
|
@@ -224,6 +296,18 @@ class MetricTrigger(ResourceTrigger):
|
|
224
296
|
description="The metric query to evaluate for this trigger. ",
|
225
297
|
)
|
226
298
|
|
299
|
+
def describe_for_cli(self, indent: int = 0) -> str:
|
300
|
+
"""Return a human-readable description of this trigger for the CLI"""
|
301
|
+
m = self.metric
|
302
|
+
return textwrap.indent(
|
303
|
+
"\n".join(
|
304
|
+
[
|
305
|
+
f"Metric: {m.name.value} {m.operator.value} {m.threshold} for {m.range}",
|
306
|
+
]
|
307
|
+
),
|
308
|
+
prefix=" " * indent,
|
309
|
+
)
|
310
|
+
|
227
311
|
|
228
312
|
class CompositeTrigger(Trigger, abc.ABC):
|
229
313
|
"""
|
@@ -256,6 +340,23 @@ class CompoundTrigger(CompositeTrigger):
|
|
256
340
|
|
257
341
|
return values
|
258
342
|
|
343
|
+
def describe_for_cli(self, indent: int = 0) -> str:
|
344
|
+
"""Return a human-readable description of this trigger for the CLI"""
|
345
|
+
return textwrap.indent(
|
346
|
+
"\n".join(
|
347
|
+
[
|
348
|
+
f"{str(self.require).capitalize()} of:",
|
349
|
+
"\n".join(
|
350
|
+
[
|
351
|
+
trigger.describe_for_cli(indent=indent + 1)
|
352
|
+
for trigger in self.triggers
|
353
|
+
]
|
354
|
+
),
|
355
|
+
]
|
356
|
+
),
|
357
|
+
prefix=" " * indent,
|
358
|
+
)
|
359
|
+
|
259
360
|
|
260
361
|
class SequenceTrigger(CompositeTrigger):
|
261
362
|
"""A composite trigger that requires some number of triggers to have fired
|
@@ -263,6 +364,23 @@ class SequenceTrigger(CompositeTrigger):
|
|
263
364
|
|
264
365
|
type: Literal["sequence"] = "sequence"
|
265
366
|
|
367
|
+
def describe_for_cli(self, indent: int = 0) -> str:
|
368
|
+
"""Return a human-readable description of this trigger for the CLI"""
|
369
|
+
return textwrap.indent(
|
370
|
+
"\n".join(
|
371
|
+
[
|
372
|
+
"In this order:",
|
373
|
+
"\n".join(
|
374
|
+
[
|
375
|
+
trigger.describe_for_cli(indent=indent + 1)
|
376
|
+
for trigger in self.triggers
|
377
|
+
]
|
378
|
+
),
|
379
|
+
]
|
380
|
+
),
|
381
|
+
prefix=" " * indent,
|
382
|
+
)
|
383
|
+
|
266
384
|
|
267
385
|
TriggerTypes: TypeAlias = Union[
|
268
386
|
EventTrigger, MetricTrigger, CompoundTrigger, SequenceTrigger
|
@@ -273,7 +391,7 @@ CompoundTrigger.update_forward_refs()
|
|
273
391
|
SequenceTrigger.update_forward_refs()
|
274
392
|
|
275
393
|
|
276
|
-
class
|
394
|
+
class AutomationCore(PrefectBaseModel, extra="ignore"):
|
277
395
|
"""Defines an action a user wants to take when a certain number of events
|
278
396
|
do or don't happen to the matching resources"""
|
279
397
|
|
@@ -310,5 +428,5 @@ class Automation(PrefectBaseModel, extra="ignore"):
|
|
310
428
|
)
|
311
429
|
|
312
430
|
|
313
|
-
class
|
431
|
+
class Automation(AutomationCore):
|
314
432
|
id: UUID = Field(..., description="The ID of this automation")
|
@@ -11,13 +11,11 @@ create them from YAML.
|
|
11
11
|
|
12
12
|
import abc
|
13
13
|
import textwrap
|
14
|
-
import warnings
|
15
14
|
from datetime import timedelta
|
16
15
|
from typing import (
|
17
16
|
Any,
|
18
17
|
Dict,
|
19
18
|
List,
|
20
|
-
Literal,
|
21
19
|
Optional,
|
22
20
|
Set,
|
23
21
|
Union,
|
@@ -26,38 +24,25 @@ from uuid import UUID
|
|
26
24
|
|
27
25
|
from typing_extensions import TypeAlias
|
28
26
|
|
29
|
-
from prefect._internal.compatibility.deprecated import deprecated_class
|
30
27
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
31
|
-
from prefect._internal.schemas.validators import validate_trigger_within
|
32
28
|
|
33
29
|
if HAS_PYDANTIC_V2:
|
34
|
-
from pydantic.v1 import Field, PrivateAttr
|
35
|
-
from pydantic.v1.fields import ModelField
|
30
|
+
from pydantic.v1 import Field, PrivateAttr
|
36
31
|
else:
|
37
|
-
from pydantic import Field, PrivateAttr
|
38
|
-
|
39
|
-
|
40
|
-
from prefect._internal.compatibility.experimental import (
|
41
|
-
EXPERIMENTAL_WARNING,
|
42
|
-
PREFECT_EXPERIMENTAL_WARN,
|
43
|
-
ExperimentalFeature,
|
44
|
-
experiment_enabled,
|
45
|
-
)
|
32
|
+
from pydantic import Field, PrivateAttr # type: ignore
|
33
|
+
|
34
|
+
from prefect._internal.compatibility.deprecated import deprecated_class
|
46
35
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
47
|
-
from prefect.events.actions import RunDeployment
|
48
|
-
from prefect.settings import (
|
49
|
-
PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES,
|
50
|
-
)
|
36
|
+
from prefect.events.actions import ActionTypes, RunDeployment
|
51
37
|
|
52
38
|
from .automations import (
|
53
|
-
|
39
|
+
AutomationCore,
|
54
40
|
CompoundTrigger,
|
55
41
|
EventTrigger,
|
56
42
|
MetricTrigger,
|
57
43
|
MetricTriggerQuery,
|
58
44
|
Posture,
|
59
45
|
SequenceTrigger,
|
60
|
-
Trigger,
|
61
46
|
TriggerTypes,
|
62
47
|
)
|
63
48
|
from .events import ResourceSpecification
|
@@ -77,11 +62,7 @@ class BaseDeploymentTrigger(PrefectBaseModel, abc.ABC, extra="ignore"):
|
|
77
62
|
description: str = Field("", description="A longer description of this automation")
|
78
63
|
enabled: bool = Field(True, description="Whether this automation will be evaluated")
|
79
64
|
|
80
|
-
# Fields from
|
81
|
-
|
82
|
-
type: str
|
83
|
-
|
84
|
-
# Fields from Deployment
|
65
|
+
# Fields from the RunDeployment action
|
85
66
|
|
86
67
|
parameters: Optional[Dict[str, Any]] = Field(
|
87
68
|
None,
|
@@ -97,256 +78,37 @@ class BaseDeploymentTrigger(PrefectBaseModel, abc.ABC, extra="ignore"):
|
|
97
78
|
"deployment's default job variables"
|
98
79
|
),
|
99
80
|
)
|
100
|
-
_deployment_id: Optional[UUID] = PrivateAttr(default=None)
|
101
|
-
|
102
|
-
def set_deployment_id(self, deployment_id: UUID):
|
103
|
-
self._deployment_id = deployment_id
|
104
|
-
|
105
|
-
def owner_resource(self) -> Optional[str]:
|
106
|
-
return f"prefect.deployment.{self._deployment_id}"
|
107
|
-
|
108
|
-
def actions(self) -> List[RunDeployment]:
|
109
|
-
if self.job_variables is not None and experiment_enabled(
|
110
|
-
"flow_run_infra_overrides"
|
111
|
-
):
|
112
|
-
if (
|
113
|
-
PREFECT_EXPERIMENTAL_WARN
|
114
|
-
and PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES
|
115
|
-
):
|
116
|
-
warnings.warn(
|
117
|
-
EXPERIMENTAL_WARNING.format(
|
118
|
-
feature="Flow run job variables",
|
119
|
-
group="flow_run_infra_overrides",
|
120
|
-
help="To use this feature, update your workers to Prefect 2.16.4 or later. ",
|
121
|
-
),
|
122
|
-
ExperimentalFeature,
|
123
|
-
stacklevel=3,
|
124
|
-
)
|
125
|
-
if not experiment_enabled("flow_run_infra_overrides"):
|
126
|
-
# nullify job_variables if the flag is disabled
|
127
|
-
self.job_variables = None
|
128
|
-
|
129
|
-
assert self._deployment_id
|
130
|
-
return [
|
131
|
-
RunDeployment(
|
132
|
-
parameters=self.parameters,
|
133
|
-
deployment_id=self._deployment_id,
|
134
|
-
job_variables=self.job_variables,
|
135
|
-
)
|
136
|
-
]
|
137
|
-
|
138
|
-
def as_automation(self) -> Automation:
|
139
|
-
if not self.name:
|
140
|
-
raise ValueError("name is required")
|
141
|
-
|
142
|
-
return Automation(
|
143
|
-
name=self.name,
|
144
|
-
description=self.description,
|
145
|
-
enabled=self.enabled,
|
146
|
-
trigger=self.as_trigger(),
|
147
|
-
actions=self.actions(),
|
148
|
-
owner_resource=self.owner_resource(),
|
149
|
-
)
|
150
|
-
|
151
|
-
@abc.abstractmethod
|
152
|
-
def as_trigger(self) -> Trigger:
|
153
|
-
...
|
154
|
-
|
155
|
-
|
156
|
-
class DeploymentResourceTrigger(BaseDeploymentTrigger, abc.ABC):
|
157
|
-
"""
|
158
|
-
Base class for triggers that may filter by the labels of resources.
|
159
|
-
"""
|
160
|
-
|
161
|
-
type: str
|
162
|
-
|
163
|
-
match: ResourceSpecification = Field(
|
164
|
-
default_factory=lambda: ResourceSpecification.parse_obj({}),
|
165
|
-
description="Labels for resources which this trigger will match.",
|
166
|
-
)
|
167
|
-
match_related: ResourceSpecification = Field(
|
168
|
-
default_factory=lambda: ResourceSpecification.parse_obj({}),
|
169
|
-
description="Labels for related resources which this trigger will match.",
|
170
|
-
)
|
171
81
|
|
172
82
|
|
173
|
-
class DeploymentEventTrigger(
|
83
|
+
class DeploymentEventTrigger(BaseDeploymentTrigger, EventTrigger):
|
174
84
|
"""
|
175
85
|
A trigger that fires based on the presence or absence of events within a given
|
176
86
|
period of time.
|
177
87
|
"""
|
178
88
|
|
179
|
-
|
180
|
-
|
181
|
-
after: Set[str] = Field(
|
182
|
-
default_factory=set,
|
183
|
-
description=(
|
184
|
-
"The event(s) which must first been seen to fire this trigger. If "
|
185
|
-
"empty, then fire this trigger immediately. Events may include "
|
186
|
-
"trailing wildcards, like `prefect.flow-run.*`"
|
187
|
-
),
|
188
|
-
)
|
189
|
-
expect: Set[str] = Field(
|
190
|
-
default_factory=set,
|
191
|
-
description=(
|
192
|
-
"The event(s) this trigger is expecting to see. If empty, this "
|
193
|
-
"trigger will match any event. Events may include trailing wildcards, "
|
194
|
-
"like `prefect.flow-run.*`"
|
195
|
-
),
|
196
|
-
)
|
197
|
-
|
198
|
-
for_each: Set[str] = Field(
|
199
|
-
default_factory=set,
|
200
|
-
description=(
|
201
|
-
"Evaluate the trigger separately for each distinct value of these labels "
|
202
|
-
"on the resource. By default, labels refer to the primary resource of the "
|
203
|
-
"triggering event. You may also refer to labels from related "
|
204
|
-
"resources by specifying `related:<role>:<label>`. This will use the "
|
205
|
-
"value of that label for the first related resource in that role. For "
|
206
|
-
'example, `"for_each": ["related:flow:prefect.resource.id"]` would '
|
207
|
-
"evaluate the trigger for each flow."
|
208
|
-
),
|
209
|
-
)
|
210
|
-
posture: Literal[Posture.Reactive, Posture.Proactive] = Field( # type: ignore[valid-type]
|
211
|
-
Posture.Reactive,
|
212
|
-
description=(
|
213
|
-
"The posture of this trigger, either Reactive or Proactive. Reactive "
|
214
|
-
"triggers respond to the _presence_ of the expected events, while "
|
215
|
-
"Proactive triggers respond to the _absence_ of those expected events."
|
216
|
-
),
|
217
|
-
)
|
218
|
-
threshold: int = Field(
|
219
|
-
1,
|
220
|
-
description=(
|
221
|
-
"The number of events required for this trigger to fire (for "
|
222
|
-
"Reactive triggers), or the number of events expected (for Proactive "
|
223
|
-
"triggers)"
|
224
|
-
),
|
225
|
-
)
|
226
|
-
within: timedelta = Field(
|
227
|
-
timedelta(0),
|
228
|
-
minimum=0.0,
|
229
|
-
exclusiveMinimum=False,
|
230
|
-
description=(
|
231
|
-
"The time period over which the events must occur. For Reactive triggers, "
|
232
|
-
"this may be as low as 0 seconds, but must be at least 10 seconds for "
|
233
|
-
"Proactive triggers"
|
234
|
-
),
|
235
|
-
)
|
236
|
-
|
237
|
-
@validator("within")
|
238
|
-
def enforce_minimum_within(
|
239
|
-
cls, value: timedelta, values, config, field: ModelField
|
240
|
-
):
|
241
|
-
return validate_trigger_within(value, field)
|
242
|
-
|
243
|
-
@root_validator(skip_on_failure=True)
|
244
|
-
def enforce_minimum_within_for_proactive_triggers(cls, values: Dict[str, Any]):
|
245
|
-
posture: Optional[Posture] = values.get("posture")
|
246
|
-
within: Optional[timedelta] = values.get("within")
|
247
|
-
|
248
|
-
if posture == Posture.Proactive:
|
249
|
-
if not within or within == timedelta(0):
|
250
|
-
values["within"] = timedelta(seconds=10.0)
|
251
|
-
elif within < timedelta(seconds=10.0):
|
252
|
-
raise ValueError(
|
253
|
-
"The minimum within for Proactive triggers is 10 seconds"
|
254
|
-
)
|
255
|
-
|
256
|
-
return values
|
257
|
-
|
258
|
-
def as_trigger(self) -> Trigger:
|
259
|
-
return EventTrigger(
|
260
|
-
match=self.match,
|
261
|
-
match_related=self.match_related,
|
262
|
-
after=self.after,
|
263
|
-
expect=self.expect,
|
264
|
-
for_each=self.for_each,
|
265
|
-
posture=self.posture,
|
266
|
-
threshold=self.threshold,
|
267
|
-
within=self.within,
|
268
|
-
)
|
89
|
+
trigger_type = EventTrigger
|
269
90
|
|
270
91
|
|
271
|
-
class DeploymentMetricTrigger(
|
92
|
+
class DeploymentMetricTrigger(BaseDeploymentTrigger, MetricTrigger):
|
272
93
|
"""
|
273
94
|
A trigger that fires based on the results of a metric query.
|
274
95
|
"""
|
275
96
|
|
276
|
-
|
277
|
-
|
278
|
-
posture: Literal[Posture.Metric] = Field( # type: ignore[valid-type]
|
279
|
-
Posture.Metric,
|
280
|
-
description="Periodically evaluate the configured metric query.",
|
281
|
-
)
|
282
|
-
|
283
|
-
metric: MetricTriggerQuery = Field(
|
284
|
-
...,
|
285
|
-
description="The metric query to evaluate for this trigger. ",
|
286
|
-
)
|
287
|
-
|
288
|
-
def as_trigger(self) -> Trigger:
|
289
|
-
return MetricTrigger(
|
290
|
-
match=self.match,
|
291
|
-
match_related=self.match_related,
|
292
|
-
posture=self.posture,
|
293
|
-
metric=self.metric,
|
294
|
-
job_variables=self.job_variables,
|
295
|
-
)
|
296
|
-
|
297
|
-
|
298
|
-
class DeploymentCompositeTrigger(BaseDeploymentTrigger, abc.ABC):
|
299
|
-
"""
|
300
|
-
Requires some number of triggers to have fired within the given time period.
|
301
|
-
"""
|
302
|
-
|
303
|
-
type: Literal["compound", "sequence"]
|
304
|
-
triggers: List["TriggerTypes"]
|
305
|
-
within: Optional[timedelta]
|
97
|
+
trigger_type = MetricTrigger
|
306
98
|
|
307
99
|
|
308
|
-
class DeploymentCompoundTrigger(
|
100
|
+
class DeploymentCompoundTrigger(BaseDeploymentTrigger, CompoundTrigger):
|
309
101
|
"""A composite trigger that requires some number of triggers to have
|
310
102
|
fired within the given time period"""
|
311
103
|
|
312
|
-
|
313
|
-
require: Union[int, Literal["any", "all"]]
|
314
|
-
|
315
|
-
@root_validator
|
316
|
-
def validate_require(cls, values: Dict[str, Any]) -> Dict[str, Any]:
|
317
|
-
require = values.get("require")
|
318
|
-
|
319
|
-
if isinstance(require, int):
|
320
|
-
if require < 1:
|
321
|
-
raise ValueError("required must be at least 1")
|
322
|
-
if require > len(values["triggers"]):
|
323
|
-
raise ValueError(
|
324
|
-
"required must be less than or equal to the number of triggers"
|
325
|
-
)
|
326
|
-
|
327
|
-
return values
|
328
|
-
|
329
|
-
def as_trigger(self) -> Trigger:
|
330
|
-
return CompoundTrigger(
|
331
|
-
require=self.require,
|
332
|
-
triggers=self.triggers,
|
333
|
-
within=self.within,
|
334
|
-
job_variables=self.job_variables,
|
335
|
-
)
|
104
|
+
trigger_type = CompoundTrigger
|
336
105
|
|
337
106
|
|
338
|
-
class DeploymentSequenceTrigger(
|
107
|
+
class DeploymentSequenceTrigger(BaseDeploymentTrigger, SequenceTrigger):
|
339
108
|
"""A composite trigger that requires some number of triggers to have fired
|
340
109
|
within the given time period in a specific order"""
|
341
110
|
|
342
|
-
|
343
|
-
|
344
|
-
def as_trigger(self) -> Trigger:
|
345
|
-
return SequenceTrigger(
|
346
|
-
triggers=self.triggers,
|
347
|
-
within=self.within,
|
348
|
-
job_variables=self.job_variables,
|
349
|
-
)
|
111
|
+
trigger_type = SequenceTrigger
|
350
112
|
|
351
113
|
|
352
114
|
# Concrete deployment trigger types
|
@@ -480,10 +242,13 @@ class DeploymentTrigger(PrefectBaseModel):
|
|
480
242
|
),
|
481
243
|
)
|
482
244
|
|
483
|
-
def as_automation(self) ->
|
245
|
+
def as_automation(self) -> AutomationCore:
|
484
246
|
assert self.name
|
485
247
|
|
248
|
+
trigger: TriggerTypes
|
249
|
+
|
486
250
|
if self.posture == Posture.Metric:
|
251
|
+
assert self.metric
|
487
252
|
trigger = MetricTrigger(
|
488
253
|
type="metric",
|
489
254
|
match=self.match,
|
@@ -503,7 +268,7 @@ class DeploymentTrigger(PrefectBaseModel):
|
|
503
268
|
within=self.within,
|
504
269
|
)
|
505
270
|
|
506
|
-
return
|
271
|
+
return AutomationCore(
|
507
272
|
name=self.name,
|
508
273
|
description=self.description,
|
509
274
|
enabled=self.enabled,
|
@@ -518,32 +283,13 @@ class DeploymentTrigger(PrefectBaseModel):
|
|
518
283
|
def owner_resource(self) -> Optional[str]:
|
519
284
|
return f"prefect.deployment.{self._deployment_id}"
|
520
285
|
|
521
|
-
def actions(self) -> List[
|
522
|
-
if self.job_variables is not None and experiment_enabled(
|
523
|
-
"flow_run_infra_overrides"
|
524
|
-
):
|
525
|
-
if (
|
526
|
-
PREFECT_EXPERIMENTAL_WARN
|
527
|
-
and PREFECT_EXPERIMENTAL_WARN_FLOW_RUN_INFRA_OVERRIDES
|
528
|
-
):
|
529
|
-
warnings.warn(
|
530
|
-
EXPERIMENTAL_WARNING.format(
|
531
|
-
feature="Flow run job variables",
|
532
|
-
group="flow_run_infra_overrides",
|
533
|
-
help="To use this feature, update your workers to Prefect 2.16.4 or later. ",
|
534
|
-
),
|
535
|
-
ExperimentalFeature,
|
536
|
-
stacklevel=3,
|
537
|
-
)
|
538
|
-
if not experiment_enabled("flow_run_infra_overrides"):
|
539
|
-
# nullify job_variables if the flag is disabled
|
540
|
-
self.job_variables = None
|
541
|
-
|
286
|
+
def actions(self) -> List[ActionTypes]:
|
542
287
|
assert self._deployment_id
|
543
288
|
return [
|
544
289
|
RunDeployment(
|
545
|
-
|
290
|
+
source="selected",
|
546
291
|
deployment_id=self._deployment_id,
|
292
|
+
parameters=self.parameters,
|
547
293
|
job_variables=self.job_variables,
|
548
294
|
)
|
549
295
|
]
|
prefect/events/schemas/events.py
CHANGED
@@ -15,9 +15,14 @@ from typing import (
|
|
15
15
|
from uuid import UUID, uuid4
|
16
16
|
|
17
17
|
import pendulum
|
18
|
-
from pydantic import Field, root_validator, validator
|
19
18
|
|
20
19
|
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
20
|
+
|
21
|
+
if HAS_PYDANTIC_V2:
|
22
|
+
from pydantic.v1 import Field, root_validator, validator
|
23
|
+
else:
|
24
|
+
from pydantic import Field, root_validator, validator # type: ignore
|
25
|
+
|
21
26
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
22
27
|
from prefect._internal.schemas.fields import DateTimeTZ
|
23
28
|
from prefect.logging import get_logger
|
@@ -26,11 +31,6 @@ from prefect.settings import (
|
|
26
31
|
PREFECT_EVENTS_MAXIMUM_RELATED_RESOURCES,
|
27
32
|
)
|
28
33
|
|
29
|
-
if HAS_PYDANTIC_V2:
|
30
|
-
from pydantic.v1 import Field, root_validator, validator
|
31
|
-
else:
|
32
|
-
from pydantic import Field, root_validator, validator
|
33
|
-
|
34
34
|
from .labelling import Labelled
|
35
35
|
|
36
36
|
logger = get_logger(__name__)
|
@@ -128,7 +128,7 @@ class Event(PrefectBaseModel):
|
|
128
128
|
description="The client-provided identifier of this event",
|
129
129
|
)
|
130
130
|
follows: Optional[UUID] = Field(
|
131
|
-
None,
|
131
|
+
default=None,
|
132
132
|
description=(
|
133
133
|
"The ID of an event that is known to have occurred prior to this one. "
|
134
134
|
"If set, this may be used to establish a more precise ordering of causally-"
|
prefect/events/utilities.py
CHANGED
@@ -9,6 +9,7 @@ from prefect._internal.schemas.fields import DateTimeTZ
|
|
9
9
|
from .clients import (
|
10
10
|
AssertingEventsClient,
|
11
11
|
PrefectCloudEventsClient,
|
12
|
+
PrefectEphemeralEventsClient,
|
12
13
|
PrefectEventsClient,
|
13
14
|
)
|
14
15
|
from .schemas.events import Event, RelatedResource
|
@@ -53,13 +54,14 @@ def emit_event(
|
|
53
54
|
AssertingEventsClient,
|
54
55
|
PrefectCloudEventsClient,
|
55
56
|
PrefectEventsClient,
|
57
|
+
PrefectEphemeralEventsClient,
|
56
58
|
]
|
57
59
|
worker_instance = EventsWorker.instance()
|
58
60
|
|
59
61
|
if worker_instance.client_type not in operational_clients:
|
60
62
|
return None
|
61
63
|
|
62
|
-
event_kwargs = {
|
64
|
+
event_kwargs: Dict[str, Any] = {
|
63
65
|
"event": event,
|
64
66
|
"resource": resource,
|
65
67
|
}
|