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
@@ -13,43 +13,52 @@
13
13
  # permissions and limitations under the License.
14
14
  """Models representing secrets."""
15
15
 
16
- from datetime import datetime
17
- from typing import Any, ClassVar, Dict, List, Optional, Union
16
+ from typing import (
17
+ TYPE_CHECKING,
18
+ ClassVar,
19
+ Dict,
20
+ List,
21
+ Optional,
22
+ Type,
23
+ TypeVar,
24
+ )
18
25
 
19
26
  from pydantic import Field, SecretStr
20
27
 
21
28
  from zenml.constants import STR_FIELD_MAX_LENGTH
22
- from zenml.enums import (
23
- GenericFilterOps,
24
- LogicalOperators,
25
- SecretScope,
26
- SorterOps,
27
- )
28
29
  from zenml.models.v2.base.base import BaseUpdate
30
+ from zenml.models.v2.base.filter import AnyQuery
29
31
  from zenml.models.v2.base.scoped import (
30
- WorkspaceScopedFilter,
31
- WorkspaceScopedRequest,
32
- WorkspaceScopedResponse,
33
- WorkspaceScopedResponseBody,
34
- WorkspaceScopedResponseMetadata,
35
- WorkspaceScopedResponseResources,
32
+ UserScopedFilter,
33
+ UserScopedRequest,
34
+ UserScopedResponse,
35
+ UserScopedResponseBody,
36
+ UserScopedResponseMetadata,
37
+ UserScopedResponseResources,
36
38
  )
37
39
  from zenml.utils.secret_utils import PlainSerializedSecretStr
38
40
 
41
+ if TYPE_CHECKING:
42
+ from zenml.zen_stores.schemas.base_schemas import BaseSchema
43
+
44
+ AnySchema = TypeVar("AnySchema", bound=BaseSchema)
45
+
39
46
  # ------------------ Request Model ------------------
40
47
 
41
48
 
42
- class SecretRequest(WorkspaceScopedRequest):
43
- """Request models for secrets."""
49
+ class SecretRequest(UserScopedRequest):
50
+ """Request model for secrets."""
44
51
 
45
- ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]
52
+ ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
46
53
 
47
54
  name: str = Field(
48
55
  title="The name of the secret.",
49
56
  max_length=STR_FIELD_MAX_LENGTH,
50
57
  )
51
- scope: SecretScope = Field(
52
- SecretScope.WORKSPACE, title="The scope of the secret."
58
+ private: bool = Field(
59
+ False,
60
+ title="Whether the secret is private. A private secret is only "
61
+ "accessible to the user who created it.",
53
62
  )
54
63
  values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
55
64
  default_factory=dict, title="The values stored in this secret."
@@ -78,17 +87,19 @@ class SecretRequest(WorkspaceScopedRequest):
78
87
 
79
88
 
80
89
  class SecretUpdate(BaseUpdate):
81
- """Secret update model."""
90
+ """Update model for secrets."""
82
91
 
83
- ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]
92
+ ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
84
93
 
85
94
  name: Optional[str] = Field(
86
95
  title="The name of the secret.",
87
96
  max_length=STR_FIELD_MAX_LENGTH,
88
97
  default=None,
89
98
  )
90
- scope: Optional[SecretScope] = Field(
91
- default=None, title="The scope of the secret."
99
+ private: Optional[bool] = Field(
100
+ default=None,
101
+ title="Whether the secret is private. A private secret is only "
102
+ "accessible to the user who created it.",
92
103
  )
93
104
  values: Optional[Dict[str, Optional[PlainSerializedSecretStr]]] = Field(
94
105
  title="The values stored in this secret.",
@@ -113,33 +124,37 @@ class SecretUpdate(BaseUpdate):
113
124
  # ------------------ Response Model ------------------
114
125
 
115
126
 
116
- class SecretResponseBody(WorkspaceScopedResponseBody):
127
+ class SecretResponseBody(UserScopedResponseBody):
117
128
  """Response body for secrets."""
118
129
 
119
- scope: SecretScope = Field(
120
- SecretScope.WORKSPACE, title="The scope of the secret."
130
+ private: bool = Field(
131
+ False,
132
+ title="Whether the secret is private. A private secret is only "
133
+ "accessible to the user who created it.",
121
134
  )
122
135
  values: Dict[str, Optional[PlainSerializedSecretStr]] = Field(
123
136
  default_factory=dict, title="The values stored in this secret."
124
137
  )
125
138
 
126
139
 
127
- class SecretResponseMetadata(WorkspaceScopedResponseMetadata):
140
+ class SecretResponseMetadata(UserScopedResponseMetadata):
128
141
  """Response metadata for secrets."""
129
142
 
130
143
 
131
- class SecretResponseResources(WorkspaceScopedResponseResources):
132
- """Class for all resource models associated with the secret entity."""
144
+ class SecretResponseResources(UserScopedResponseResources):
145
+ """Response resources for secrets."""
133
146
 
134
147
 
135
148
  class SecretResponse(
136
- WorkspaceScopedResponse[
137
- SecretResponseBody, SecretResponseMetadata, SecretResponseResources
149
+ UserScopedResponse[
150
+ SecretResponseBody,
151
+ SecretResponseMetadata,
152
+ SecretResponseResources,
138
153
  ]
139
154
  ):
140
155
  """Response model for secrets."""
141
156
 
142
- ANALYTICS_FIELDS: ClassVar[List[str]] = ["scope"]
157
+ ANALYTICS_FIELDS: ClassVar[List[str]] = ["private"]
143
158
 
144
159
  name: str = Field(
145
160
  title="The name of the secret.",
@@ -159,13 +174,13 @@ class SecretResponse(
159
174
  # Body and metadata properties
160
175
 
161
176
  @property
162
- def scope(self) -> SecretScope:
163
- """The `scope` property.
177
+ def private(self) -> bool:
178
+ """The `private` property.
164
179
 
165
180
  Returns:
166
181
  the value of the property.
167
182
  """
168
- return self.get_body().scope
183
+ return self.get_body().private
169
184
 
170
185
  @property
171
186
  def values(self) -> Dict[str, Optional[SecretStr]]:
@@ -240,11 +255,11 @@ class SecretResponse(
240
255
  # ------------------ Filter Model ------------------
241
256
 
242
257
 
243
- class SecretFilter(WorkspaceScopedFilter):
244
- """Model to enable advanced filtering of all Secrets."""
258
+ class SecretFilter(UserScopedFilter):
259
+ """Model to enable advanced secret filtering."""
245
260
 
246
261
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
247
- *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
262
+ *UserScopedFilter.FILTER_EXCLUDE_FIELDS,
248
263
  "values",
249
264
  ]
250
265
 
@@ -252,103 +267,54 @@ class SecretFilter(WorkspaceScopedFilter):
252
267
  default=None,
253
268
  description="Name of the secret",
254
269
  )
255
- scope: Optional[Union[SecretScope, str]] = Field(
270
+ private: Optional[bool] = Field(
256
271
  default=None,
257
- description="Scope in which to filter secrets",
258
- union_mode="left_to_right",
272
+ description="Whether to filter secrets by private status",
259
273
  )
260
274
 
261
- @staticmethod
262
- def _get_filtering_value(value: Optional[Any]) -> str:
263
- """Convert the value to a string that can be used for lexicographical filtering and sorting.
275
+ def apply_filter(
276
+ self,
277
+ query: AnyQuery,
278
+ table: Type["AnySchema"],
279
+ ) -> AnyQuery:
280
+ """Applies the filter to a query.
264
281
 
265
282
  Args:
266
- value: The value to convert.
283
+ query: The query to which to apply the filter.
284
+ table: The query table.
267
285
 
268
286
  Returns:
269
- The value converted to string format that can be used for
270
- lexicographical sorting and filtering.
287
+ The query with filter applied.
271
288
  """
272
- if value is None:
273
- return ""
274
- str_value = str(value)
275
- if isinstance(value, datetime):
276
- str_value = value.strftime("%Y-%m-%d %H:%M:%S")
277
- return str_value
278
-
279
- def secret_matches(self, secret: SecretResponse) -> bool:
280
- """Checks if a secret matches the filter criteria.
281
-
282
- Args:
283
- secret: The secret to check.
289
+ # The secret user scoping works a bit differently than the other
290
+ # scoped filters. We have to filter out all private secrets that are
291
+ # not owned by the current user.
292
+ if not self.scope_user:
293
+ return super().apply_filter(query=query, table=table)
294
+
295
+ scope_user = self.scope_user
296
+
297
+ # First we apply the inherited filters without the user scoping
298
+ # applied.
299
+ self.scope_user = None
300
+ query = super().apply_filter(query=query, table=table)
301
+ self.scope_user = scope_user
302
+
303
+ # Then we apply the user scoping filter.
304
+ if self.scope_user:
305
+ from sqlmodel import and_, or_
306
+
307
+ query = query.where(
308
+ or_(
309
+ and_(
310
+ getattr(table, "user_id") == self.scope_user,
311
+ getattr(table, "private") == True, # noqa: E712
312
+ ),
313
+ getattr(table, "private") == False, # noqa: E712
314
+ )
315
+ )
284
316
 
285
- Returns:
286
- True if the secret matches the filter criteria, False otherwise.
287
- """
288
- for filter in self.list_of_filters:
289
- column_value: Optional[Any] = None
290
- if filter.column == "workspace_id":
291
- column_value = secret.workspace.id
292
- elif filter.column == "user_id":
293
- column_value = secret.user.id if secret.user else None
294
- else:
295
- column_value = getattr(secret, filter.column)
296
-
297
- # Convert the values to strings for lexicographical comparison.
298
- str_column_value = self._get_filtering_value(column_value)
299
- str_filter_value = self._get_filtering_value(filter.value)
300
-
301
- # Compare the lexicographical values according to the operation.
302
- if filter.operation == GenericFilterOps.EQUALS:
303
- result = str_column_value == str_filter_value
304
- elif filter.operation == GenericFilterOps.CONTAINS:
305
- result = str_filter_value in str_column_value
306
- elif filter.operation == GenericFilterOps.STARTSWITH:
307
- result = str_column_value.startswith(str_filter_value)
308
- elif filter.operation == GenericFilterOps.ENDSWITH:
309
- result = str_column_value.endswith(str_filter_value)
310
- elif filter.operation == GenericFilterOps.GT:
311
- result = str_column_value > str_filter_value
312
- elif filter.operation == GenericFilterOps.GTE:
313
- result = str_column_value >= str_filter_value
314
- elif filter.operation == GenericFilterOps.LT:
315
- result = str_column_value < str_filter_value
316
- elif filter.operation == GenericFilterOps.LTE:
317
- result = str_column_value <= str_filter_value
318
-
319
- # Exit early if the result is False for AND, and True for OR
320
- if self.logical_operator == LogicalOperators.AND:
321
- if not result:
322
- return False
323
- else:
324
- if result:
325
- return True
326
-
327
- # If we get here, all filters have been checked and the result is
328
- # True for AND, and False for OR
329
- if self.logical_operator == LogicalOperators.AND:
330
- return True
331
317
  else:
332
- return False
318
+ query = query.where(getattr(table, "private") == False) # noqa: E712
333
319
 
334
- def sort_secrets(
335
- self, secrets: List[SecretResponse]
336
- ) -> List[SecretResponse]:
337
- """Sorts a list of secrets according to the filter criteria.
338
-
339
- Args:
340
- secrets: The list of secrets to sort.
341
-
342
- Returns:
343
- The sorted list of secrets.
344
- """
345
- column, sort_op = self.sorting_params
346
- sorted_secrets = sorted(
347
- secrets,
348
- key=lambda secret: self._get_filtering_value(
349
- getattr(secret, column)
350
- ),
351
- reverse=sort_op == SorterOps.DESCENDING,
352
- )
353
-
354
- return sorted_secrets
320
+ return query
@@ -26,7 +26,7 @@ from zenml.models.v2.base.base import (
26
26
  BaseResponseBody,
27
27
  BaseResponseMetadata,
28
28
  BaseResponseResources,
29
- BaseZenModel,
29
+ BaseUpdate,
30
30
  )
31
31
 
32
32
  # ------------------ Base Model ------------------
@@ -34,7 +34,7 @@ from zenml.models.v2.base.base import (
34
34
  # ------------------ Update Model ------------------
35
35
 
36
36
 
37
- class ServerSettingsUpdate(BaseZenModel):
37
+ class ServerSettingsUpdate(BaseUpdate):
38
38
  """Model for updating server settings."""
39
39
 
40
40
  server_name: Optional[str] = Field(
@@ -27,10 +27,11 @@ from typing import (
27
27
  )
28
28
  from uuid import UUID
29
29
 
30
- from pydantic import BaseModel, ConfigDict, Field
30
+ from pydantic import ConfigDict, Field
31
31
  from sqlalchemy.sql.elements import ColumnElement
32
32
 
33
33
  from zenml.constants import STR_FIELD_MAX_LENGTH
34
+ from zenml.models.v2.base.base import BaseUpdate
34
35
  from zenml.models.v2.base.scoped import (
35
36
  WorkspaceScopedFilter,
36
37
  WorkspaceScopedRequest,
@@ -43,6 +44,8 @@ from zenml.services.service_status import ServiceState
43
44
  from zenml.services.service_type import ServiceType
44
45
 
45
46
  if TYPE_CHECKING:
47
+ from zenml.models.v2.core.model_version import ModelVersionResponse
48
+ from zenml.models.v2.core.pipeline_run import PipelineRunResponse
46
49
  from zenml.zen_stores.schemas import BaseSchema
47
50
 
48
51
  AnySchema = TypeVar("AnySchema", bound=BaseSchema)
@@ -101,10 +104,9 @@ class ServiceRequest(WorkspaceScopedRequest):
101
104
  default=None,
102
105
  title="The model version id linked to the service.",
103
106
  )
104
- pipeline_run_id: Optional[Union[UUID, str]] = Field(
107
+ pipeline_run_id: Optional[UUID] = Field(
105
108
  default=None,
106
- description="By the event source this trigger is attached to.",
107
- union_mode="left_to_right",
109
+ title="The pipeline run id linked to the service.",
108
110
  )
109
111
 
110
112
  # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
@@ -119,7 +121,7 @@ class ServiceRequest(WorkspaceScopedRequest):
119
121
  # ------------------ Update Model ------------------
120
122
 
121
123
 
122
- class ServiceUpdate(BaseModel):
124
+ class ServiceUpdate(BaseUpdate):
123
125
  """Update model for stack components."""
124
126
 
125
127
  name: Optional[str] = Field(
@@ -230,6 +232,23 @@ class ServiceResponseMetadata(WorkspaceScopedResponseMetadata):
230
232
  class ServiceResponseResources(WorkspaceScopedResponseResources):
231
233
  """Class for all resource models associated with the service entity."""
232
234
 
235
+ pipeline_run: Optional["PipelineRunResponse"] = Field(
236
+ default=None,
237
+ title="The pipeline run associated with the service.",
238
+ )
239
+ model_version: Optional["ModelVersionResponse"] = Field(
240
+ default=None,
241
+ title="The model version associated with the service.",
242
+ )
243
+
244
+ # TODO: In Pydantic v2, the `model_` is a protected namespaces for all
245
+ # fields defined under base models. If not handled, this raises a warning.
246
+ # It is possible to suppress this warning message with the following
247
+ # configuration, however the ultimate solution is to rename these fields.
248
+ # Even though they do not cause any problems right now, if we are not
249
+ # careful we might overwrite some fields protected by pydantic.
250
+ model_config = ConfigDict(protected_namespaces=())
251
+
233
252
 
234
253
  class ServiceResponse(
235
254
  WorkspaceScopedResponse[
@@ -363,18 +382,30 @@ class ServiceResponse(
363
382
  """
364
383
  return self.get_body().state
365
384
 
385
+ @property
386
+ def pipeline_run(self) -> Optional["PipelineRunResponse"]:
387
+ """The `pipeline_run` property.
388
+
389
+ Returns:
390
+ the value of the property.
391
+ """
392
+ return self.get_resources().pipeline_run
393
+
394
+ @property
395
+ def model_version(self) -> Optional["ModelVersionResponse"]:
396
+ """The `model_version` property.
397
+
398
+ Returns:
399
+ the value of the property.
400
+ """
401
+ return self.get_resources().model_version
402
+
366
403
 
367
404
  # ------------------ Filter Model ------------------
368
405
 
369
406
 
370
407
  class ServiceFilter(WorkspaceScopedFilter):
371
- """Model to enable advanced filtering of services.
372
-
373
- The Service needs additional scoping. As such the `_scope_user` field
374
- can be set to the user that is doing the filtering. The
375
- `generate_filter()` method of the baseclass is overwritten to include the
376
- scoping.
377
- """
408
+ """Model to enable advanced filtering of services."""
378
409
 
379
410
  name: Optional[str] = Field(
380
411
  default=None,
@@ -24,12 +24,12 @@ from zenml.constants import STR_FIELD_MAX_LENGTH
24
24
  from zenml.logger import get_logger
25
25
  from zenml.models.v2.base.base import BaseUpdate
26
26
  from zenml.models.v2.base.scoped import (
27
- WorkspaceScopedFilter,
28
- WorkspaceScopedRequest,
29
- WorkspaceScopedResponse,
30
- WorkspaceScopedResponseBody,
31
- WorkspaceScopedResponseMetadata,
32
- WorkspaceScopedResponseResources,
27
+ UserScopedFilter,
28
+ UserScopedRequest,
29
+ UserScopedResponse,
30
+ UserScopedResponseBody,
31
+ UserScopedResponseMetadata,
32
+ UserScopedResponseResources,
33
33
  )
34
34
  from zenml.models.v2.misc.service_connector_type import (
35
35
  ServiceConnectorTypeModel,
@@ -41,7 +41,7 @@ logger = get_logger(__name__)
41
41
  # ------------------ Request Model ------------------
42
42
 
43
43
 
44
- class ServiceConnectorRequest(WorkspaceScopedRequest):
44
+ class ServiceConnectorRequest(UserScopedRequest):
45
45
  """Request model for service connectors."""
46
46
 
47
47
  name: str = Field(
@@ -223,8 +223,6 @@ class ServiceConnectorUpdate(BaseUpdate):
223
223
  valid configuration update, not just a partial update. If either is
224
224
  set (i.e. not None) in the update, their values are merged together and
225
225
  will replace the existing configuration and secrets values.
226
- * the `secret_id` field value in the update is ignored, given that
227
- secrets are managed internally by the ZenML store.
228
226
  * the `labels` field is also a full labels update: if set (i.e. not
229
227
  `None`), all existing labels are removed and replaced by the new labels
230
228
  in the update.
@@ -400,7 +398,7 @@ class ServiceConnectorUpdate(BaseUpdate):
400
398
  # ------------------ Response Model ------------------
401
399
 
402
400
 
403
- class ServiceConnectorResponseBody(WorkspaceScopedResponseBody):
401
+ class ServiceConnectorResponseBody(UserScopedResponseBody):
404
402
  """Response body for service connectors."""
405
403
 
406
404
  description: str = Field(
@@ -446,7 +444,7 @@ class ServiceConnectorResponseBody(WorkspaceScopedResponseBody):
446
444
  )
447
445
 
448
446
 
449
- class ServiceConnectorResponseMetadata(WorkspaceScopedResponseMetadata):
447
+ class ServiceConnectorResponseMetadata(UserScopedResponseMetadata):
450
448
  """Response metadata for service connectors."""
451
449
 
452
450
  configuration: Dict[str, Any] = Field(
@@ -475,12 +473,12 @@ class ServiceConnectorResponseMetadata(WorkspaceScopedResponseMetadata):
475
473
  )
476
474
 
477
475
 
478
- class ServiceConnectorResponseResources(WorkspaceScopedResponseResources):
476
+ class ServiceConnectorResponseResources(UserScopedResponseResources):
479
477
  """Class for all resource models associated with the service connector entity."""
480
478
 
481
479
 
482
480
  class ServiceConnectorResponse(
483
- WorkspaceScopedResponse[
481
+ UserScopedResponse[
484
482
  ServiceConnectorResponseBody,
485
483
  ServiceConnectorResponseMetadata,
486
484
  ServiceConnectorResponseResources,
@@ -781,18 +779,18 @@ class ServiceConnectorResponse(
781
779
  # ------------------ Filter Model ------------------
782
780
 
783
781
 
784
- class ServiceConnectorFilter(WorkspaceScopedFilter):
782
+ class ServiceConnectorFilter(UserScopedFilter):
785
783
  """Model to enable advanced filtering of service connectors."""
786
784
 
787
785
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
788
- *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
786
+ *UserScopedFilter.FILTER_EXCLUDE_FIELDS,
789
787
  "scope_type",
790
788
  "resource_type",
791
789
  "labels_str",
792
790
  "labels",
793
791
  ]
794
792
  CLI_EXCLUDE_FIELDS: ClassVar[List[str]] = [
795
- *WorkspaceScopedFilter.CLI_EXCLUDE_FIELDS,
793
+ *UserScopedFilter.CLI_EXCLUDE_FIELDS,
796
794
  "scope_type",
797
795
  "labels_str",
798
796
  "labels",
@@ -32,13 +32,14 @@ from sqlmodel import and_
32
32
 
33
33
  from zenml.constants import STR_FIELD_MAX_LENGTH
34
34
  from zenml.enums import StackComponentType
35
- from zenml.models.v2.base.base import BaseRequest, BaseUpdate
35
+ from zenml.models.v2.base.base import BaseUpdate
36
36
  from zenml.models.v2.base.scoped import (
37
- WorkspaceScopedFilter,
38
- WorkspaceScopedResponse,
39
- WorkspaceScopedResponseBody,
40
- WorkspaceScopedResponseMetadata,
41
- WorkspaceScopedResponseResources,
37
+ UserScopedFilter,
38
+ UserScopedRequest,
39
+ UserScopedResponse,
40
+ UserScopedResponseBody,
41
+ UserScopedResponseMetadata,
42
+ UserScopedResponseResources,
42
43
  )
43
44
  from zenml.models.v2.misc.info_models import (
44
45
  ComponentInfo,
@@ -57,11 +58,8 @@ if TYPE_CHECKING:
57
58
  # ------------------ Request Model ------------------
58
59
 
59
60
 
60
- class StackRequest(BaseRequest):
61
- """Request model for a stack."""
62
-
63
- user: Optional[UUID] = None
64
- workspace: Optional[UUID] = None
61
+ class StackRequest(UserScopedRequest):
62
+ """Request model for stack creation."""
65
63
 
66
64
  name: str = Field(
67
65
  title="The name of the stack.", max_length=STR_FIELD_MAX_LENGTH
@@ -131,6 +129,10 @@ class StackRequest(BaseRequest):
131
129
  return self
132
130
 
133
131
 
132
+ class DefaultStackRequest(StackRequest):
133
+ """Internal stack request model used only for default stacks."""
134
+
135
+
134
136
  # ------------------ Update Model ------------------
135
137
 
136
138
 
@@ -165,11 +167,11 @@ class StackUpdate(BaseUpdate):
165
167
  # ------------------ Response Model ------------------
166
168
 
167
169
 
168
- class StackResponseBody(WorkspaceScopedResponseBody):
170
+ class StackResponseBody(UserScopedResponseBody):
169
171
  """Response body for stacks."""
170
172
 
171
173
 
172
- class StackResponseMetadata(WorkspaceScopedResponseMetadata):
174
+ class StackResponseMetadata(UserScopedResponseMetadata):
173
175
  """Response metadata for stacks."""
174
176
 
175
177
  components: Dict[StackComponentType, List["ComponentResponse"]] = Field(
@@ -191,13 +193,15 @@ class StackResponseMetadata(WorkspaceScopedResponseMetadata):
191
193
  )
192
194
 
193
195
 
194
- class StackResponseResources(WorkspaceScopedResponseResources):
195
- """Class for all resource models associated with the stack entity."""
196
+ class StackResponseResources(UserScopedResponseResources):
197
+ """Response resources for stacks."""
196
198
 
197
199
 
198
200
  class StackResponse(
199
- WorkspaceScopedResponse[
200
- StackResponseBody, StackResponseMetadata, StackResponseResources
201
+ UserScopedResponse[
202
+ StackResponseBody,
203
+ StackResponseMetadata,
204
+ StackResponseResources,
201
205
  ]
202
206
  ):
203
207
  """Response model for stacks."""
@@ -324,17 +328,11 @@ class StackResponse(
324
328
  # ------------------ Filter Model ------------------
325
329
 
326
330
 
327
- class StackFilter(WorkspaceScopedFilter):
328
- """Model to enable advanced filtering of all StackModels.
329
-
330
- The Stack Model needs additional scoping. As such the `_scope_user` field
331
- can be set to the user that is doing the filtering. The
332
- `generate_filter()` method of the baseclass is overwritten to include the
333
- scoping.
334
- """
331
+ class StackFilter(UserScopedFilter):
332
+ """Model to enable advanced stack filtering."""
335
333
 
336
334
  FILTER_EXCLUDE_FIELDS: ClassVar[List[str]] = [
337
- *WorkspaceScopedFilter.FILTER_EXCLUDE_FIELDS,
335
+ *UserScopedFilter.FILTER_EXCLUDE_FIELDS,
338
336
  "component_id",
339
337
  "component",
340
338
  ]
@@ -27,12 +27,13 @@ from typing import (
27
27
  )
28
28
  from uuid import UUID
29
29
 
30
- from pydantic import BaseModel, ConfigDict, Field
30
+ from pydantic import ConfigDict, Field
31
31
 
32
32
  from zenml.config.step_configurations import StepConfiguration, StepSpec
33
33
  from zenml.constants import STR_FIELD_MAX_LENGTH, TEXT_FIELD_MAX_LENGTH
34
34
  from zenml.enums import ExecutionStatus, StepRunInputArtifactType
35
35
  from zenml.metadata.metadata_types import MetadataType
36
+ from zenml.models.v2.base.base import BaseUpdate
36
37
  from zenml.models.v2.base.scoped import (
37
38
  WorkspaceScopedFilter,
38
39
  WorkspaceScopedRequest,
@@ -137,14 +138,6 @@ class StepRunRequest(WorkspaceScopedRequest):
137
138
  title="Logs associated with this step run.",
138
139
  default=None,
139
140
  )
140
- deployment: UUID = Field(
141
- title="The deployment associated with the step run."
142
- )
143
- model_version_id: Optional[UUID] = Field(
144
- title="The ID of the model version that was "
145
- "configured by this step run explicitly.",
146
- default=None,
147
- )
148
141
 
149
142
  model_config = ConfigDict(protected_namespaces=())
150
143
 
@@ -152,7 +145,7 @@ class StepRunRequest(WorkspaceScopedRequest):
152
145
  # ------------------ Update Model ------------------
153
146
 
154
147
 
155
- class StepRunUpdate(BaseModel):
148
+ class StepRunUpdate(BaseUpdate):
156
149
  """Update model for step runs."""
157
150
 
158
151
  outputs: Dict[str, List[UUID]] = Field(
@@ -171,11 +164,6 @@ class StepRunUpdate(BaseModel):
171
164
  title="The end time of the step run.",
172
165
  default=None,
173
166
  )
174
- model_version_id: Optional[UUID] = Field(
175
- title="The ID of the model version that was "
176
- "configured by this step run explicitly.",
177
- default=None,
178
- )
179
167
  model_config = ConfigDict(protected_namespaces=())
180
168
 
181
169