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.
Files changed (48) hide show
  1. zenml/VERSION +1 -1
  2. zenml/actions/base_action.py +177 -174
  3. zenml/actions/pipeline_run/pipeline_run_action.py +28 -23
  4. zenml/client.py +226 -55
  5. zenml/config/compiler.py +10 -9
  6. zenml/config/docker_settings.py +25 -9
  7. zenml/constants.py +1 -1
  8. zenml/event_hub/base_event_hub.py +5 -5
  9. zenml/event_hub/event_hub.py +15 -6
  10. zenml/event_sources/base_event.py +0 -11
  11. zenml/event_sources/base_event_source.py +7 -0
  12. zenml/event_sources/webhooks/base_webhook_event_source.py +1 -4
  13. zenml/exceptions.py +4 -0
  14. zenml/hooks/hook_validators.py +2 -3
  15. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +3 -3
  16. zenml/integrations/mlflow/__init__.py +1 -1
  17. zenml/models/__init__.py +17 -0
  18. zenml/models/v2/core/action.py +276 -0
  19. zenml/models/v2/core/trigger.py +182 -141
  20. zenml/new/pipelines/pipeline.py +13 -3
  21. zenml/new/pipelines/pipeline_decorator.py +1 -2
  22. zenml/new/pipelines/run_utils.py +1 -12
  23. zenml/new/steps/step_decorator.py +2 -3
  24. zenml/pipelines/base_pipeline.py +0 -2
  25. zenml/pipelines/pipeline_decorator.py +1 -2
  26. zenml/steps/base_step.py +1 -2
  27. zenml/steps/step_decorator.py +1 -2
  28. zenml/types.py +10 -1
  29. zenml/utils/pipeline_docker_image_builder.py +20 -5
  30. zenml/zen_server/rbac/models.py +1 -0
  31. zenml/zen_server/rbac/utils.py +22 -1
  32. zenml/zen_server/routers/actions_endpoints.py +324 -0
  33. zenml/zen_server/routers/triggers_endpoints.py +30 -158
  34. zenml/zen_server/zen_server_api.py +2 -0
  35. zenml/zen_stores/migrations/versions/25155145c545_separate_actions_and_triggers.py +228 -0
  36. zenml/zen_stores/rest_zen_store.py +103 -4
  37. zenml/zen_stores/schemas/__init__.py +2 -0
  38. zenml/zen_stores/schemas/action_schemas.py +192 -0
  39. zenml/zen_stores/schemas/trigger_schemas.py +43 -50
  40. zenml/zen_stores/schemas/user_schemas.py +10 -2
  41. zenml/zen_stores/schemas/workspace_schemas.py +5 -0
  42. zenml/zen_stores/sql_zen_store.py +240 -30
  43. zenml/zen_stores/zen_store_interface.py +85 -0
  44. {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/METADATA +1 -1
  45. {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/RECORD +48 -44
  46. {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/LICENSE +0 -0
  47. {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/WHEEL +0 -0
  48. {zenml_nightly-0.58.2.dev20240624.dist-info → zenml_nightly-0.58.2.dev20240625.dist-info}/entry_points.txt +0 -0
@@ -14,7 +14,9 @@
14
14
  """Base class for all the Event Hub."""
15
15
 
16
16
  from functools import partial
17
- from typing import TYPE_CHECKING, List
17
+ from typing import List
18
+
19
+ from pydantic import ValidationError
18
20
 
19
21
  from zenml import EventSourceResponse
20
22
  from zenml.enums import PluginType
@@ -35,9 +37,6 @@ from zenml.zen_server.utils import plugin_flavor_registry
35
37
 
36
38
  logger = get_logger(__name__)
37
39
 
38
- if TYPE_CHECKING:
39
- pass
40
-
41
40
 
42
41
  class InternalEventHub(BaseEventHub):
43
42
  """Internal in-server event hub implementation.
@@ -158,9 +157,19 @@ class InternalEventHub(BaseEventHub):
158
157
 
159
158
  assert issubclass(plugin_flavor, BaseEventSourceFlavor)
160
159
 
161
- # Get the filter class from the plugin flavor class
162
160
  event_filter_config_class = plugin_flavor.EVENT_FILTER_CONFIG_CLASS
163
- event_filter = event_filter_config_class(**trigger.event_filter)
161
+ try:
162
+ event_filter = event_filter_config_class(
163
+ **trigger.event_filter if trigger.event_filter else {}
164
+ )
165
+ except ValidationError:
166
+ logger.exception(
167
+ f"Could not instantiate event filter config class for "
168
+ f"event source {event_source.id}. Skipping trigger "
169
+ f"{trigger.id}."
170
+ )
171
+ continue
172
+
164
173
  if event_filter.event_matches_filter(event=event):
165
174
  trigger_list.append(trigger)
166
175
 
@@ -13,19 +13,8 @@
13
13
  # permissions and limitations under the License.
14
14
  """Base implementation for events."""
15
15
 
16
- from typing import (
17
- TYPE_CHECKING,
18
- )
19
-
20
16
  from pydantic import BaseModel
21
17
 
22
- from zenml.logger import get_logger
23
-
24
- if TYPE_CHECKING:
25
- pass
26
-
27
- logger = get_logger(__name__)
28
-
29
18
  # -------------------- Event Models -----------------------------------
30
19
 
31
20
 
@@ -449,6 +449,13 @@ class BaseEventSourceHandler(BasePlugin, ABC):
449
449
  event: The event to dispatch.
450
450
  event_source: The event source that produced the event.
451
451
  """
452
+ if not event_source.is_active:
453
+ logger.debug(
454
+ f"Event source {event_source.id} is not active. Skipping event "
455
+ f"dispatch."
456
+ )
457
+ return
458
+
452
459
  self.event_hub.publish_event(
453
460
  event=event,
454
461
  event_source=event_source,
@@ -17,7 +17,7 @@ import hashlib
17
17
  import hmac
18
18
  import json
19
19
  from abc import ABC, abstractmethod
20
- from typing import TYPE_CHECKING, Any, ClassVar, Dict, Optional, Type
20
+ from typing import Any, ClassVar, Dict, Optional, Type
21
21
 
22
22
  from zenml.enums import PluginSubType
23
23
  from zenml.event_sources.base_event import BaseEvent
@@ -33,9 +33,6 @@ from zenml.models import EventSourceResponse
33
33
 
34
34
  logger = get_logger(__name__)
35
35
 
36
- if TYPE_CHECKING:
37
- pass
38
-
39
36
 
40
37
  # -------------------- Event Models -----------------------------------
41
38
 
zenml/exceptions.py CHANGED
@@ -197,6 +197,10 @@ class EntityExistsError(ZenMLBaseException):
197
197
  """Raised when trying to register an entity that already exists."""
198
198
 
199
199
 
200
+ class ActionExistsError(EntityExistsError):
201
+ """Raised when registering an action with a name that already exists."""
202
+
203
+
200
204
  class TriggerExistsError(EntityExistsError):
201
205
  """Raised when registering a trigger with name that already exists."""
202
206
 
@@ -14,14 +14,13 @@
14
14
  """Validation functions for hooks."""
15
15
 
16
16
  import inspect
17
- from types import FunctionType
18
- from typing import TYPE_CHECKING, Union
17
+ from typing import TYPE_CHECKING
19
18
 
20
19
  from zenml.config.source import Source
21
20
  from zenml.utils import source_utils
22
21
 
23
22
  if TYPE_CHECKING:
24
- HookSpecification = Union[str, Source, FunctionType]
23
+ from zenml.types import HookSpecification
25
24
 
26
25
 
27
26
  def resolve_and_validate_hook(hook: "HookSpecification") -> Source:
@@ -152,9 +152,9 @@ class BitbucketEvent(BaseEvent):
152
152
  class BitbucketWebhookEventFilterConfiguration(WebhookEventFilterConfig):
153
153
  """Configuration for Bitbucket event filters."""
154
154
 
155
- repo: Optional[str]
156
- branch: Optional[str]
157
- event_type: Optional[BitbucketEventType]
155
+ repo: Optional[str] = None
156
+ branch: Optional[str] = None
157
+ event_type: Optional[BitbucketEventType] = None
158
158
 
159
159
  def event_matches_filter(self, event: BaseEvent) -> bool:
160
160
  """Checks the filter against the inbound event.
@@ -33,7 +33,7 @@ class MlflowIntegration(Integration):
33
33
  NAME = MLFLOW
34
34
 
35
35
  REQUIREMENTS = [
36
- "mlflow>=2.1.1,<=2.12.2",
36
+ "mlflow>=2.1.1,<=2.14.1",
37
37
  "mlserver>=1.3.3",
38
38
  "mlserver-mlflow>=1.3.3",
39
39
  # TODO: remove this requirement once rapidjson is fixed
zenml/models/__init__.py CHANGED
@@ -51,6 +51,15 @@ from zenml.models.v2.base.filter import (
51
51
  from zenml.models.v2.base.page import Page
52
52
 
53
53
  # V2 Core
54
+ from zenml.models.v2.core.action import (
55
+ ActionFilter,
56
+ ActionRequest,
57
+ ActionResponse,
58
+ ActionResponseBody,
59
+ ActionResponseMetadata,
60
+ ActionResponseResources,
61
+ ActionUpdate,
62
+ )
54
63
  from zenml.models.v2.core.action_flavor import (
55
64
  ActionFlavorResponse,
56
65
  ActionFlavorResponseBody,
@@ -381,6 +390,7 @@ from zenml.models.v2.core.server_settings import (
381
390
  # ----------------------------- Forward References -----------------------------
382
391
 
383
392
  # V2
393
+ ActionResponseResources.model_rebuild()
384
394
  APIKeyResponseBody.model_rebuild()
385
395
  ArtifactVersionRequest.model_rebuild()
386
396
  ArtifactVersionResponseBody.model_rebuild()
@@ -470,6 +480,13 @@ __all__ = [
470
480
  "UUIDFilter",
471
481
  "Page",
472
482
  # V2 Core
483
+ "ActionFilter",
484
+ "ActionRequest",
485
+ "ActionResponse",
486
+ "ActionResponseBody",
487
+ "ActionResponseMetadata",
488
+ "ActionResponseResources",
489
+ "ActionUpdate",
473
490
  "ActionFlavorResponse",
474
491
  "ActionFlavorResponseBody",
475
492
  "ActionFlavorResponseMetadata",
@@ -0,0 +1,276 @@
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
+ """Collection of all models concerning actions."""
15
+
16
+ import copy
17
+ from typing import (
18
+ TYPE_CHECKING,
19
+ Any,
20
+ Dict,
21
+ Optional,
22
+ TypeVar,
23
+ )
24
+ from uuid import UUID
25
+
26
+ from pydantic import Field
27
+
28
+ from zenml.constants import STR_FIELD_MAX_LENGTH
29
+ from zenml.enums import PluginSubType
30
+ from zenml.models.v2.base.base import BaseUpdate
31
+ from zenml.models.v2.base.scoped import (
32
+ WorkspaceScopedFilter,
33
+ WorkspaceScopedRequest,
34
+ WorkspaceScopedResponse,
35
+ WorkspaceScopedResponseBody,
36
+ WorkspaceScopedResponseMetadata,
37
+ WorkspaceScopedResponseResources,
38
+ )
39
+ from zenml.models.v2.core.user import UserResponse
40
+
41
+ if TYPE_CHECKING:
42
+ from zenml.zen_stores.schemas import BaseSchema
43
+
44
+ AnySchema = TypeVar("AnySchema", bound=BaseSchema)
45
+
46
+
47
+ # ------------------ Request Model ------------------
48
+
49
+
50
+ class ActionRequest(WorkspaceScopedRequest):
51
+ """Model for creating a new action."""
52
+
53
+ name: str = Field(
54
+ title="The name of the action.", max_length=STR_FIELD_MAX_LENGTH
55
+ )
56
+ description: str = Field(
57
+ default="",
58
+ title="The description of the action",
59
+ max_length=STR_FIELD_MAX_LENGTH,
60
+ )
61
+ flavor: str = Field(
62
+ title="The flavor of the action.",
63
+ max_length=STR_FIELD_MAX_LENGTH,
64
+ )
65
+ plugin_subtype: PluginSubType = Field(
66
+ title="The subtype of the action.",
67
+ max_length=STR_FIELD_MAX_LENGTH,
68
+ )
69
+ configuration: Dict[str, Any] = Field(
70
+ title="The configuration for the action.",
71
+ )
72
+ service_account_id: UUID = Field(
73
+ title="The service account that is used to execute the action.",
74
+ )
75
+ auth_window: Optional[int] = Field(
76
+ default=None,
77
+ title="The time window in minutes for which the service account is "
78
+ "authorized to execute the action. Set this to 0 to authorize the "
79
+ "service account indefinitely (not recommended). If not set, a "
80
+ "default value defined for each individual action type is used.",
81
+ )
82
+
83
+
84
+ # ------------------ Update Model ------------------
85
+
86
+
87
+ class ActionUpdate(BaseUpdate):
88
+ """Update model for actions."""
89
+
90
+ name: Optional[str] = Field(
91
+ default=None,
92
+ title="The new name for the action.",
93
+ max_length=STR_FIELD_MAX_LENGTH,
94
+ )
95
+ description: Optional[str] = Field(
96
+ default=None,
97
+ title="The new description for the action.",
98
+ max_length=STR_FIELD_MAX_LENGTH,
99
+ )
100
+ configuration: Optional[Dict[str, Any]] = Field(
101
+ default=None,
102
+ title="The configuration for the action.",
103
+ )
104
+ service_account_id: Optional[UUID] = Field(
105
+ default=None,
106
+ title="The service account that is used to execute the action.",
107
+ )
108
+ auth_window: Optional[int] = Field(
109
+ default=None,
110
+ title="The time window in minutes for which the service account is "
111
+ "authorized to execute the action. Set this to 0 to authorize the "
112
+ "service account indefinitely (not recommended). If not set, a "
113
+ "default value defined for each individual action type is used.",
114
+ )
115
+
116
+ @classmethod
117
+ def from_response(cls, response: "ActionResponse") -> "ActionUpdate":
118
+ """Create an update model from a response model.
119
+
120
+ Args:
121
+ response: The response model to create the update model from.
122
+
123
+ Returns:
124
+ The update model.
125
+ """
126
+ return ActionUpdate(
127
+ configuration=copy.deepcopy(response.configuration),
128
+ )
129
+
130
+
131
+ # ------------------ Response Model ------------------
132
+
133
+
134
+ class ActionResponseBody(WorkspaceScopedResponseBody):
135
+ """Response body for actions."""
136
+
137
+ flavor: str = Field(
138
+ title="The flavor of the action.",
139
+ max_length=STR_FIELD_MAX_LENGTH,
140
+ )
141
+ plugin_subtype: PluginSubType = Field(
142
+ title="The subtype of the action.",
143
+ max_length=STR_FIELD_MAX_LENGTH,
144
+ )
145
+
146
+
147
+ class ActionResponseMetadata(WorkspaceScopedResponseMetadata):
148
+ """Response metadata for actions."""
149
+
150
+ description: str = Field(
151
+ default="",
152
+ title="The description of the action.",
153
+ max_length=STR_FIELD_MAX_LENGTH,
154
+ )
155
+ configuration: Dict[str, Any] = Field(
156
+ title="The configuration for the action.",
157
+ )
158
+ auth_window: int = Field(
159
+ title="The time window in minutes for which the service account is "
160
+ "authorized to execute the action."
161
+ )
162
+
163
+
164
+ class ActionResponseResources(WorkspaceScopedResponseResources):
165
+ """Class for all resource models associated with the action entity."""
166
+
167
+ service_account: UserResponse = Field(
168
+ title="The service account that is used to execute the action.",
169
+ )
170
+
171
+
172
+ class ActionResponse(
173
+ WorkspaceScopedResponse[
174
+ ActionResponseBody, ActionResponseMetadata, ActionResponseResources
175
+ ]
176
+ ):
177
+ """Response model for actions."""
178
+
179
+ name: str = Field(
180
+ title="The name of the action.",
181
+ max_length=STR_FIELD_MAX_LENGTH,
182
+ )
183
+
184
+ def get_hydrated_version(self) -> "ActionResponse":
185
+ """Get the hydrated version of this action.
186
+
187
+ Returns:
188
+ An instance of the same entity with the metadata field attached.
189
+ """
190
+ from zenml.client import Client
191
+
192
+ return Client().zen_store.get_action(self.id)
193
+
194
+ # Body and metadata properties
195
+ @property
196
+ def flavor(self) -> str:
197
+ """The `flavor` property.
198
+
199
+ Returns:
200
+ the value of the property.
201
+ """
202
+ return self.get_body().flavor
203
+
204
+ @property
205
+ def plugin_subtype(self) -> PluginSubType:
206
+ """The `plugin_subtype` property.
207
+
208
+ Returns:
209
+ the value of the property.
210
+ """
211
+ return self.get_body().plugin_subtype
212
+
213
+ @property
214
+ def description(self) -> str:
215
+ """The `description` property.
216
+
217
+ Returns:
218
+ the value of the property.
219
+ """
220
+ return self.get_metadata().description
221
+
222
+ @property
223
+ def auth_window(self) -> int:
224
+ """The `auth_window` property.
225
+
226
+ Returns:
227
+ the value of the property.
228
+ """
229
+ return self.get_metadata().auth_window
230
+
231
+ @property
232
+ def configuration(self) -> Dict[str, Any]:
233
+ """The `configuration` property.
234
+
235
+ Returns:
236
+ the value of the property.
237
+ """
238
+ return self.get_metadata().configuration
239
+
240
+ def set_configuration(self, configuration: Dict[str, Any]) -> None:
241
+ """Set the `configuration` property.
242
+
243
+ Args:
244
+ configuration: The value to set.
245
+ """
246
+ self.get_metadata().configuration = configuration
247
+
248
+ # Resource properties
249
+ @property
250
+ def service_account(self) -> "UserResponse":
251
+ """The `service_account` property.
252
+
253
+ Returns:
254
+ the value of the property.
255
+ """
256
+ return self.get_resources().service_account
257
+
258
+
259
+ # ------------------ Filter Model ------------------
260
+
261
+
262
+ class ActionFilter(WorkspaceScopedFilter):
263
+ """Model to enable advanced filtering of all actions."""
264
+
265
+ name: Optional[str] = Field(
266
+ default=None,
267
+ description="Name of the action.",
268
+ )
269
+ flavor: Optional[str] = Field(
270
+ default=None,
271
+ title="The flavor of the action.",
272
+ )
273
+ plugin_subtype: Optional[str] = Field(
274
+ default=None,
275
+ title="The subtype of the action.",
276
+ )