zenml-nightly 0.58.2.dev20240624__py3-none-any.whl → 0.58.2.dev20240625__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.
- zenml/VERSION +1 -1
- zenml/actions/base_action.py +177 -174
- zenml/actions/pipeline_run/pipeline_run_action.py +28 -23
- zenml/client.py +226 -55
- zenml/config/compiler.py +10 -9
- zenml/config/docker_settings.py +25 -9
- zenml/constants.py +1 -1
- zenml/event_hub/base_event_hub.py +5 -5
- zenml/event_hub/event_hub.py +15 -6
- zenml/event_sources/base_event.py +0 -11
- zenml/event_sources/base_event_source.py +7 -0
- zenml/event_sources/webhooks/base_webhook_event_source.py +1 -4
- zenml/exceptions.py +4 -0
- zenml/hooks/hook_validators.py +2 -3
- zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +3 -3
- zenml/integrations/mlflow/__init__.py +1 -1
- zenml/models/__init__.py +17 -0
- zenml/models/v2/core/action.py +276 -0
- zenml/models/v2/core/trigger.py +182 -141
- zenml/new/pipelines/pipeline.py +13 -3
- zenml/new/pipelines/pipeline_decorator.py +1 -2
- zenml/new/pipelines/run_utils.py +1 -12
- zenml/new/steps/step_decorator.py +2 -3
- zenml/pipelines/base_pipeline.py +0 -2
- zenml/pipelines/pipeline_decorator.py +1 -2
- zenml/steps/base_step.py +1 -2
- zenml/steps/step_decorator.py +1 -2
- zenml/types.py +10 -1
- zenml/utils/pipeline_docker_image_builder.py +20 -5
- zenml/zen_server/rbac/models.py +1 -0
- zenml/zen_server/rbac/utils.py +22 -1
- zenml/zen_server/routers/actions_endpoints.py +324 -0
- zenml/zen_server/routers/triggers_endpoints.py +30 -158
- zenml/zen_server/zen_server_api.py +2 -0
- zenml/zen_stores/migrations/versions/25155145c545_separate_actions_and_triggers.py +228 -0
- zenml/zen_stores/rest_zen_store.py +103 -4
- zenml/zen_stores/schemas/__init__.py +2 -0
- zenml/zen_stores/schemas/action_schemas.py +192 -0
- zenml/zen_stores/schemas/trigger_schemas.py +43 -50
- zenml/zen_stores/schemas/user_schemas.py +10 -2
- zenml/zen_stores/schemas/workspace_schemas.py +5 -0
- zenml/zen_stores/sql_zen_store.py +240 -30
- zenml/zen_stores/zen_store_interface.py +85 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/METADATA +1 -1
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/RECORD +48 -44
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
# Copyright (c) ZenML GmbH 2024. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at:
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
12
|
+
# or implied. See the License for the specific language governing
|
13
|
+
# permissions and limitations under the License.
|
14
|
+
"""SQL Model Implementations for Actions."""
|
15
|
+
|
16
|
+
import base64
|
17
|
+
import json
|
18
|
+
from datetime import datetime
|
19
|
+
from typing import TYPE_CHECKING, Any, List, Optional
|
20
|
+
from uuid import UUID
|
21
|
+
|
22
|
+
from pydantic.json import pydantic_encoder
|
23
|
+
from sqlalchemy import TEXT, Column
|
24
|
+
from sqlmodel import Field, Relationship
|
25
|
+
|
26
|
+
from zenml.models import (
|
27
|
+
ActionRequest,
|
28
|
+
ActionResponse,
|
29
|
+
ActionResponseBody,
|
30
|
+
ActionResponseMetadata,
|
31
|
+
ActionResponseResources,
|
32
|
+
ActionUpdate,
|
33
|
+
)
|
34
|
+
from zenml.zen_stores.schemas.base_schemas import NamedSchema
|
35
|
+
from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
|
36
|
+
from zenml.zen_stores.schemas.user_schemas import UserSchema
|
37
|
+
from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
|
38
|
+
|
39
|
+
if TYPE_CHECKING:
|
40
|
+
from zenml.zen_stores.schemas import TriggerSchema
|
41
|
+
|
42
|
+
|
43
|
+
class ActionSchema(NamedSchema, table=True):
|
44
|
+
"""SQL Model for actions."""
|
45
|
+
|
46
|
+
__tablename__ = "action"
|
47
|
+
|
48
|
+
workspace_id: UUID = build_foreign_key_field(
|
49
|
+
source=__tablename__,
|
50
|
+
target=WorkspaceSchema.__tablename__,
|
51
|
+
source_column="workspace_id",
|
52
|
+
target_column="id",
|
53
|
+
ondelete="CASCADE",
|
54
|
+
nullable=False,
|
55
|
+
)
|
56
|
+
workspace: "WorkspaceSchema" = Relationship(back_populates="actions")
|
57
|
+
|
58
|
+
user_id: Optional[UUID] = build_foreign_key_field(
|
59
|
+
source=__tablename__,
|
60
|
+
target=UserSchema.__tablename__,
|
61
|
+
source_column="user_id",
|
62
|
+
target_column="id",
|
63
|
+
ondelete="SET NULL",
|
64
|
+
nullable=True,
|
65
|
+
)
|
66
|
+
user: Optional["UserSchema"] = Relationship(
|
67
|
+
back_populates="actions",
|
68
|
+
sa_relationship_kwargs={"foreign_keys": "[ActionSchema.user_id]"},
|
69
|
+
)
|
70
|
+
|
71
|
+
triggers: List["TriggerSchema"] = Relationship(back_populates="action")
|
72
|
+
|
73
|
+
service_account_id: UUID = build_foreign_key_field(
|
74
|
+
source=__tablename__,
|
75
|
+
target=UserSchema.__tablename__,
|
76
|
+
source_column="service_account_id",
|
77
|
+
target_column="id",
|
78
|
+
ondelete="CASCADE",
|
79
|
+
nullable=False,
|
80
|
+
)
|
81
|
+
service_account: UserSchema = Relationship(
|
82
|
+
back_populates="auth_actions",
|
83
|
+
sa_relationship_kwargs={
|
84
|
+
"foreign_keys": "[ActionSchema.service_account_id]"
|
85
|
+
},
|
86
|
+
)
|
87
|
+
auth_window: int
|
88
|
+
|
89
|
+
flavor: str = Field(nullable=False)
|
90
|
+
plugin_subtype: str = Field(nullable=False)
|
91
|
+
description: Optional[str] = Field(sa_column=Column(TEXT, nullable=True))
|
92
|
+
|
93
|
+
configuration: bytes
|
94
|
+
|
95
|
+
@classmethod
|
96
|
+
def from_request(cls, request: "ActionRequest") -> "ActionSchema":
|
97
|
+
"""Convert a `ActionRequest` to a `ActionSchema`.
|
98
|
+
|
99
|
+
Args:
|
100
|
+
request: The request model to convert.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
The converted schema.
|
104
|
+
"""
|
105
|
+
return cls(
|
106
|
+
name=request.name,
|
107
|
+
workspace_id=request.workspace,
|
108
|
+
user_id=request.user,
|
109
|
+
configuration=base64.b64encode(
|
110
|
+
json.dumps(
|
111
|
+
request.configuration, default=pydantic_encoder
|
112
|
+
).encode("utf-8"),
|
113
|
+
),
|
114
|
+
flavor=request.flavor,
|
115
|
+
plugin_subtype=request.plugin_subtype,
|
116
|
+
description=request.description,
|
117
|
+
service_account_id=request.service_account_id,
|
118
|
+
auth_window=request.auth_window,
|
119
|
+
)
|
120
|
+
|
121
|
+
def update(self, action_update: "ActionUpdate") -> "ActionSchema":
|
122
|
+
"""Updates a action schema with a action update model.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
action_update: `ActionUpdate` to update the action with.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
The updated ActionSchema.
|
129
|
+
"""
|
130
|
+
for field, value in action_update.dict(
|
131
|
+
exclude_unset=True,
|
132
|
+
exclude_none=True,
|
133
|
+
).items():
|
134
|
+
if field == "configuration":
|
135
|
+
self.configuration = base64.b64encode(
|
136
|
+
json.dumps(
|
137
|
+
action_update.configuration, default=pydantic_encoder
|
138
|
+
).encode("utf-8")
|
139
|
+
)
|
140
|
+
else:
|
141
|
+
setattr(self, field, value)
|
142
|
+
|
143
|
+
self.updated = datetime.utcnow()
|
144
|
+
return self
|
145
|
+
|
146
|
+
def to_model(
|
147
|
+
self,
|
148
|
+
include_metadata: bool = False,
|
149
|
+
include_resources: bool = False,
|
150
|
+
**kwargs: Any,
|
151
|
+
) -> "ActionResponse":
|
152
|
+
"""Converts the action schema to a model.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
include_metadata: Flag deciding whether to include the output model(s)
|
156
|
+
metadata fields in the response.
|
157
|
+
include_resources: Flag deciding whether to include the output model(s)
|
158
|
+
metadata fields in the response.
|
159
|
+
**kwargs: Keyword arguments to allow schema specific logic
|
160
|
+
|
161
|
+
Returns:
|
162
|
+
The converted model.
|
163
|
+
"""
|
164
|
+
body = ActionResponseBody(
|
165
|
+
user=self.user.to_model() if self.user else None,
|
166
|
+
created=self.created,
|
167
|
+
updated=self.updated,
|
168
|
+
flavor=self.flavor,
|
169
|
+
plugin_subtype=self.plugin_subtype,
|
170
|
+
)
|
171
|
+
metadata = None
|
172
|
+
if include_metadata:
|
173
|
+
metadata = ActionResponseMetadata(
|
174
|
+
workspace=self.workspace.to_model(),
|
175
|
+
configuration=json.loads(
|
176
|
+
base64.b64decode(self.configuration).decode()
|
177
|
+
),
|
178
|
+
description=self.description,
|
179
|
+
auth_window=self.auth_window,
|
180
|
+
)
|
181
|
+
resources = None
|
182
|
+
if include_resources:
|
183
|
+
resources = ActionResponseResources(
|
184
|
+
service_account=self.service_account.to_model(),
|
185
|
+
)
|
186
|
+
return ActionResponse(
|
187
|
+
id=self.id,
|
188
|
+
name=self.name,
|
189
|
+
body=body,
|
190
|
+
metadata=metadata,
|
191
|
+
resources=resources,
|
192
|
+
)
|
@@ -22,13 +22,14 @@ from uuid import UUID
|
|
22
22
|
from sqlalchemy import TEXT, Column
|
23
23
|
from sqlmodel import Field, Relationship
|
24
24
|
|
25
|
-
from zenml import
|
25
|
+
from zenml.config.schedule import Schedule
|
26
26
|
from zenml.models import (
|
27
27
|
Page,
|
28
28
|
TriggerExecutionRequest,
|
29
29
|
TriggerExecutionResponse,
|
30
30
|
TriggerExecutionResponseBody,
|
31
31
|
TriggerExecutionResponseMetadata,
|
32
|
+
TriggerExecutionResponseResources,
|
32
33
|
TriggerRequest,
|
33
34
|
TriggerResponse,
|
34
35
|
TriggerResponseBody,
|
@@ -37,6 +38,7 @@ from zenml.models import (
|
|
37
38
|
TriggerUpdate,
|
38
39
|
)
|
39
40
|
from zenml.utils.json_utils import pydantic_encoder
|
41
|
+
from zenml.zen_stores.schemas.action_schemas import ActionSchema
|
40
42
|
from zenml.zen_stores.schemas.base_schemas import BaseSchema, NamedSchema
|
41
43
|
from zenml.zen_stores.schemas.event_source_schemas import EventSourceSchema
|
42
44
|
from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
|
@@ -78,36 +80,33 @@ class TriggerSchema(NamedSchema, table=True):
|
|
78
80
|
target=EventSourceSchema.__tablename__,
|
79
81
|
source_column="event_source_id",
|
80
82
|
target_column="id",
|
81
|
-
|
82
|
-
|
83
|
+
# This won't happen because the SQL zen store prevents an event source
|
84
|
+
# from being deleted if it has associated triggers
|
85
|
+
ondelete="SET NULL",
|
86
|
+
nullable=True,
|
83
87
|
)
|
84
|
-
event_source: "EventSourceSchema" = Relationship(
|
85
|
-
|
86
|
-
executions: List["TriggerExecutionSchema"] = Relationship(
|
87
|
-
back_populates="trigger"
|
88
|
+
event_source: Optional["EventSourceSchema"] = Relationship(
|
89
|
+
back_populates="triggers"
|
88
90
|
)
|
89
91
|
|
90
|
-
|
92
|
+
action_id: UUID = build_foreign_key_field(
|
91
93
|
source=__tablename__,
|
92
|
-
target=
|
93
|
-
source_column="
|
94
|
+
target=ActionSchema.__tablename__,
|
95
|
+
source_column="action_id",
|
94
96
|
target_column="id",
|
95
|
-
|
97
|
+
# This won't happen because the SQL zen store prevents an action
|
98
|
+
# from being deleted if it has associated triggers
|
99
|
+
ondelete="CASCADE",
|
96
100
|
nullable=False,
|
97
101
|
)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
},
|
102
|
+
action: "ActionSchema" = Relationship(back_populates="triggers")
|
103
|
+
|
104
|
+
executions: List["TriggerExecutionSchema"] = Relationship(
|
105
|
+
back_populates="trigger"
|
103
106
|
)
|
104
|
-
auth_window: int
|
105
107
|
|
106
108
|
event_filter: bytes
|
107
|
-
|
108
|
-
action: bytes
|
109
|
-
action_flavor: str # <- "builtin"
|
110
|
-
action_subtype: str # <- "PipelineRun"
|
109
|
+
schedule: Optional[bytes] = Field(nullable=True)
|
111
110
|
|
112
111
|
description: str = Field(sa_column=Column(TEXT, nullable=True))
|
113
112
|
is_active: bool = Field(nullable=False)
|
@@ -131,12 +130,6 @@ class TriggerSchema(NamedSchema, table=True):
|
|
131
130
|
trigger_update.event_filter, default=pydantic_encoder
|
132
131
|
).encode("utf-8")
|
133
132
|
)
|
134
|
-
elif field == "action":
|
135
|
-
self.action = base64.b64encode(
|
136
|
-
json.dumps(
|
137
|
-
trigger_update.action, default=pydantic_encoder
|
138
|
-
).encode("utf-8")
|
139
|
-
)
|
140
133
|
else:
|
141
134
|
setattr(self, field, value)
|
142
135
|
|
@@ -152,31 +145,21 @@ class TriggerSchema(NamedSchema, table=True):
|
|
152
145
|
|
153
146
|
Returns:
|
154
147
|
The converted schema.
|
155
|
-
|
156
|
-
Raises:
|
157
|
-
ValueError: If `auth_window` is not set.
|
158
148
|
"""
|
159
|
-
if request.auth_window is None:
|
160
|
-
raise ValueError("auth_window must be set")
|
161
149
|
return cls(
|
162
150
|
name=request.name,
|
163
151
|
workspace_id=request.workspace,
|
164
152
|
user_id=request.user,
|
165
|
-
|
166
|
-
json.dumps(request.action, default=pydantic_encoder).encode(
|
167
|
-
"utf-8"
|
168
|
-
),
|
169
|
-
),
|
170
|
-
action_flavor=request.action_flavor,
|
171
|
-
action_subtype=request.action_subtype,
|
153
|
+
action_id=request.action_id,
|
172
154
|
event_source_id=request.event_source_id,
|
173
|
-
service_account_id=request.service_account_id,
|
174
|
-
auth_window=request.auth_window,
|
175
155
|
event_filter=base64.b64encode(
|
176
156
|
json.dumps(
|
177
157
|
request.event_filter, default=pydantic_encoder
|
178
158
|
).encode("utf-8")
|
179
159
|
),
|
160
|
+
schedule=base64.b64encode(request.schedule.json().encode("utf-8"))
|
161
|
+
if request.schedule
|
162
|
+
else None,
|
180
163
|
description=request.description,
|
181
164
|
is_active=True, # Makes no sense for it to be created inactive
|
182
165
|
)
|
@@ -205,9 +188,14 @@ class TriggerSchema(NamedSchema, table=True):
|
|
205
188
|
user=self.user.to_model() if self.user else None,
|
206
189
|
created=self.created,
|
207
190
|
updated=self.updated,
|
208
|
-
action_flavor=self.
|
209
|
-
action_subtype=self.
|
210
|
-
event_source_flavor=self.event_source.flavor
|
191
|
+
action_flavor=self.action.flavor,
|
192
|
+
action_subtype=self.action.plugin_subtype,
|
193
|
+
event_source_flavor=self.event_source.flavor
|
194
|
+
if self.event_source
|
195
|
+
else None,
|
196
|
+
event_source_subtype=self.event_source.plugin_subtype
|
197
|
+
if self.event_source
|
198
|
+
else None,
|
211
199
|
is_active=self.is_active,
|
212
200
|
)
|
213
201
|
metadata = None
|
@@ -217,9 +205,12 @@ class TriggerSchema(NamedSchema, table=True):
|
|
217
205
|
event_filter=json.loads(
|
218
206
|
base64.b64decode(self.event_filter).decode()
|
219
207
|
),
|
220
|
-
|
208
|
+
schedule=Schedule.parse_raw(
|
209
|
+
base64.b64decode(self.schedule).decode()
|
210
|
+
)
|
211
|
+
if self.schedule
|
212
|
+
else None,
|
221
213
|
description=self.description,
|
222
|
-
auth_window=self.auth_window,
|
223
214
|
)
|
224
215
|
resources = None
|
225
216
|
if include_resources:
|
@@ -228,13 +219,15 @@ class TriggerSchema(NamedSchema, table=True):
|
|
228
219
|
get_page_from_list(
|
229
220
|
items_list=self.executions,
|
230
221
|
response_model=TriggerExecutionResponse,
|
231
|
-
include_resources=
|
232
|
-
include_metadata=
|
222
|
+
include_resources=False,
|
223
|
+
include_metadata=False,
|
233
224
|
),
|
234
225
|
)
|
235
226
|
resources = TriggerResponseResources(
|
236
|
-
|
237
|
-
|
227
|
+
action=self.action.to_model(),
|
228
|
+
event_source=self.event_source.to_model()
|
229
|
+
if self.event_source
|
230
|
+
else None,
|
238
231
|
executions=executions,
|
239
232
|
)
|
240
233
|
return TriggerResponse(
|
@@ -37,6 +37,7 @@ from zenml.zen_stores.schemas.base_schemas import NamedSchema
|
|
37
37
|
|
38
38
|
if TYPE_CHECKING:
|
39
39
|
from zenml.zen_stores.schemas import (
|
40
|
+
ActionSchema,
|
40
41
|
APIKeySchema,
|
41
42
|
ArtifactVersionSchema,
|
42
43
|
CodeRepositorySchema,
|
@@ -87,6 +88,13 @@ class UserSchema(NamedSchema, table=True):
|
|
87
88
|
back_populates="user",
|
88
89
|
)
|
89
90
|
flavors: List["FlavorSchema"] = Relationship(back_populates="user")
|
91
|
+
actions: List["ActionSchema"] = Relationship(
|
92
|
+
back_populates="user",
|
93
|
+
sa_relationship_kwargs={
|
94
|
+
"cascade": "delete",
|
95
|
+
"primaryjoin": "UserSchema.id==ActionSchema.user_id",
|
96
|
+
},
|
97
|
+
)
|
90
98
|
event_sources: List["EventSourceSchema"] = Relationship(
|
91
99
|
back_populates="user"
|
92
100
|
)
|
@@ -114,11 +122,11 @@ class UserSchema(NamedSchema, table=True):
|
|
114
122
|
"primaryjoin": "UserSchema.id==TriggerSchema.user_id",
|
115
123
|
},
|
116
124
|
)
|
117
|
-
|
125
|
+
auth_actions: List["ActionSchema"] = Relationship(
|
118
126
|
back_populates="service_account",
|
119
127
|
sa_relationship_kwargs={
|
120
128
|
"cascade": "delete",
|
121
|
-
"primaryjoin": "UserSchema.id==
|
129
|
+
"primaryjoin": "UserSchema.id==ActionSchema.service_account_id",
|
122
130
|
},
|
123
131
|
)
|
124
132
|
deployments: List["PipelineDeploymentSchema"] = Relationship(
|
@@ -29,6 +29,7 @@ from zenml.zen_stores.schemas.base_schemas import NamedSchema
|
|
29
29
|
|
30
30
|
if TYPE_CHECKING:
|
31
31
|
from zenml.zen_stores.schemas import (
|
32
|
+
ActionSchema,
|
32
33
|
ArtifactVersionSchema,
|
33
34
|
CodeRepositorySchema,
|
34
35
|
EventSourceSchema,
|
@@ -104,6 +105,10 @@ class WorkspaceSchema(NamedSchema, table=True):
|
|
104
105
|
back_populates="workspace",
|
105
106
|
sa_relationship_kwargs={"cascade": "delete"},
|
106
107
|
)
|
108
|
+
actions: List["ActionSchema"] = Relationship(
|
109
|
+
back_populates="workspace",
|
110
|
+
sa_relationship_kwargs={"cascade": "delete"},
|
111
|
+
)
|
107
112
|
triggers: List["TriggerSchema"] = Relationship(
|
108
113
|
back_populates="workspace",
|
109
114
|
sa_relationship_kwargs={"cascade": "delete"},
|