zenml-nightly 0.75.0.dev20250312__py3-none-any.whl → 0.75.0.dev20250313__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 (160) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/artifacts/utils.py +0 -2
  5. zenml/cli/login.py +6 -0
  6. zenml/cli/model.py +7 -15
  7. zenml/cli/secret.py +47 -44
  8. zenml/cli/service_connectors.py +0 -1
  9. zenml/cli/stack.py +0 -1
  10. zenml/cli/tag.py +3 -5
  11. zenml/cli/utils.py +25 -23
  12. zenml/cli/workspace.py +79 -5
  13. zenml/client.py +615 -348
  14. zenml/config/global_config.py +16 -3
  15. zenml/config/pipeline_configurations.py +3 -2
  16. zenml/config/pipeline_run_configuration.py +2 -1
  17. zenml/config/secret_reference_mixin.py +1 -1
  18. zenml/constants.py +1 -3
  19. zenml/enums.py +0 -7
  20. zenml/event_hub/event_hub.py +3 -1
  21. zenml/exceptions.py +0 -24
  22. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  23. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  24. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  25. zenml/integrations/mlflow/steps/mlflow_registry.py +1 -1
  26. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  27. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +3 -3
  28. zenml/model/model.py +8 -8
  29. zenml/models/__init__.py +18 -1
  30. zenml/models/v2/base/base.py +0 -5
  31. zenml/models/v2/base/filter.py +1 -1
  32. zenml/models/v2/base/scoped.py +104 -121
  33. zenml/models/v2/core/api_key.py +1 -1
  34. zenml/models/v2/core/artifact.py +31 -18
  35. zenml/models/v2/core/artifact_version.py +42 -25
  36. zenml/models/v2/core/component.py +22 -33
  37. zenml/models/v2/core/device.py +3 -2
  38. zenml/models/v2/core/event_source.py +2 -2
  39. zenml/models/v2/core/flavor.py +19 -47
  40. zenml/models/v2/core/logs.py +1 -2
  41. zenml/models/v2/core/model.py +7 -4
  42. zenml/models/v2/core/model_version.py +36 -27
  43. zenml/models/v2/core/pipeline.py +1 -1
  44. zenml/models/v2/core/pipeline_run.py +5 -13
  45. zenml/models/v2/core/run_template.py +1 -2
  46. zenml/models/v2/core/schedule.py +0 -9
  47. zenml/models/v2/core/secret.py +93 -127
  48. zenml/models/v2/core/server_settings.py +2 -2
  49. zenml/models/v2/core/service.py +43 -12
  50. zenml/models/v2/core/service_connector.py +14 -16
  51. zenml/models/v2/core/stack.py +24 -26
  52. zenml/models/v2/core/step_run.py +3 -15
  53. zenml/models/v2/core/tag.py +41 -15
  54. zenml/models/v2/core/user.py +19 -2
  55. zenml/models/v2/misc/statistics.py +45 -0
  56. zenml/models/v2/misc/tag.py +27 -0
  57. zenml/orchestrators/cache_utils.py +1 -1
  58. zenml/orchestrators/input_utils.py +1 -0
  59. zenml/orchestrators/step_launcher.py +0 -1
  60. zenml/orchestrators/step_run_utils.py +0 -2
  61. zenml/orchestrators/step_runner.py +10 -1
  62. zenml/pipelines/build_utils.py +0 -2
  63. zenml/pipelines/pipeline_decorator.py +3 -2
  64. zenml/pipelines/pipeline_definition.py +4 -5
  65. zenml/pipelines/run_utils.py +3 -3
  66. zenml/service_connectors/service_connector.py +0 -7
  67. zenml/service_connectors/service_connector_utils.py +0 -1
  68. zenml/stack/authentication_mixin.py +1 -1
  69. zenml/stack/flavor.py +3 -14
  70. zenml/stack/stack_component.py +1 -5
  71. zenml/steps/step_context.py +19 -0
  72. zenml/utils/string_utils.py +1 -1
  73. zenml/utils/tag_utils.py +642 -0
  74. zenml/zen_server/cloud_utils.py +21 -0
  75. zenml/zen_server/exceptions.py +0 -6
  76. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  77. zenml/zen_server/rbac/models.py +65 -3
  78. zenml/zen_server/rbac/rbac_interface.py +9 -0
  79. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  80. zenml/zen_server/rbac/utils.py +156 -29
  81. zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -11
  82. zenml/zen_server/routers/actions_endpoints.py +3 -5
  83. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  84. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  85. zenml/zen_server/routers/auth_endpoints.py +22 -7
  86. zenml/zen_server/routers/code_repositories_endpoints.py +56 -3
  87. zenml/zen_server/routers/devices_endpoints.py +0 -4
  88. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  89. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  90. zenml/zen_server/routers/logs_endpoints.py +0 -1
  91. zenml/zen_server/routers/model_versions_endpoints.py +102 -23
  92. zenml/zen_server/routers/models_endpoints.py +51 -68
  93. zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
  94. zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
  95. zenml/zen_server/routers/pipelines_endpoints.py +73 -4
  96. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  97. zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
  98. zenml/zen_server/routers/run_templates_endpoints.py +66 -3
  99. zenml/zen_server/routers/runs_endpoints.py +60 -8
  100. zenml/zen_server/routers/schedule_endpoints.py +69 -6
  101. zenml/zen_server/routers/secrets_endpoints.py +40 -4
  102. zenml/zen_server/routers/server_endpoints.py +53 -1
  103. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  104. zenml/zen_server/routers/service_connectors_endpoints.py +96 -14
  105. zenml/zen_server/routers/service_endpoints.py +20 -7
  106. zenml/zen_server/routers/stack_components_endpoints.py +68 -7
  107. zenml/zen_server/routers/stacks_endpoints.py +98 -7
  108. zenml/zen_server/routers/steps_endpoints.py +17 -11
  109. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  110. zenml/zen_server/routers/tags_endpoints.py +6 -17
  111. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  112. zenml/zen_server/routers/users_endpoints.py +47 -12
  113. zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
  114. zenml/zen_server/template_execution/utils.py +5 -4
  115. zenml/zen_server/utils.py +21 -0
  116. zenml/zen_server/zen_server_api.py +4 -0
  117. zenml/zen_stores/base_zen_store.py +29 -44
  118. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  119. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  120. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  121. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  122. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  123. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  124. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  125. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  126. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  127. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  128. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  129. zenml/zen_stores/rest_zen_store.py +172 -171
  130. zenml/zen_stores/schemas/action_schemas.py +8 -1
  131. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  132. zenml/zen_stores/schemas/artifact_schemas.py +28 -1
  133. zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
  134. zenml/zen_stores/schemas/component_schemas.py +9 -14
  135. zenml/zen_stores/schemas/event_source_schemas.py +8 -1
  136. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  137. zenml/zen_stores/schemas/model_schemas.py +3 -0
  138. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
  139. zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
  140. zenml/zen_stores/schemas/run_template_schemas.py +8 -4
  141. zenml/zen_stores/schemas/schedule_schema.py +9 -14
  142. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  143. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  144. zenml/zen_stores/schemas/service_schemas.py +0 -1
  145. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  146. zenml/zen_stores/schemas/step_run_schemas.py +7 -8
  147. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  148. zenml/zen_stores/schemas/trigger_schemas.py +8 -1
  149. zenml/zen_stores/schemas/user_schemas.py +24 -2
  150. zenml/zen_stores/schemas/utils.py +16 -0
  151. zenml/zen_stores/schemas/workspace_schemas.py +7 -25
  152. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  153. zenml/zen_stores/sql_zen_store.py +2905 -2280
  154. zenml/zen_stores/template_utils.py +1 -1
  155. zenml/zen_stores/zen_store_interface.py +82 -58
  156. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
  157. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +160 -147
  158. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
  159. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
  160. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
@@ -19,7 +19,7 @@ from typing import TYPE_CHECKING, Any, List, Optional
19
19
  from uuid import UUID
20
20
 
21
21
  from pydantic.json import pydantic_encoder
22
- from sqlalchemy import TEXT, Column
22
+ from sqlalchemy import TEXT, Column, UniqueConstraint
23
23
  from sqlmodel import Field, Relationship
24
24
 
25
25
  from zenml.models import (
@@ -44,6 +44,13 @@ class ActionSchema(NamedSchema, table=True):
44
44
  """SQL Model for actions."""
45
45
 
46
46
  __tablename__ = "action"
47
+ __table_args__ = (
48
+ UniqueConstraint(
49
+ "name",
50
+ "workspace_id",
51
+ name="unique_action_name_in_workspace",
52
+ ),
53
+ )
47
54
 
48
55
  workspace_id: UUID = build_foreign_key_field(
49
56
  source=__tablename__,
@@ -19,7 +19,7 @@ from typing import Any, Optional, Tuple
19
19
  from uuid import UUID
20
20
 
21
21
  from passlib.context import CryptContext
22
- from sqlalchemy import TEXT, Column
22
+ from sqlalchemy import TEXT, Column, UniqueConstraint
23
23
  from sqlmodel import Field, Relationship
24
24
 
25
25
  from zenml.models import (
@@ -42,6 +42,13 @@ class APIKeySchema(NamedSchema, table=True):
42
42
  """SQL Model for API keys."""
43
43
 
44
44
  __tablename__ = "api_key"
45
+ __table_args__ = (
46
+ UniqueConstraint(
47
+ "name",
48
+ "service_account_id",
49
+ name="unique_api_key_name_in_service_account",
50
+ ),
51
+ )
45
52
 
46
53
  description: str = Field(sa_column=Column(TEXT))
47
54
  key: str
@@ -71,7 +71,8 @@ class ArtifactSchema(NamedSchema, table=True):
71
71
  __table_args__ = (
72
72
  UniqueConstraint(
73
73
  "name",
74
- name="unique_artifact_name",
74
+ "workspace_id",
75
+ name="unique_artifact_name_in_workspace",
75
76
  ),
76
77
  )
77
78
 
@@ -91,6 +92,28 @@ class ArtifactSchema(NamedSchema, table=True):
91
92
  ),
92
93
  )
93
94
 
95
+ workspace_id: UUID = build_foreign_key_field(
96
+ source=__tablename__,
97
+ target=WorkspaceSchema.__tablename__,
98
+ source_column="workspace_id",
99
+ target_column="id",
100
+ ondelete="CASCADE",
101
+ nullable=False,
102
+ )
103
+ workspace: "WorkspaceSchema" = Relationship()
104
+
105
+ user_id: Optional[UUID] = build_foreign_key_field(
106
+ source=__tablename__,
107
+ target=UserSchema.__tablename__,
108
+ source_column="user_id",
109
+ target_column="id",
110
+ ondelete="SET NULL",
111
+ nullable=True,
112
+ )
113
+ user: Optional["UserSchema"] = Relationship(
114
+ back_populates="artifacts",
115
+ )
116
+
94
117
  @property
95
118
  def latest_version(self) -> Optional["ArtifactVersionSchema"]:
96
119
  """Fetch the latest version for this artifact.
@@ -133,6 +156,8 @@ class ArtifactSchema(NamedSchema, table=True):
133
156
  return cls(
134
157
  name=artifact_request.name,
135
158
  has_custom_name=artifact_request.has_custom_name,
159
+ workspace_id=artifact_request.workspace,
160
+ user_id=artifact_request.user,
136
161
  )
137
162
 
138
163
  def to_model(
@@ -165,6 +190,7 @@ class ArtifactSchema(NamedSchema, table=True):
165
190
  tags=[tag.to_model() for tag in self.tags],
166
191
  latest_version_name=latest_name,
167
192
  latest_version_id=latest_id,
193
+ user=self.user.to_model() if self.user else None,
168
194
  )
169
195
 
170
196
  # Create the metadata of the model
@@ -172,6 +198,7 @@ class ArtifactSchema(NamedSchema, table=True):
172
198
  if include_metadata:
173
199
  metadata = ArtifactResponseMetadata(
174
200
  has_custom_name=self.has_custom_name,
201
+ workspace=self.workspace.to_model(),
175
202
  )
176
203
 
177
204
  return ArtifactResponse(
@@ -17,7 +17,7 @@ import json
17
17
  from typing import Any, Optional
18
18
  from uuid import UUID
19
19
 
20
- from sqlalchemy import TEXT, Column
20
+ from sqlalchemy import TEXT, Column, UniqueConstraint
21
21
  from sqlmodel import Field, Relationship
22
22
 
23
23
  from zenml.models import (
@@ -42,6 +42,13 @@ class CodeRepositorySchema(NamedSchema, table=True):
42
42
  """SQL Model for code repositories."""
43
43
 
44
44
  __tablename__ = "code_repository"
45
+ __table_args__ = (
46
+ UniqueConstraint(
47
+ "name",
48
+ "workspace_id",
49
+ name="unique_code_repository_name_in_workspace",
50
+ ),
51
+ )
45
52
 
46
53
  workspace_id: UUID = build_foreign_key_field(
47
54
  source=__tablename__,
@@ -18,6 +18,7 @@ import json
18
18
  from typing import TYPE_CHECKING, Any, List, Optional
19
19
  from uuid import UUID
20
20
 
21
+ from sqlalchemy import UniqueConstraint
21
22
  from sqlmodel import Relationship
22
23
 
23
24
  from zenml.enums import StackComponentType
@@ -37,7 +38,6 @@ from zenml.zen_stores.schemas.service_connector_schemas import (
37
38
  )
38
39
  from zenml.zen_stores.schemas.stack_schemas import StackCompositionSchema
39
40
  from zenml.zen_stores.schemas.user_schemas import UserSchema
40
- from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
41
41
 
42
42
  if TYPE_CHECKING:
43
43
  from zenml.zen_stores.schemas.flavor_schemas import FlavorSchema
@@ -51,22 +51,19 @@ class StackComponentSchema(NamedSchema, table=True):
51
51
  """SQL Model for stack components."""
52
52
 
53
53
  __tablename__ = "stack_component"
54
+ __table_args__ = (
55
+ UniqueConstraint(
56
+ "name",
57
+ "type",
58
+ name="unique_component_name_and_type",
59
+ ),
60
+ )
54
61
 
55
62
  type: str
56
63
  flavor: str
57
64
  configuration: bytes
58
65
  labels: Optional[bytes]
59
66
 
60
- workspace_id: UUID = build_foreign_key_field(
61
- source=__tablename__,
62
- target=WorkspaceSchema.__tablename__,
63
- source_column="workspace_id",
64
- target_column="id",
65
- ondelete="CASCADE",
66
- nullable=False,
67
- )
68
- workspace: "WorkspaceSchema" = Relationship(back_populates="components")
69
-
70
67
  user_id: Optional[UUID] = build_foreign_key_field(
71
68
  source=__tablename__,
72
69
  target=UserSchema.__tablename__,
@@ -132,7 +129,6 @@ class StackComponentSchema(NamedSchema, table=True):
132
129
  """
133
130
  return cls(
134
131
  name=request.name,
135
- workspace_id=request.workspace,
136
132
  user_id=request.user,
137
133
  type=request.type,
138
134
  flavor=request.flavor,
@@ -158,7 +154,7 @@ class StackComponentSchema(NamedSchema, table=True):
158
154
  The updated `StackComponentSchema`.
159
155
  """
160
156
  for field, value in component_update.model_dump(
161
- exclude_unset=True, exclude={"workspace", "user", "connector"}
157
+ exclude_unset=True, exclude={"user", "connector"}
162
158
  ).items():
163
159
  if field == "configuration":
164
160
  self.configuration = base64.b64encode(
@@ -209,7 +205,6 @@ class StackComponentSchema(NamedSchema, table=True):
209
205
  metadata = None
210
206
  if include_metadata:
211
207
  metadata = ComponentResponseMetadata(
212
- workspace=self.workspace.to_model(),
213
208
  configuration=json.loads(
214
209
  base64.b64decode(self.configuration).decode()
215
210
  ),
@@ -18,7 +18,7 @@ import json
18
18
  from typing import TYPE_CHECKING, Any, List, Optional, cast
19
19
  from uuid import UUID
20
20
 
21
- from sqlalchemy import TEXT, Column
21
+ from sqlalchemy import TEXT, Column, UniqueConstraint
22
22
  from sqlmodel import Field, Relationship
23
23
 
24
24
  from zenml import EventSourceResponseMetadata
@@ -46,6 +46,13 @@ class EventSourceSchema(NamedSchema, table=True):
46
46
  """SQL Model for tag."""
47
47
 
48
48
  __tablename__ = "event_source"
49
+ __table_args__ = (
50
+ UniqueConstraint(
51
+ "name",
52
+ "workspace_id",
53
+ name="unique_event_source_name_in_workspace",
54
+ ),
55
+ )
49
56
 
50
57
  workspace_id: UUID = build_foreign_key_field(
51
58
  source=__tablename__,
@@ -17,7 +17,7 @@ import json
17
17
  from typing import Any, Optional
18
18
  from uuid import UUID
19
19
 
20
- from sqlalchemy import TEXT, Column
20
+ from sqlalchemy import TEXT, Column, UniqueConstraint
21
21
  from sqlmodel import Field, Relationship
22
22
 
23
23
  from zenml.enums import StackComponentType
@@ -31,7 +31,6 @@ from zenml.utils.time_utils import utc_now
31
31
  from zenml.zen_stores.schemas.base_schemas import NamedSchema
32
32
  from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
33
33
  from zenml.zen_stores.schemas.user_schemas import UserSchema
34
- from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
35
34
 
36
35
 
37
36
  class FlavorSchema(NamedSchema, table=True):
@@ -45,6 +44,13 @@ class FlavorSchema(NamedSchema, table=True):
45
44
  """
46
45
 
47
46
  __tablename__ = "flavor"
47
+ __table_args__ = (
48
+ UniqueConstraint(
49
+ "name",
50
+ "type",
51
+ name="unique_flavor_name_and_type",
52
+ ),
53
+ )
48
54
 
49
55
  type: str
50
56
  source: str
@@ -54,18 +60,6 @@ class FlavorSchema(NamedSchema, table=True):
54
60
  connector_resource_type: Optional[str]
55
61
  connector_resource_id_attr: Optional[str]
56
62
 
57
- workspace_id: Optional[UUID] = build_foreign_key_field(
58
- source=__tablename__,
59
- target=WorkspaceSchema.__tablename__,
60
- source_column="workspace_id",
61
- target_column="id",
62
- ondelete="CASCADE",
63
- nullable=True,
64
- )
65
- workspace: Optional["WorkspaceSchema"] = Relationship(
66
- back_populates="flavors"
67
- )
68
-
69
63
  user_id: Optional[UUID] = build_foreign_key_field(
70
64
  source=__tablename__,
71
65
  target=UserSchema.__tablename__,
@@ -84,7 +78,10 @@ class FlavorSchema(NamedSchema, table=True):
84
78
 
85
79
  is_custom: bool = Field(default=True)
86
80
 
87
- def update(self, flavor_update: "FlavorUpdate") -> "FlavorSchema":
81
+ def update(
82
+ self,
83
+ flavor_update: "FlavorUpdate",
84
+ ) -> "FlavorSchema":
88
85
  """Update a `FlavorSchema` from a `FlavorUpdate`.
89
86
 
90
87
  Args:
@@ -94,7 +91,7 @@ class FlavorSchema(NamedSchema, table=True):
94
91
  The updated `FlavorSchema`.
95
92
  """
96
93
  for field, value in flavor_update.model_dump(
97
- exclude_unset=True, exclude={"workspace", "user"}
94
+ exclude_unset=True, exclude={"user"}
98
95
  ).items():
99
96
  if field == "config_schema":
100
97
  setattr(self, field, json.dumps(value))
@@ -129,22 +126,19 @@ class FlavorSchema(NamedSchema, table=True):
129
126
  integration=self.integration,
130
127
  source=self.source,
131
128
  logo_url=self.logo_url,
129
+ is_custom=self.is_custom,
132
130
  created=self.created,
133
131
  updated=self.updated,
134
132
  )
135
133
  metadata = None
136
134
  if include_metadata:
137
135
  metadata = FlavorResponseMetadata(
138
- workspace=self.workspace.to_model()
139
- if self.workspace
140
- else None,
141
136
  config_schema=json.loads(self.config_schema),
142
137
  connector_type=self.connector_type,
143
138
  connector_resource_type=self.connector_resource_type,
144
139
  connector_resource_id_attr=self.connector_resource_id_attr,
145
140
  docs_url=self.docs_url,
146
141
  sdk_docs_url=self.sdk_docs_url,
147
- is_custom=self.is_custom,
148
142
  )
149
143
  return FlavorResponse(
150
144
  id=self.id,
@@ -248,6 +248,9 @@ class ModelSchema(NamedSchema, table=True):
248
248
  for field, value in model_update.model_dump(
249
249
  exclude_unset=True, exclude_none=True
250
250
  ).items():
251
+ if field in ["add_tags", "remove_tags"]:
252
+ # Tags are handled separately
253
+ continue
251
254
  setattr(self, field, value)
252
255
  self.updated = utc_now()
253
256
  return self
@@ -148,7 +148,9 @@ class PipelineDeploymentSchema(BaseSchema, table=True):
148
148
  template_id: Optional[UUID] = None
149
149
 
150
150
  # SQLModel Relationships
151
- user: Optional["UserSchema"] = Relationship()
151
+ user: Optional["UserSchema"] = Relationship(
152
+ back_populates="deployments",
153
+ )
152
154
  workspace: "WorkspaceSchema" = Relationship()
153
155
  stack: Optional["StackSchema"] = Relationship()
154
156
  pipeline: Optional["PipelineSchema"] = Relationship()
@@ -251,7 +251,6 @@ class PipelineRunSchema(NamedSchema, RunMetadataInterface, table=True):
251
251
  pipeline_id=request.pipeline,
252
252
  deployment_id=request.deployment,
253
253
  trigger_execution_id=request.trigger_execution_id,
254
- model_version_id=request.model_version_id,
255
254
  )
256
255
 
257
256
  def fetch_metadata_collection(self) -> Dict[str, List[RunMetadataEntry]]:
@@ -435,8 +434,6 @@ class PipelineRunSchema(NamedSchema, RunMetadataInterface, table=True):
435
434
  if run_update.status:
436
435
  self.status = run_update.status.value
437
436
  self.end_time = run_update.end_time
438
- if run_update.model_version_id and self.model_version_id is None:
439
- self.model_version_id = run_update.model_version_id
440
437
 
441
438
  self.updated = utc_now()
442
439
  return self
@@ -32,7 +32,7 @@ from zenml.models import (
32
32
  RunTemplateUpdate,
33
33
  )
34
34
  from zenml.utils.time_utils import utc_now
35
- from zenml.zen_stores.schemas.base_schemas import BaseSchema
35
+ from zenml.zen_stores.schemas.base_schemas import NamedSchema
36
36
  from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
37
37
  from zenml.zen_stores.schemas.user_schemas import UserSchema
38
38
  from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
@@ -45,7 +45,7 @@ if TYPE_CHECKING:
45
45
  from zenml.zen_stores.schemas.tag_schemas import TagSchema
46
46
 
47
47
 
48
- class RunTemplateSchema(BaseSchema, table=True):
48
+ class RunTemplateSchema(NamedSchema, table=True):
49
49
  """SQL Model for run templates."""
50
50
 
51
51
  __tablename__ = "run_template"
@@ -57,7 +57,6 @@ class RunTemplateSchema(BaseSchema, table=True):
57
57
  ),
58
58
  )
59
59
 
60
- name: str = Field(nullable=False)
61
60
  description: Optional[str] = Field(
62
61
  sa_column=Column(
63
62
  String(length=MEDIUMTEXT_MAX_LENGTH).with_variant(
@@ -92,7 +91,9 @@ class RunTemplateSchema(BaseSchema, table=True):
92
91
  nullable=True,
93
92
  )
94
93
 
95
- user: Optional["UserSchema"] = Relationship()
94
+ user: Optional["UserSchema"] = Relationship(
95
+ back_populates="run_templates",
96
+ )
96
97
  workspace: "WorkspaceSchema" = Relationship()
97
98
  source_deployment: Optional["PipelineDeploymentSchema"] = Relationship(
98
99
  sa_relationship_kwargs={
@@ -180,6 +181,9 @@ class RunTemplateSchema(BaseSchema, table=True):
180
181
  for field, value in update.model_dump(
181
182
  exclude_unset=True, exclude_none=True
182
183
  ).items():
184
+ if field in ["add_tags", "remove_tags"]:
185
+ # Tags are handled separately
186
+ continue
183
187
  setattr(self, field, value)
184
188
 
185
189
  self.updated = utc_now()
@@ -17,6 +17,7 @@ from datetime import datetime, timedelta
17
17
  from typing import TYPE_CHECKING, Any, List, Optional
18
18
  from uuid import UUID
19
19
 
20
+ from sqlalchemy import UniqueConstraint
20
21
  from sqlmodel import Field, Relationship
21
22
 
22
23
  from zenml.enums import MetadataResourceTypes
@@ -49,6 +50,13 @@ class ScheduleSchema(NamedSchema, RunMetadataInterface, table=True):
49
50
  """SQL Model for schedules."""
50
51
 
51
52
  __tablename__ = "schedule"
53
+ __table_args__ = (
54
+ UniqueConstraint(
55
+ "name",
56
+ "workspace_id",
57
+ name="unique_schedule_name_in_workspace",
58
+ ),
59
+ )
52
60
 
53
61
  workspace_id: UUID = build_foreign_key_field(
54
62
  source=__tablename__,
@@ -154,20 +162,7 @@ class ScheduleSchema(NamedSchema, RunMetadataInterface, table=True):
154
162
  """
155
163
  if schedule_update.name is not None:
156
164
  self.name = schedule_update.name
157
- if schedule_update.active is not None:
158
- self.active = schedule_update.active
159
- if schedule_update.cron_expression is not None:
160
- self.cron_expression = schedule_update.cron_expression
161
- if schedule_update.start_time is not None:
162
- self.start_time = schedule_update.start_time
163
- if schedule_update.end_time is not None:
164
- self.end_time = schedule_update.end_time
165
- if schedule_update.interval_second is not None:
166
- self.interval_second = (
167
- schedule_update.interval_second.total_seconds()
168
- )
169
- if schedule_update.catchup is not None:
170
- self.catchup = schedule_update.catchup
165
+
171
166
  self.updated = utc_now()
172
167
  return self
173
168
 
@@ -18,7 +18,7 @@ import json
18
18
  from typing import Any, Dict, Optional, cast
19
19
  from uuid import UUID
20
20
 
21
- from sqlalchemy import TEXT, Column
21
+ from sqlalchemy import TEXT, Column, UniqueConstraint
22
22
  from sqlalchemy_utils.types.encrypted.encrypted_type import (
23
23
  AesGcmEngine,
24
24
  InvalidCiphertextError,
@@ -26,7 +26,6 @@ from sqlalchemy_utils.types.encrypted.encrypted_type import (
26
26
  from sqlmodel import Field, Relationship
27
27
 
28
28
  from zenml.constants import TEXT_FIELD_MAX_LENGTH
29
- from zenml.enums import SecretScope
30
29
  from zenml.models import (
31
30
  SecretRequest,
32
31
  SecretResponse,
@@ -38,7 +37,6 @@ from zenml.utils.time_utils import utc_now
38
37
  from zenml.zen_stores.schemas.base_schemas import NamedSchema
39
38
  from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
40
39
  from zenml.zen_stores.schemas.user_schemas import UserSchema
41
- from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
42
40
 
43
41
 
44
42
  class SecretDecodeError(Exception):
@@ -54,21 +52,19 @@ class SecretSchema(NamedSchema, table=True):
54
52
  """
55
53
 
56
54
  __tablename__ = "secret"
55
+ __table_args__ = (
56
+ UniqueConstraint(
57
+ "name",
58
+ "private",
59
+ "user_id",
60
+ name="unique_secret_name_private_scope_user",
61
+ ),
62
+ )
57
63
 
58
- scope: str
64
+ private: bool
59
65
 
60
66
  values: Optional[bytes] = Field(sa_column=Column(TEXT, nullable=True))
61
67
 
62
- workspace_id: UUID = build_foreign_key_field(
63
- source=__tablename__,
64
- target=WorkspaceSchema.__tablename__,
65
- source_column="workspace_id",
66
- target_column="id",
67
- ondelete="CASCADE",
68
- nullable=False,
69
- )
70
- workspace: "WorkspaceSchema" = Relationship(back_populates="secrets")
71
-
72
68
  user_id: UUID = build_foreign_key_field(
73
69
  source=__tablename__,
74
70
  target=UserSchema.__tablename__,
@@ -177,8 +173,7 @@ class SecretSchema(NamedSchema, table=True):
177
173
  assert secret.user is not None, "User must be set for secret creation."
178
174
  return cls(
179
175
  name=secret.name,
180
- scope=secret.scope.value,
181
- workspace_id=secret.workspace,
176
+ private=secret.private,
182
177
  user_id=secret.user,
183
178
  # Don't store secret values implicitly in the secret. The
184
179
  # SQL secret store will call `store_secret_values` to store the
@@ -202,12 +197,9 @@ class SecretSchema(NamedSchema, table=True):
202
197
  # SQL secret store will call `set_secret_values` to update the
203
198
  # values separately if SQL is used as the secrets store.
204
199
  for field, value in secret_update.model_dump(
205
- exclude_unset=True, exclude={"workspace", "user", "values"}
200
+ exclude_unset=True, exclude={"user", "values"}
206
201
  ).items():
207
- if field == "scope":
208
- setattr(self, field, value.value)
209
- else:
210
- setattr(self, field, value)
202
+ setattr(self, field, value)
211
203
 
212
204
  self.updated = utc_now()
213
205
  return self
@@ -231,9 +223,7 @@ class SecretSchema(NamedSchema, table=True):
231
223
  """
232
224
  metadata = None
233
225
  if include_metadata:
234
- metadata = SecretResponseMetadata(
235
- workspace=self.workspace.to_model(),
236
- )
226
+ metadata = SecretResponseMetadata()
237
227
 
238
228
  # Don't load the secret values implicitly in the secret. The
239
229
  # SQL secret store will call `get_secret_values` to load the
@@ -242,7 +232,7 @@ class SecretSchema(NamedSchema, table=True):
242
232
  user=self.user.to_model() if self.user else None,
243
233
  created=self.created,
244
234
  updated=self.updated,
245
- scope=SecretScope(self.scope),
235
+ private=self.private,
246
236
  )
247
237
  return SecretResponse(
248
238
  id=self.id,
@@ -19,7 +19,7 @@ from datetime import datetime
19
19
  from typing import TYPE_CHECKING, Any, Dict, List, Optional, cast
20
20
  from uuid import UUID
21
21
 
22
- from sqlalchemy import TEXT, Column
22
+ from sqlalchemy import TEXT, Column, UniqueConstraint
23
23
  from sqlmodel import Field, Relationship
24
24
 
25
25
  from zenml.models import (
@@ -33,7 +33,6 @@ from zenml.utils.time_utils import utc_now
33
33
  from zenml.zen_stores.schemas.base_schemas import NamedSchema
34
34
  from zenml.zen_stores.schemas.schema_utils import build_foreign_key_field
35
35
  from zenml.zen_stores.schemas.user_schemas import UserSchema
36
- from zenml.zen_stores.schemas.workspace_schemas import WorkspaceSchema
37
36
 
38
37
  if TYPE_CHECKING:
39
38
  from zenml.zen_stores.schemas.component_schemas import StackComponentSchema
@@ -43,6 +42,12 @@ class ServiceConnectorSchema(NamedSchema, table=True):
43
42
  """SQL Model for service connectors."""
44
43
 
45
44
  __tablename__ = "service_connector"
45
+ __table_args__ = (
46
+ UniqueConstraint(
47
+ "name",
48
+ name="unique_service_connector_name",
49
+ ),
50
+ )
46
51
 
47
52
  connector_type: str = Field(sa_column=Column(TEXT))
48
53
  description: str
@@ -57,18 +62,6 @@ class ServiceConnectorSchema(NamedSchema, table=True):
57
62
  expiration_seconds: Optional[int]
58
63
  labels: Optional[bytes]
59
64
 
60
- workspace_id: UUID = build_foreign_key_field(
61
- source=__tablename__,
62
- target=WorkspaceSchema.__tablename__,
63
- source_column="workspace_id",
64
- target_column="id",
65
- ondelete="CASCADE",
66
- nullable=False,
67
- )
68
- workspace: "WorkspaceSchema" = Relationship(
69
- back_populates="service_connectors"
70
- )
71
-
72
65
  user_id: Optional[UUID] = build_foreign_key_field(
73
66
  source=__tablename__,
74
67
  target=UserSchema.__tablename__,
@@ -146,7 +139,6 @@ class ServiceConnectorSchema(NamedSchema, table=True):
146
139
  """
147
140
  assert connector_request.user is not None, "User must be set."
148
141
  return cls(
149
- workspace_id=connector_request.workspace,
150
142
  user_id=connector_request.user,
151
143
  name=connector_request.name,
152
144
  description=connector_request.description,
@@ -189,7 +181,7 @@ class ServiceConnectorSchema(NamedSchema, table=True):
189
181
  """
190
182
  for field, value in connector_update.model_dump(
191
183
  exclude_unset=False,
192
- exclude={"workspace", "user", "secrets"},
184
+ exclude={"user", "secrets"},
193
185
  ).items():
194
186
  if value is None:
195
187
  if field == "resource_id":
@@ -264,7 +256,6 @@ class ServiceConnectorSchema(NamedSchema, table=True):
264
256
  metadata = None
265
257
  if include_metadata:
266
258
  metadata = ServiceConnectorResponseMetadata(
267
- workspace=self.workspace.to_model(),
268
259
  configuration=json.loads(
269
260
  base64.b64decode(self.configuration).decode()
270
261
  )
@@ -135,7 +135,6 @@ class ServiceSchema(NamedSchema, table=True):
135
135
  """
136
136
  body = ServiceResponseBody(
137
137
  user=self.user.to_model() if self.user else None,
138
- workspace=self.workspace.to_model(),
139
138
  created=self.created,
140
139
  updated=self.updated,
141
140
  service_type=json.loads(self.service_type),