prefect-client 2.19.2__py3-none-any.whl → 3.0.0rc1__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/__init__.py +8 -56
- prefect/_internal/compatibility/deprecated.py +6 -115
- prefect/_internal/compatibility/experimental.py +4 -79
- prefect/_internal/concurrency/api.py +0 -34
- prefect/_internal/concurrency/calls.py +0 -6
- prefect/_internal/concurrency/cancellation.py +0 -3
- prefect/_internal/concurrency/event_loop.py +0 -20
- prefect/_internal/concurrency/inspection.py +3 -3
- prefect/_internal/concurrency/threads.py +35 -0
- prefect/_internal/concurrency/waiters.py +0 -28
- prefect/_internal/pydantic/__init__.py +0 -45
- prefect/_internal/pydantic/v1_schema.py +21 -22
- prefect/_internal/pydantic/v2_schema.py +0 -2
- prefect/_internal/pydantic/v2_validated_func.py +18 -23
- prefect/_internal/schemas/bases.py +44 -177
- prefect/_internal/schemas/fields.py +1 -43
- prefect/_internal/schemas/validators.py +60 -158
- prefect/artifacts.py +161 -14
- prefect/automations.py +39 -4
- prefect/blocks/abstract.py +1 -1
- prefect/blocks/core.py +268 -148
- prefect/blocks/fields.py +2 -57
- prefect/blocks/kubernetes.py +8 -12
- prefect/blocks/notifications.py +40 -20
- prefect/blocks/system.py +22 -11
- prefect/blocks/webhook.py +2 -9
- prefect/client/base.py +4 -4
- prefect/client/cloud.py +8 -13
- prefect/client/orchestration.py +347 -341
- prefect/client/schemas/actions.py +92 -86
- prefect/client/schemas/filters.py +20 -40
- prefect/client/schemas/objects.py +151 -145
- prefect/client/schemas/responses.py +16 -24
- prefect/client/schemas/schedules.py +47 -35
- prefect/client/subscriptions.py +2 -2
- prefect/client/utilities.py +5 -2
- prefect/concurrency/asyncio.py +3 -1
- prefect/concurrency/events.py +1 -1
- prefect/concurrency/services.py +6 -3
- prefect/context.py +195 -27
- prefect/deployments/__init__.py +5 -6
- prefect/deployments/base.py +7 -5
- prefect/deployments/flow_runs.py +185 -0
- prefect/deployments/runner.py +50 -45
- prefect/deployments/schedules.py +28 -23
- prefect/deployments/steps/__init__.py +0 -1
- prefect/deployments/steps/core.py +1 -0
- prefect/deployments/steps/pull.py +7 -21
- prefect/engine.py +12 -2422
- prefect/events/actions.py +17 -23
- prefect/events/cli/automations.py +19 -6
- prefect/events/clients.py +14 -37
- prefect/events/filters.py +14 -18
- prefect/events/related.py +2 -2
- prefect/events/schemas/__init__.py +0 -5
- prefect/events/schemas/automations.py +55 -46
- prefect/events/schemas/deployment_triggers.py +7 -197
- prefect/events/schemas/events.py +34 -65
- prefect/events/schemas/labelling.py +10 -14
- prefect/events/utilities.py +2 -3
- prefect/events/worker.py +2 -3
- prefect/filesystems.py +6 -517
- prefect/{new_flow_engine.py → flow_engine.py} +313 -72
- prefect/flow_runs.py +377 -5
- prefect/flows.py +307 -166
- prefect/futures.py +186 -345
- prefect/infrastructure/__init__.py +0 -27
- prefect/infrastructure/provisioners/__init__.py +5 -3
- prefect/infrastructure/provisioners/cloud_run.py +11 -6
- prefect/infrastructure/provisioners/container_instance.py +11 -7
- prefect/infrastructure/provisioners/ecs.py +6 -4
- prefect/infrastructure/provisioners/modal.py +8 -5
- prefect/input/actions.py +2 -4
- prefect/input/run_input.py +5 -7
- prefect/logging/formatters.py +0 -2
- prefect/logging/handlers.py +3 -11
- prefect/logging/loggers.py +2 -2
- prefect/manifests.py +2 -1
- prefect/records/__init__.py +1 -0
- prefect/records/result_store.py +42 -0
- prefect/records/store.py +9 -0
- prefect/results.py +43 -39
- prefect/runner/runner.py +19 -15
- prefect/runner/server.py +6 -10
- prefect/runner/storage.py +3 -8
- prefect/runner/submit.py +2 -2
- prefect/runner/utils.py +2 -2
- prefect/serializers.py +24 -35
- prefect/server/api/collections_data/views/aggregate-worker-metadata.json +5 -14
- prefect/settings.py +70 -133
- prefect/states.py +17 -47
- prefect/task_engine.py +697 -58
- prefect/task_runners.py +269 -301
- prefect/task_server.py +53 -34
- prefect/tasks.py +327 -337
- prefect/transactions.py +220 -0
- prefect/types/__init__.py +61 -82
- prefect/utilities/asyncutils.py +195 -136
- prefect/utilities/callables.py +311 -43
- prefect/utilities/collections.py +23 -38
- prefect/utilities/dispatch.py +11 -3
- prefect/utilities/dockerutils.py +4 -0
- prefect/utilities/engine.py +140 -20
- prefect/utilities/importtools.py +97 -27
- prefect/utilities/pydantic.py +128 -38
- prefect/utilities/schema_tools/hydration.py +5 -1
- prefect/utilities/templating.py +12 -2
- prefect/variables.py +78 -61
- prefect/workers/__init__.py +0 -1
- prefect/workers/base.py +15 -17
- prefect/workers/process.py +3 -8
- prefect/workers/server.py +2 -2
- {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/METADATA +22 -21
- prefect_client-3.0.0rc1.dist-info/RECORD +176 -0
- prefect/_internal/pydantic/_base_model.py +0 -51
- prefect/_internal/pydantic/_compat.py +0 -82
- prefect/_internal/pydantic/_flags.py +0 -20
- prefect/_internal/pydantic/_types.py +0 -8
- prefect/_internal/pydantic/utilities/__init__.py +0 -0
- prefect/_internal/pydantic/utilities/config_dict.py +0 -72
- prefect/_internal/pydantic/utilities/field_validator.py +0 -150
- prefect/_internal/pydantic/utilities/model_construct.py +0 -56
- prefect/_internal/pydantic/utilities/model_copy.py +0 -55
- prefect/_internal/pydantic/utilities/model_dump.py +0 -136
- prefect/_internal/pydantic/utilities/model_dump_json.py +0 -112
- prefect/_internal/pydantic/utilities/model_fields.py +0 -50
- prefect/_internal/pydantic/utilities/model_fields_set.py +0 -29
- prefect/_internal/pydantic/utilities/model_json_schema.py +0 -82
- prefect/_internal/pydantic/utilities/model_rebuild.py +0 -80
- prefect/_internal/pydantic/utilities/model_validate.py +0 -75
- prefect/_internal/pydantic/utilities/model_validate_json.py +0 -68
- prefect/_internal/pydantic/utilities/model_validator.py +0 -87
- prefect/_internal/pydantic/utilities/type_adapter.py +0 -71
- prefect/_vendor/__init__.py +0 -0
- prefect/_vendor/fastapi/__init__.py +0 -25
- prefect/_vendor/fastapi/applications.py +0 -946
- prefect/_vendor/fastapi/background.py +0 -3
- prefect/_vendor/fastapi/concurrency.py +0 -44
- prefect/_vendor/fastapi/datastructures.py +0 -58
- prefect/_vendor/fastapi/dependencies/__init__.py +0 -0
- prefect/_vendor/fastapi/dependencies/models.py +0 -64
- prefect/_vendor/fastapi/dependencies/utils.py +0 -877
- prefect/_vendor/fastapi/encoders.py +0 -177
- prefect/_vendor/fastapi/exception_handlers.py +0 -40
- prefect/_vendor/fastapi/exceptions.py +0 -46
- prefect/_vendor/fastapi/logger.py +0 -3
- prefect/_vendor/fastapi/middleware/__init__.py +0 -1
- prefect/_vendor/fastapi/middleware/asyncexitstack.py +0 -25
- prefect/_vendor/fastapi/middleware/cors.py +0 -3
- prefect/_vendor/fastapi/middleware/gzip.py +0 -3
- prefect/_vendor/fastapi/middleware/httpsredirect.py +0 -3
- prefect/_vendor/fastapi/middleware/trustedhost.py +0 -3
- prefect/_vendor/fastapi/middleware/wsgi.py +0 -3
- prefect/_vendor/fastapi/openapi/__init__.py +0 -0
- prefect/_vendor/fastapi/openapi/constants.py +0 -2
- prefect/_vendor/fastapi/openapi/docs.py +0 -203
- prefect/_vendor/fastapi/openapi/models.py +0 -480
- prefect/_vendor/fastapi/openapi/utils.py +0 -485
- prefect/_vendor/fastapi/param_functions.py +0 -340
- prefect/_vendor/fastapi/params.py +0 -453
- prefect/_vendor/fastapi/requests.py +0 -4
- prefect/_vendor/fastapi/responses.py +0 -40
- prefect/_vendor/fastapi/routing.py +0 -1331
- prefect/_vendor/fastapi/security/__init__.py +0 -15
- prefect/_vendor/fastapi/security/api_key.py +0 -98
- prefect/_vendor/fastapi/security/base.py +0 -6
- prefect/_vendor/fastapi/security/http.py +0 -172
- prefect/_vendor/fastapi/security/oauth2.py +0 -227
- prefect/_vendor/fastapi/security/open_id_connect_url.py +0 -34
- prefect/_vendor/fastapi/security/utils.py +0 -10
- prefect/_vendor/fastapi/staticfiles.py +0 -1
- prefect/_vendor/fastapi/templating.py +0 -3
- prefect/_vendor/fastapi/testclient.py +0 -1
- prefect/_vendor/fastapi/types.py +0 -3
- prefect/_vendor/fastapi/utils.py +0 -235
- prefect/_vendor/fastapi/websockets.py +0 -7
- prefect/_vendor/starlette/__init__.py +0 -1
- prefect/_vendor/starlette/_compat.py +0 -28
- prefect/_vendor/starlette/_exception_handler.py +0 -80
- prefect/_vendor/starlette/_utils.py +0 -88
- prefect/_vendor/starlette/applications.py +0 -261
- prefect/_vendor/starlette/authentication.py +0 -159
- prefect/_vendor/starlette/background.py +0 -43
- prefect/_vendor/starlette/concurrency.py +0 -59
- prefect/_vendor/starlette/config.py +0 -151
- prefect/_vendor/starlette/convertors.py +0 -87
- prefect/_vendor/starlette/datastructures.py +0 -707
- prefect/_vendor/starlette/endpoints.py +0 -130
- prefect/_vendor/starlette/exceptions.py +0 -60
- prefect/_vendor/starlette/formparsers.py +0 -276
- prefect/_vendor/starlette/middleware/__init__.py +0 -17
- prefect/_vendor/starlette/middleware/authentication.py +0 -52
- prefect/_vendor/starlette/middleware/base.py +0 -220
- prefect/_vendor/starlette/middleware/cors.py +0 -176
- prefect/_vendor/starlette/middleware/errors.py +0 -265
- prefect/_vendor/starlette/middleware/exceptions.py +0 -74
- prefect/_vendor/starlette/middleware/gzip.py +0 -113
- prefect/_vendor/starlette/middleware/httpsredirect.py +0 -19
- prefect/_vendor/starlette/middleware/sessions.py +0 -82
- prefect/_vendor/starlette/middleware/trustedhost.py +0 -64
- prefect/_vendor/starlette/middleware/wsgi.py +0 -147
- prefect/_vendor/starlette/requests.py +0 -328
- prefect/_vendor/starlette/responses.py +0 -347
- prefect/_vendor/starlette/routing.py +0 -933
- prefect/_vendor/starlette/schemas.py +0 -154
- prefect/_vendor/starlette/staticfiles.py +0 -248
- prefect/_vendor/starlette/status.py +0 -199
- prefect/_vendor/starlette/templating.py +0 -231
- prefect/_vendor/starlette/testclient.py +0 -804
- prefect/_vendor/starlette/types.py +0 -30
- prefect/_vendor/starlette/websockets.py +0 -193
- prefect/agent.py +0 -698
- prefect/deployments/deployments.py +0 -1042
- prefect/deprecated/__init__.py +0 -0
- prefect/deprecated/data_documents.py +0 -350
- prefect/deprecated/packaging/__init__.py +0 -12
- prefect/deprecated/packaging/base.py +0 -96
- prefect/deprecated/packaging/docker.py +0 -146
- prefect/deprecated/packaging/file.py +0 -92
- prefect/deprecated/packaging/orion.py +0 -80
- prefect/deprecated/packaging/serializers.py +0 -171
- prefect/events/instrument.py +0 -135
- prefect/infrastructure/base.py +0 -323
- prefect/infrastructure/container.py +0 -818
- prefect/infrastructure/kubernetes.py +0 -920
- prefect/infrastructure/process.py +0 -289
- prefect/new_task_engine.py +0 -423
- prefect/pydantic/__init__.py +0 -76
- prefect/pydantic/main.py +0 -39
- prefect/software/__init__.py +0 -2
- prefect/software/base.py +0 -50
- prefect/software/conda.py +0 -199
- prefect/software/pip.py +0 -122
- prefect/software/python.py +0 -52
- prefect/workers/block.py +0 -218
- prefect_client-2.19.2.dist-info/RECORD +0 -292
- {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/LICENSE +0 -0
- {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/WHEEL +0 -0
- {prefect_client-2.19.2.dist-info → prefect_client-3.0.0rc1.dist-info}/top_level.txt +0 -0
@@ -10,42 +10,27 @@ create them from YAML.
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
import abc
|
13
|
-
import textwrap
|
14
|
-
from datetime import timedelta
|
15
13
|
from typing import (
|
16
14
|
Any,
|
15
|
+
ClassVar,
|
17
16
|
Dict,
|
18
|
-
List,
|
19
17
|
Optional,
|
20
|
-
|
18
|
+
Type,
|
21
19
|
Union,
|
22
20
|
)
|
23
|
-
from uuid import UUID
|
24
21
|
|
22
|
+
from pydantic import Field
|
25
23
|
from typing_extensions import TypeAlias
|
26
24
|
|
27
|
-
from prefect._internal.pydantic import HAS_PYDANTIC_V2
|
28
|
-
|
29
|
-
if HAS_PYDANTIC_V2:
|
30
|
-
from pydantic.v1 import Field, PrivateAttr
|
31
|
-
else:
|
32
|
-
from pydantic import Field, PrivateAttr # type: ignore
|
33
|
-
|
34
|
-
from prefect._internal.compatibility.deprecated import deprecated_class
|
35
25
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
36
|
-
from prefect.events.actions import ActionTypes, RunDeployment
|
37
26
|
|
38
27
|
from .automations import (
|
39
|
-
AutomationCore,
|
40
28
|
CompoundTrigger,
|
41
29
|
EventTrigger,
|
42
30
|
MetricTrigger,
|
43
|
-
MetricTriggerQuery,
|
44
|
-
Posture,
|
45
31
|
SequenceTrigger,
|
46
32
|
TriggerTypes,
|
47
33
|
)
|
48
|
-
from .events import ResourceSpecification
|
49
34
|
|
50
35
|
|
51
36
|
class BaseDeploymentTrigger(PrefectBaseModel, abc.ABC, extra="ignore"): # type: ignore[call-arg]
|
@@ -86,7 +71,7 @@ class DeploymentEventTrigger(BaseDeploymentTrigger, EventTrigger):
|
|
86
71
|
period of time.
|
87
72
|
"""
|
88
73
|
|
89
|
-
trigger_type = EventTrigger
|
74
|
+
trigger_type: ClassVar[Type[TriggerTypes]] = EventTrigger
|
90
75
|
|
91
76
|
|
92
77
|
class DeploymentMetricTrigger(BaseDeploymentTrigger, MetricTrigger):
|
@@ -94,21 +79,21 @@ class DeploymentMetricTrigger(BaseDeploymentTrigger, MetricTrigger):
|
|
94
79
|
A trigger that fires based on the results of a metric query.
|
95
80
|
"""
|
96
81
|
|
97
|
-
trigger_type = MetricTrigger
|
82
|
+
trigger_type: ClassVar[Type[TriggerTypes]] = MetricTrigger
|
98
83
|
|
99
84
|
|
100
85
|
class DeploymentCompoundTrigger(BaseDeploymentTrigger, CompoundTrigger):
|
101
86
|
"""A composite trigger that requires some number of triggers to have
|
102
87
|
fired within the given time period"""
|
103
88
|
|
104
|
-
trigger_type = CompoundTrigger
|
89
|
+
trigger_type: ClassVar[Type[TriggerTypes]] = CompoundTrigger
|
105
90
|
|
106
91
|
|
107
92
|
class DeploymentSequenceTrigger(BaseDeploymentTrigger, SequenceTrigger):
|
108
93
|
"""A composite trigger that requires some number of triggers to have fired
|
109
94
|
within the given time period in a specific order"""
|
110
95
|
|
111
|
-
trigger_type = SequenceTrigger
|
96
|
+
trigger_type: ClassVar[Type[TriggerTypes]] = SequenceTrigger
|
112
97
|
|
113
98
|
|
114
99
|
# Concrete deployment trigger types
|
@@ -118,178 +103,3 @@ DeploymentTriggerTypes: TypeAlias = Union[
|
|
118
103
|
DeploymentCompoundTrigger,
|
119
104
|
DeploymentSequenceTrigger,
|
120
105
|
]
|
121
|
-
|
122
|
-
|
123
|
-
# The deprecated all-in-one DeploymentTrigger
|
124
|
-
|
125
|
-
|
126
|
-
@deprecated_class(
|
127
|
-
start_date="Mar 2024",
|
128
|
-
help=textwrap.dedent(
|
129
|
-
"""
|
130
|
-
To associate a specific kind of trigger with a Deployment, use one of the more
|
131
|
-
specific deployment trigger types instead:
|
132
|
-
|
133
|
-
* DeploymentEventTrigger to associate an EventTrigger with a deployment
|
134
|
-
* DeploymentMetricTrigger to associate an MetricTrigger with a deployment
|
135
|
-
* DeploymentCompoundTrigger to associate an CompoundTrigger with a deployment
|
136
|
-
* DeploymentSequenceTrigger to associate an SequenceTrigger with a deployment
|
137
|
-
|
138
|
-
In other cases, use the Automation and Trigger class hierarchy directly.
|
139
|
-
"""
|
140
|
-
),
|
141
|
-
)
|
142
|
-
class DeploymentTrigger(PrefectBaseModel):
|
143
|
-
name: Optional[str] = Field(
|
144
|
-
None, description="The name to give to the automation created for this trigger."
|
145
|
-
)
|
146
|
-
description: str = Field("", description="A longer description of this automation")
|
147
|
-
enabled: bool = Field(True, description="Whether this automation will be evaluated")
|
148
|
-
job_variables: Optional[Dict[str, Any]] = Field(
|
149
|
-
None,
|
150
|
-
description=(
|
151
|
-
"Job variables to pass to the run, or None to use the "
|
152
|
-
"deployment's default job variables"
|
153
|
-
),
|
154
|
-
)
|
155
|
-
|
156
|
-
# from ResourceTrigger
|
157
|
-
|
158
|
-
match: ResourceSpecification = Field(
|
159
|
-
default_factory=lambda: ResourceSpecification.parse_obj({}),
|
160
|
-
description="Labels for resources which this trigger will match.",
|
161
|
-
)
|
162
|
-
match_related: ResourceSpecification = Field(
|
163
|
-
default_factory=lambda: ResourceSpecification.parse_obj({}),
|
164
|
-
description="Labels for related resources which this trigger will match.",
|
165
|
-
)
|
166
|
-
|
167
|
-
# from both EventTrigger and MetricTrigger
|
168
|
-
|
169
|
-
posture: Posture = Field(
|
170
|
-
Posture.Reactive,
|
171
|
-
description=(
|
172
|
-
"The posture of this trigger, either Reactive, Proactive, or Metric. "
|
173
|
-
"Reactive triggers respond to the _presence_ of the expected events, while "
|
174
|
-
"Proactive triggers respond to the _absence_ of those expected events. "
|
175
|
-
"Metric triggers periodically evaluate the configured metric query."
|
176
|
-
),
|
177
|
-
)
|
178
|
-
|
179
|
-
# from EventTrigger
|
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
|
-
threshold: int = Field(
|
211
|
-
1,
|
212
|
-
description=(
|
213
|
-
"The number of events required for this trigger to fire (for "
|
214
|
-
"Reactive triggers), or the number of events expected (for Proactive "
|
215
|
-
"triggers)"
|
216
|
-
),
|
217
|
-
)
|
218
|
-
within: timedelta = Field(
|
219
|
-
timedelta(0),
|
220
|
-
minimum=0.0,
|
221
|
-
exclusiveMinimum=False,
|
222
|
-
description=(
|
223
|
-
"The time period over which the events must occur. For Reactive triggers, "
|
224
|
-
"this may be as low as 0 seconds, but must be at least 10 seconds for "
|
225
|
-
"Proactive triggers"
|
226
|
-
),
|
227
|
-
)
|
228
|
-
|
229
|
-
# from MetricTrigger
|
230
|
-
|
231
|
-
metric: Optional[MetricTriggerQuery] = Field(
|
232
|
-
None,
|
233
|
-
description="The metric query to evaluate for this trigger. ",
|
234
|
-
)
|
235
|
-
|
236
|
-
_deployment_id: Optional[UUID] = PrivateAttr(default=None)
|
237
|
-
parameters: Optional[Dict[str, Any]] = Field(
|
238
|
-
None,
|
239
|
-
description=(
|
240
|
-
"The parameters to pass to the deployment, or None to use the "
|
241
|
-
"deployment's default parameters"
|
242
|
-
),
|
243
|
-
)
|
244
|
-
|
245
|
-
def as_automation(self) -> AutomationCore:
|
246
|
-
assert self.name
|
247
|
-
|
248
|
-
trigger: TriggerTypes
|
249
|
-
|
250
|
-
if self.posture == Posture.Metric:
|
251
|
-
assert self.metric
|
252
|
-
trigger = MetricTrigger(
|
253
|
-
type="metric",
|
254
|
-
match=self.match,
|
255
|
-
match_related=self.match_related,
|
256
|
-
posture=self.posture,
|
257
|
-
metric=self.metric,
|
258
|
-
)
|
259
|
-
else:
|
260
|
-
trigger = EventTrigger(
|
261
|
-
match=self.match,
|
262
|
-
match_related=self.match_related,
|
263
|
-
after=self.after,
|
264
|
-
expect=self.expect,
|
265
|
-
for_each=self.for_each,
|
266
|
-
posture=self.posture,
|
267
|
-
threshold=self.threshold,
|
268
|
-
within=self.within,
|
269
|
-
)
|
270
|
-
|
271
|
-
return AutomationCore(
|
272
|
-
name=self.name,
|
273
|
-
description=self.description,
|
274
|
-
enabled=self.enabled,
|
275
|
-
trigger=trigger,
|
276
|
-
actions=self.actions(),
|
277
|
-
owner_resource=self.owner_resource(),
|
278
|
-
)
|
279
|
-
|
280
|
-
def set_deployment_id(self, deployment_id: UUID):
|
281
|
-
self._deployment_id = deployment_id
|
282
|
-
|
283
|
-
def owner_resource(self) -> Optional[str]:
|
284
|
-
return f"prefect.deployment.{self._deployment_id}"
|
285
|
-
|
286
|
-
def actions(self) -> List[ActionTypes]:
|
287
|
-
assert self._deployment_id
|
288
|
-
return [
|
289
|
-
RunDeployment(
|
290
|
-
source="selected",
|
291
|
-
deployment_id=self._deployment_id,
|
292
|
-
parameters=self.parameters,
|
293
|
-
job_variables=self.job_variables,
|
294
|
-
)
|
295
|
-
]
|
prefect/events/schemas/events.py
CHANGED
@@ -10,21 +10,15 @@ from typing import (
|
|
10
10
|
Sequence,
|
11
11
|
Tuple,
|
12
12
|
Union,
|
13
|
-
cast,
|
14
13
|
)
|
15
14
|
from uuid import UUID, uuid4
|
16
15
|
|
17
16
|
import pendulum
|
18
|
-
|
19
|
-
from
|
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
|
17
|
+
from pydantic import ConfigDict, Field, RootModel, field_validator, model_validator
|
18
|
+
from pydantic_extra_types.pendulum_dt import DateTime
|
19
|
+
from typing_extensions import Self
|
25
20
|
|
26
21
|
from prefect._internal.schemas.bases import PrefectBaseModel
|
27
|
-
from prefect._internal.schemas.fields import DateTimeTZ
|
28
22
|
from prefect.logging import get_logger
|
29
23
|
from prefect.settings import (
|
30
24
|
PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE,
|
@@ -39,34 +33,24 @@ logger = get_logger(__name__)
|
|
39
33
|
class Resource(Labelled):
|
40
34
|
"""An observable business object of interest to the user"""
|
41
35
|
|
42
|
-
@
|
43
|
-
def enforce_maximum_labels(
|
44
|
-
|
45
|
-
if not isinstance(labels, dict):
|
46
|
-
return values
|
47
|
-
|
48
|
-
if len(labels) > PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value():
|
36
|
+
@model_validator(mode="after")
|
37
|
+
def enforce_maximum_labels(self) -> Self:
|
38
|
+
if len(self.root) > PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value():
|
49
39
|
raise ValueError(
|
50
40
|
"The maximum number of labels per resource "
|
51
41
|
f"is {PREFECT_EVENTS_MAXIMUM_LABELS_PER_RESOURCE.value()}"
|
52
42
|
)
|
53
43
|
|
54
|
-
return
|
55
|
-
|
56
|
-
@root_validator(pre=True)
|
57
|
-
def requires_resource_id(cls, values: Dict[str, Any]):
|
58
|
-
labels = values.get("__root__")
|
59
|
-
if not isinstance(labels, dict):
|
60
|
-
return values
|
44
|
+
return self
|
61
45
|
|
62
|
-
|
63
|
-
|
64
|
-
if "prefect.resource.id" not in
|
46
|
+
@model_validator(mode="after")
|
47
|
+
def requires_resource_id(self) -> Self:
|
48
|
+
if "prefect.resource.id" not in self.root:
|
65
49
|
raise ValueError("Resources must include the prefect.resource.id label")
|
66
|
-
if not
|
50
|
+
if not self.root["prefect.resource.id"]:
|
67
51
|
raise ValueError("The prefect.resource.id label must be non-empty")
|
68
52
|
|
69
|
-
return
|
53
|
+
return self
|
70
54
|
|
71
55
|
@property
|
72
56
|
def id(self) -> str:
|
@@ -80,22 +64,16 @@ class Resource(Labelled):
|
|
80
64
|
class RelatedResource(Resource):
|
81
65
|
"""A Resource with a specific role in an Event"""
|
82
66
|
|
83
|
-
@
|
84
|
-
def requires_resource_role(
|
85
|
-
|
86
|
-
if not isinstance(labels, dict):
|
87
|
-
return values
|
88
|
-
|
89
|
-
labels = cast(Dict[str, str], labels)
|
90
|
-
|
91
|
-
if "prefect.resource.role" not in labels:
|
67
|
+
@model_validator(mode="after")
|
68
|
+
def requires_resource_role(self) -> Self:
|
69
|
+
if "prefect.resource.role" not in self.root:
|
92
70
|
raise ValueError(
|
93
71
|
"Related Resources must include the prefect.resource.role label"
|
94
72
|
)
|
95
|
-
if not
|
73
|
+
if not self.root["prefect.resource.role"]:
|
96
74
|
raise ValueError("The prefect.resource.role label must be non-empty")
|
97
75
|
|
98
|
-
return
|
76
|
+
return self
|
99
77
|
|
100
78
|
@property
|
101
79
|
def role(self) -> str:
|
@@ -105,7 +83,7 @@ class RelatedResource(Resource):
|
|
105
83
|
class Event(PrefectBaseModel):
|
106
84
|
"""The client-side view of an event that has happened to a Resource"""
|
107
85
|
|
108
|
-
occurred:
|
86
|
+
occurred: DateTime = Field(
|
109
87
|
default_factory=lambda: pendulum.now("UTC"),
|
110
88
|
description="When the event happened from the sender's perspective",
|
111
89
|
)
|
@@ -154,7 +132,8 @@ class Event(PrefectBaseModel):
|
|
154
132
|
resources[related.role].append(related)
|
155
133
|
return resources
|
156
134
|
|
157
|
-
@
|
135
|
+
@field_validator("related")
|
136
|
+
@classmethod
|
158
137
|
def enforce_maximum_related_resources(cls, value: List[RelatedResource]):
|
159
138
|
if len(value) > PREFECT_EVENTS_MAXIMUM_RELATED_RESOURCES.value():
|
160
139
|
raise ValueError(
|
@@ -181,10 +160,9 @@ class ReceivedEvent(Event):
|
|
181
160
|
"""The server-side view of an event that has happened to a Resource after it has
|
182
161
|
been received by the server"""
|
183
162
|
|
184
|
-
|
185
|
-
orm_mode = True
|
163
|
+
model_config = ConfigDict(from_attributes=True)
|
186
164
|
|
187
|
-
received:
|
165
|
+
received: DateTime = Field(
|
188
166
|
...,
|
189
167
|
description="When the event was received by Prefect Cloud",
|
190
168
|
)
|
@@ -210,35 +188,26 @@ def matches(expected: str, value: Optional[str]) -> bool:
|
|
210
188
|
return match if positive else not match
|
211
189
|
|
212
190
|
|
213
|
-
class ResourceSpecification(
|
214
|
-
"""A specification that may match zero, one, or many resources, used to target or
|
215
|
-
select a set of resources in a query or automation. A resource must match at least
|
216
|
-
one value of all of the provided labels"""
|
217
|
-
|
218
|
-
__root__: Dict[str, Union[str, List[str]]]
|
219
|
-
|
191
|
+
class ResourceSpecification(RootModel[Dict[str, Union[str, List[str]]]]):
|
220
192
|
def matches_every_resource(self) -> bool:
|
221
|
-
return len(self) == 0
|
193
|
+
return len(self.root) == 0
|
222
194
|
|
223
195
|
def matches_every_resource_of_kind(self, prefix: str) -> bool:
|
224
196
|
if self.matches_every_resource():
|
225
197
|
return True
|
226
|
-
|
227
|
-
|
228
|
-
if resource_id
|
198
|
+
if len(self.root) == 1:
|
199
|
+
resource_id = self.root.get("prefect.resource.id")
|
200
|
+
if resource_id:
|
229
201
|
values = [resource_id] if isinstance(resource_id, str) else resource_id
|
230
202
|
return any(value == f"{prefix}.*" for value in values)
|
231
|
-
|
232
203
|
return False
|
233
204
|
|
234
205
|
def includes(self, candidates: Iterable[Resource]) -> bool:
|
235
206
|
if self.matches_every_resource():
|
236
207
|
return True
|
237
|
-
|
238
208
|
for candidate in candidates:
|
239
209
|
if self.matches(candidate):
|
240
210
|
return True
|
241
|
-
|
242
211
|
return False
|
243
212
|
|
244
213
|
def matches(self, resource: Resource) -> bool:
|
@@ -251,14 +220,14 @@ class ResourceSpecification(PrefectBaseModel):
|
|
251
220
|
def items(self) -> Iterable[Tuple[str, List[str]]]:
|
252
221
|
return [
|
253
222
|
(label, [value] if isinstance(value, str) else value)
|
254
|
-
for label, value in self.
|
223
|
+
for label, value in self.root.items()
|
255
224
|
]
|
256
225
|
|
257
226
|
def __contains__(self, key: str) -> bool:
|
258
|
-
return self.
|
227
|
+
return key in self.root
|
259
228
|
|
260
229
|
def __getitem__(self, key: str) -> List[str]:
|
261
|
-
value = self.
|
230
|
+
value = self.root[key]
|
262
231
|
if not value:
|
263
232
|
return []
|
264
233
|
if not isinstance(value, list):
|
@@ -268,7 +237,7 @@ class ResourceSpecification(PrefectBaseModel):
|
|
268
237
|
def pop(
|
269
238
|
self, key: str, default: Optional[Union[str, List[str]]] = None
|
270
239
|
) -> Optional[List[str]]:
|
271
|
-
value = self.
|
240
|
+
value = self.root.pop(key, default)
|
272
241
|
if not value:
|
273
242
|
return []
|
274
243
|
if not isinstance(value, list):
|
@@ -278,7 +247,7 @@ class ResourceSpecification(PrefectBaseModel):
|
|
278
247
|
def get(
|
279
248
|
self, key: str, default: Optional[Union[str, List[str]]] = None
|
280
249
|
) -> Optional[List[str]]:
|
281
|
-
value = self.
|
250
|
+
value = self.root.get(key, default)
|
282
251
|
if not value:
|
283
252
|
return []
|
284
253
|
if not isinstance(value, list):
|
@@ -286,7 +255,7 @@ class ResourceSpecification(PrefectBaseModel):
|
|
286
255
|
return value
|
287
256
|
|
288
257
|
def __len__(self) -> int:
|
289
|
-
return len(self.
|
258
|
+
return len(self.root)
|
290
259
|
|
291
260
|
def deepcopy(self) -> "ResourceSpecification":
|
292
|
-
return ResourceSpecification
|
261
|
+
return ResourceSpecification(root=copy.deepcopy(self.root))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Dict, Iterable, Iterator, List, Optional, Tuple
|
2
2
|
|
3
|
-
from
|
3
|
+
from pydantic import RootModel
|
4
4
|
|
5
5
|
|
6
6
|
class LabelDiver:
|
@@ -71,36 +71,32 @@ class LabelDiver:
|
|
71
71
|
raise AttributeError
|
72
72
|
|
73
73
|
|
74
|
-
class Labelled(
|
75
|
-
"""An object defined by string labels and values"""
|
76
|
-
|
77
|
-
__root__: Dict[str, str]
|
78
|
-
|
74
|
+
class Labelled(RootModel[Dict[str, str]]):
|
79
75
|
def keys(self) -> Iterable[str]:
|
80
|
-
return self.
|
76
|
+
return self.root.keys()
|
81
77
|
|
82
78
|
def items(self) -> Iterable[Tuple[str, str]]:
|
83
|
-
return self.
|
79
|
+
return self.root.items()
|
84
80
|
|
85
81
|
def __getitem__(self, label: str) -> str:
|
86
|
-
return self.
|
82
|
+
return self.root[label]
|
87
83
|
|
88
84
|
def __setitem__(self, label: str, value: str) -> str:
|
89
|
-
self.
|
85
|
+
self.root[label] = value
|
90
86
|
return value
|
91
87
|
|
92
88
|
def __contains__(self, key: str) -> bool:
|
93
|
-
return key in self.
|
89
|
+
return key in self.root
|
94
90
|
|
95
91
|
def get(self, label: str, default: Optional[str] = None) -> Optional[str]:
|
96
|
-
return self.
|
92
|
+
return self.root.get(label, default)
|
97
93
|
|
98
94
|
def as_label_value_array(self) -> List[Dict[str, str]]:
|
99
95
|
return [{"label": label, "value": value} for label, value in self.items()]
|
100
96
|
|
101
97
|
@property
|
102
98
|
def labels(self) -> LabelDiver:
|
103
|
-
return LabelDiver(self.
|
99
|
+
return LabelDiver(self.root)
|
104
100
|
|
105
101
|
def has_all_labels(self, labels: Dict[str, str]) -> bool:
|
106
|
-
return all(self.
|
102
|
+
return all(self.root.get(label) == value for label, value in labels.items())
|
prefect/events/utilities.py
CHANGED
@@ -3,8 +3,7 @@ from typing import Any, Dict, List, Optional, Union
|
|
3
3
|
from uuid import UUID
|
4
4
|
|
5
5
|
import pendulum
|
6
|
-
|
7
|
-
from prefect._internal.schemas.fields import DateTimeTZ
|
6
|
+
from pydantic_extra_types.pendulum_dt import DateTime
|
8
7
|
|
9
8
|
from .clients import (
|
10
9
|
AssertingEventsClient,
|
@@ -21,7 +20,7 @@ TIGHT_TIMING = timedelta(minutes=5)
|
|
21
20
|
def emit_event(
|
22
21
|
event: str,
|
23
22
|
resource: Dict[str, str],
|
24
|
-
occurred: Optional[
|
23
|
+
occurred: Optional[DateTime] = None,
|
25
24
|
related: Optional[Union[List[Dict[str, str]], List[RelatedResource]]] = None,
|
26
25
|
payload: Optional[Dict[str, Any]] = None,
|
27
26
|
id: Optional[UUID] = None,
|
prefect/events/worker.py
CHANGED
@@ -10,7 +10,6 @@ from prefect.settings import (
|
|
10
10
|
PREFECT_API_KEY,
|
11
11
|
PREFECT_API_URL,
|
12
12
|
PREFECT_CLOUD_API_URL,
|
13
|
-
PREFECT_EXPERIMENTAL_EVENTS,
|
14
13
|
)
|
15
14
|
from prefect.utilities.context import temporary_context
|
16
15
|
|
@@ -42,11 +41,11 @@ def emit_events_to_cloud() -> bool:
|
|
42
41
|
|
43
42
|
def should_emit_events_to_running_server() -> bool:
|
44
43
|
api_url = PREFECT_API_URL.value()
|
45
|
-
return isinstance(api_url, str)
|
44
|
+
return isinstance(api_url, str)
|
46
45
|
|
47
46
|
|
48
47
|
def should_emit_events_to_ephemeral_server() -> bool:
|
49
|
-
return PREFECT_API_KEY.value() is None
|
48
|
+
return PREFECT_API_KEY.value() is None
|
50
49
|
|
51
50
|
|
52
51
|
class EventsWorker(QueueService[Event]):
|