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,38 +13,36 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for models."""
15
15
 
16
- from typing import Union
16
+ from typing import Optional, Union
17
17
  from uuid import UUID
18
18
 
19
19
  from fastapi import APIRouter, Depends, Security
20
20
 
21
21
  from zenml.constants import (
22
22
  API,
23
- MODEL_VERSIONS,
24
23
  MODELS,
25
24
  VERSION_1,
26
25
  )
27
26
  from zenml.models import (
28
27
  ModelFilter,
28
+ ModelRequest,
29
29
  ModelResponse,
30
30
  ModelUpdate,
31
- ModelVersionFilter,
32
- ModelVersionResponse,
33
31
  Page,
34
32
  )
35
33
  from zenml.zen_server.auth import AuthContext, authorize
36
34
  from zenml.zen_server.exceptions import error_response
37
35
  from zenml.zen_server.feature_gate.endpoint_utils import report_decrement
38
36
  from zenml.zen_server.rbac.endpoint_utils import (
37
+ verify_permissions_and_create_entity,
39
38
  verify_permissions_and_delete_entity,
40
39
  verify_permissions_and_get_entity,
41
40
  verify_permissions_and_list_entities,
42
41
  verify_permissions_and_update_entity,
43
42
  )
44
43
  from zenml.zen_server.rbac.models import ResourceType
45
- from zenml.zen_server.rbac.utils import (
46
- dehydrate_page,
47
- get_allowed_resource_ids,
44
+ from zenml.zen_server.routers.workspaces_endpoints import (
45
+ router as workspace_router,
48
46
  )
49
47
  from zenml.zen_server.utils import (
50
48
  handle_exceptions,
@@ -64,9 +62,45 @@ router = APIRouter(
64
62
  )
65
63
 
66
64
 
65
+ @router.post(
66
+ "",
67
+ responses={401: error_response, 409: error_response, 422: error_response},
68
+ )
69
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
70
+ # and can be removed after the migration
71
+ @workspace_router.post(
72
+ "/{workspace_name_or_id}" + MODELS,
73
+ responses={401: error_response, 409: error_response, 422: error_response},
74
+ deprecated=True,
75
+ tags=["models"],
76
+ )
77
+ @handle_exceptions
78
+ def create_model(
79
+ model: ModelRequest,
80
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
81
+ _: AuthContext = Security(authorize),
82
+ ) -> ModelResponse:
83
+ """Creates a model.
84
+
85
+ Args:
86
+ model: Model to create.
87
+ workspace_name_or_id: Optional name or ID of the workspace.
88
+
89
+ Returns:
90
+ The created model.
91
+ """
92
+ if workspace_name_or_id:
93
+ workspace = zen_store().get_workspace(workspace_name_or_id)
94
+ model.workspace = workspace.id
95
+
96
+ return verify_permissions_and_create_entity(
97
+ request_model=model,
98
+ create_method=zen_store().create_model,
99
+ )
100
+
101
+
67
102
  @router.get(
68
103
  "",
69
- response_model=Page[ModelResponse],
70
104
  responses={401: error_response, 404: error_response, 422: error_response},
71
105
  )
72
106
  @handle_exceptions
@@ -95,20 +129,19 @@ def list_models(
95
129
 
96
130
 
97
131
  @router.get(
98
- "/{model_name_or_id}",
99
- response_model=ModelResponse,
132
+ "/{model_id}",
100
133
  responses={401: error_response, 404: error_response, 422: error_response},
101
134
  )
102
135
  @handle_exceptions
103
136
  def get_model(
104
- model_name_or_id: Union[str, UUID],
137
+ model_id: UUID,
105
138
  hydrate: bool = True,
106
139
  _: AuthContext = Security(authorize),
107
140
  ) -> ModelResponse:
108
141
  """Get a model by name or ID.
109
142
 
110
143
  Args:
111
- model_name_or_id: The name or ID of the model to get.
144
+ model_id: The ID of the model to get.
112
145
  hydrate: Flag deciding whether to hydrate the output model(s)
113
146
  by including metadata fields in the response.
114
147
 
@@ -116,13 +149,12 @@ def get_model(
116
149
  The model with the given name or ID.
117
150
  """
118
151
  return verify_permissions_and_get_entity(
119
- id=model_name_or_id, get_method=zen_store().get_model, hydrate=hydrate
152
+ id=model_id, get_method=zen_store().get_model, hydrate=hydrate
120
153
  )
121
154
 
122
155
 
123
156
  @router.put(
124
157
  "/{model_id}",
125
- response_model=ModelResponse,
126
158
  responses={401: error_response, 404: error_response, 422: error_response},
127
159
  )
128
160
  @handle_exceptions
@@ -149,21 +181,21 @@ def update_model(
149
181
 
150
182
 
151
183
  @router.delete(
152
- "/{model_name_or_id}",
184
+ "/{model_id}",
153
185
  responses={401: error_response, 404: error_response, 422: error_response},
154
186
  )
155
187
  @handle_exceptions
156
188
  def delete_model(
157
- model_name_or_id: Union[str, UUID],
189
+ model_id: UUID,
158
190
  _: AuthContext = Security(authorize),
159
191
  ) -> None:
160
- """Delete a model by name or ID.
192
+ """Delete a model by ID.
161
193
 
162
194
  Args:
163
- model_name_or_id: The name or ID of the model to delete.
195
+ model_id: The ID of the model to delete.
164
196
  """
165
197
  model = verify_permissions_and_delete_entity(
166
- id=model_name_or_id,
198
+ id=model_id,
167
199
  get_method=zen_store().get_model,
168
200
  delete_method=zen_store().delete_model,
169
201
  )
@@ -171,52 +203,3 @@ def delete_model(
171
203
  if server_config().feature_gate_enabled:
172
204
  if ResourceType.MODEL in server_config().reportable_resources:
173
205
  report_decrement(ResourceType.MODEL, resource_id=model.id)
174
-
175
-
176
- #################
177
- # Model Versions
178
- #################
179
-
180
-
181
- @router.get(
182
- "/{model_name_or_id}" + MODEL_VERSIONS,
183
- response_model=Page[ModelVersionResponse],
184
- responses={401: error_response, 404: error_response, 422: error_response},
185
- )
186
- @handle_exceptions
187
- def list_model_versions(
188
- model_name_or_id: Union[str, UUID],
189
- model_version_filter_model: ModelVersionFilter = Depends(
190
- make_dependable(ModelVersionFilter)
191
- ),
192
- hydrate: bool = False,
193
- auth_context: AuthContext = Security(authorize),
194
- ) -> Page[ModelVersionResponse]:
195
- """Get model versions according to query filters.
196
-
197
- This endpoint serves the purpose of allowing scoped filtering by model_id.
198
-
199
- Args:
200
- model_name_or_id: The name or ID of the model to list in.
201
- model_version_filter_model: Filter model used for pagination, sorting,
202
- filtering.
203
- hydrate: Flag deciding whether to hydrate the output model(s)
204
- by including metadata fields in the response.
205
- auth_context: The authentication context.
206
-
207
- Returns:
208
- The model versions according to query filters.
209
- """
210
- allowed_model_ids = get_allowed_resource_ids(
211
- resource_type=ResourceType.MODEL
212
- )
213
- model_version_filter_model.configure_rbac(
214
- authenticated_user_id=auth_context.user.id, model_id=allowed_model_ids
215
- )
216
-
217
- model_versions = zen_store().list_model_versions(
218
- model_name_or_id=model_name_or_id,
219
- model_version_filter_model=model_version_filter_model,
220
- hydrate=hydrate,
221
- )
222
- return dehydrate_page(model_versions)
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for builds."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -21,16 +22,21 @@ from zenml.constants import API, PIPELINE_BUILDS, VERSION_1
21
22
  from zenml.models import (
22
23
  Page,
23
24
  PipelineBuildFilter,
25
+ PipelineBuildRequest,
24
26
  PipelineBuildResponse,
25
27
  )
26
28
  from zenml.zen_server.auth import AuthContext, authorize
27
29
  from zenml.zen_server.exceptions import error_response
28
30
  from zenml.zen_server.rbac.endpoint_utils import (
31
+ verify_permissions_and_create_entity,
29
32
  verify_permissions_and_delete_entity,
30
33
  verify_permissions_and_get_entity,
31
34
  verify_permissions_and_list_entities,
32
35
  )
33
36
  from zenml.zen_server.rbac.models import ResourceType
37
+ from zenml.zen_server.routers.workspaces_endpoints import (
38
+ router as workspace_router,
39
+ )
34
40
  from zenml.zen_server.utils import (
35
41
  handle_exceptions,
36
42
  make_dependable,
@@ -44,30 +50,79 @@ router = APIRouter(
44
50
  )
45
51
 
46
52
 
53
+ @router.post(
54
+ "",
55
+ responses={401: error_response, 409: error_response, 422: error_response},
56
+ )
57
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
58
+ # and can be removed after the migration
59
+ @workspace_router.post(
60
+ "/{workspace_name_or_id}" + PIPELINE_BUILDS,
61
+ responses={401: error_response, 409: error_response, 422: error_response},
62
+ deprecated=True,
63
+ tags=["builds"],
64
+ )
65
+ @handle_exceptions
66
+ def create_build(
67
+ build: PipelineBuildRequest,
68
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
69
+ _: AuthContext = Security(authorize),
70
+ ) -> PipelineBuildResponse:
71
+ """Creates a build, optionally in a specific workspace.
72
+
73
+ Args:
74
+ build: Build to create.
75
+ workspace_name_or_id: Optional name or ID of the workspace.
76
+
77
+ Returns:
78
+ The created build.
79
+ """
80
+ if workspace_name_or_id:
81
+ workspace = zen_store().get_workspace(workspace_name_or_id)
82
+ build.workspace = workspace.id
83
+
84
+ return verify_permissions_and_create_entity(
85
+ request_model=build,
86
+ create_method=zen_store().create_build,
87
+ )
88
+
89
+
47
90
  @router.get(
48
91
  "",
49
- response_model=Page[PipelineBuildResponse],
50
92
  responses={401: error_response, 404: error_response, 422: error_response},
51
93
  )
94
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
95
+ # and can be removed after the migration
96
+ @workspace_router.get(
97
+ "/{workspace_name_or_id}" + PIPELINE_BUILDS,
98
+ responses={401: error_response, 404: error_response, 422: error_response},
99
+ deprecated=True,
100
+ tags=["builds"],
101
+ )
52
102
  @handle_exceptions
53
103
  def list_builds(
54
104
  build_filter_model: PipelineBuildFilter = Depends(
55
105
  make_dependable(PipelineBuildFilter)
56
106
  ),
107
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
57
108
  hydrate: bool = False,
58
109
  _: AuthContext = Security(authorize),
59
110
  ) -> Page[PipelineBuildResponse]:
60
- """Gets a list of builds.
111
+ """Gets a list of builds, optionally filtered by workspace.
61
112
 
62
113
  Args:
63
114
  build_filter_model: Filter model used for pagination, sorting,
64
115
  filtering.
116
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
65
117
  hydrate: Flag deciding whether to hydrate the output model(s)
66
118
  by including metadata fields in the response.
67
119
 
68
120
  Returns:
69
- List of build objects.
121
+ List of build objects matching the filter criteria.
70
122
  """
123
+ if workspace_name_or_id:
124
+ build_filter_model.workspace = workspace_name_or_id
125
+
71
126
  return verify_permissions_and_list_entities(
72
127
  filter_model=build_filter_model,
73
128
  resource_type=ResourceType.PIPELINE_BUILD,
@@ -78,7 +133,6 @@ def list_builds(
78
133
 
79
134
  @router.get(
80
135
  "/{build_id}",
81
- response_model=PipelineBuildResponse,
82
136
  responses={401: error_response, 404: error_response, 422: error_response},
83
137
  )
84
138
  @handle_exceptions
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for deployments."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -21,16 +22,21 @@ from zenml.constants import API, PIPELINE_DEPLOYMENTS, VERSION_1
21
22
  from zenml.models import (
22
23
  Page,
23
24
  PipelineDeploymentFilter,
25
+ PipelineDeploymentRequest,
24
26
  PipelineDeploymentResponse,
25
27
  )
26
28
  from zenml.zen_server.auth import AuthContext, authorize
27
29
  from zenml.zen_server.exceptions import error_response
28
30
  from zenml.zen_server.rbac.endpoint_utils import (
31
+ verify_permissions_and_create_entity,
29
32
  verify_permissions_and_delete_entity,
30
33
  verify_permissions_and_get_entity,
31
34
  verify_permissions_and_list_entities,
32
35
  )
33
36
  from zenml.zen_server.rbac.models import ResourceType
37
+ from zenml.zen_server.routers.workspaces_endpoints import (
38
+ router as workspace_router,
39
+ )
34
40
  from zenml.zen_server.utils import (
35
41
  handle_exceptions,
36
42
  make_dependable,
@@ -46,30 +52,79 @@ router = APIRouter(
46
52
  )
47
53
 
48
54
 
55
+ @router.post(
56
+ "",
57
+ responses={401: error_response, 409: error_response, 422: error_response},
58
+ )
59
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
60
+ # and can be removed after the migration
61
+ @workspace_router.post(
62
+ "/{workspace_name_or_id}" + PIPELINE_DEPLOYMENTS,
63
+ responses={401: error_response, 409: error_response, 422: error_response},
64
+ deprecated=True,
65
+ tags=["deployments"],
66
+ )
67
+ @handle_exceptions
68
+ def create_deployment(
69
+ deployment: PipelineDeploymentRequest,
70
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
71
+ _: AuthContext = Security(authorize),
72
+ ) -> PipelineDeploymentResponse:
73
+ """Creates a deployment.
74
+
75
+ Args:
76
+ deployment: Deployment to create.
77
+ workspace_name_or_id: Optional name or ID of the workspace.
78
+
79
+ Returns:
80
+ The created deployment.
81
+ """
82
+ if workspace_name_or_id:
83
+ workspace = zen_store().get_workspace(workspace_name_or_id)
84
+ deployment.workspace = workspace.id
85
+
86
+ return verify_permissions_and_create_entity(
87
+ request_model=deployment,
88
+ create_method=zen_store().create_deployment,
89
+ )
90
+
91
+
49
92
  @router.get(
50
93
  "",
51
- response_model=Page[PipelineDeploymentResponse],
52
94
  responses={401: error_response, 404: error_response, 422: error_response},
53
95
  )
96
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
97
+ # and can be removed after the migration
98
+ @workspace_router.get(
99
+ "/{workspace_name_or_id}" + PIPELINE_DEPLOYMENTS,
100
+ responses={401: error_response, 404: error_response, 422: error_response},
101
+ deprecated=True,
102
+ tags=["deployments"],
103
+ )
54
104
  @handle_exceptions
55
105
  def list_deployments(
56
106
  deployment_filter_model: PipelineDeploymentFilter = Depends(
57
107
  make_dependable(PipelineDeploymentFilter)
58
108
  ),
109
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
59
110
  hydrate: bool = False,
60
111
  _: AuthContext = Security(authorize),
61
112
  ) -> Page[PipelineDeploymentResponse]:
62
- """Gets a list of deployment.
113
+ """Gets a list of deployments, optionally filtered by workspace.
63
114
 
64
115
  Args:
65
116
  deployment_filter_model: Filter model used for pagination, sorting,
66
117
  filtering.
118
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
67
119
  hydrate: Flag deciding whether to hydrate the output model(s)
68
120
  by including metadata fields in the response.
69
121
 
70
122
  Returns:
71
- List of deployment objects.
123
+ List of deployment objects matching the filter criteria.
72
124
  """
125
+ if workspace_name_or_id:
126
+ deployment_filter_model.workspace = workspace_name_or_id
127
+
73
128
  return verify_permissions_and_list_entities(
74
129
  filter_model=deployment_filter_model,
75
130
  resource_type=ResourceType.PIPELINE_DEPLOYMENT,
@@ -80,7 +135,6 @@ def list_deployments(
80
135
 
81
136
  @router.get(
82
137
  "/{deployment_id}",
83
- response_model=PipelineDeploymentResponse,
84
138
  responses={401: error_response, 404: error_response, 422: error_response},
85
139
  )
86
140
  @handle_exceptions
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for pipelines."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -26,6 +27,7 @@ from zenml.constants import (
26
27
  from zenml.models import (
27
28
  Page,
28
29
  PipelineFilter,
30
+ PipelineRequest,
29
31
  PipelineResponse,
30
32
  PipelineRunFilter,
31
33
  PipelineRunResponse,
@@ -33,14 +35,20 @@ from zenml.models import (
33
35
  )
34
36
  from zenml.zen_server.auth import AuthContext, authorize
35
37
  from zenml.zen_server.exceptions import error_response
36
- from zenml.zen_server.feature_gate.endpoint_utils import report_decrement
38
+ from zenml.zen_server.feature_gate.endpoint_utils import (
39
+ report_decrement,
40
+ )
37
41
  from zenml.zen_server.rbac.endpoint_utils import (
42
+ verify_permissions_and_create_entity,
38
43
  verify_permissions_and_delete_entity,
39
44
  verify_permissions_and_get_entity,
40
45
  verify_permissions_and_list_entities,
41
46
  verify_permissions_and_update_entity,
42
47
  )
43
48
  from zenml.zen_server.rbac.models import ResourceType
49
+ from zenml.zen_server.routers.workspaces_endpoints import (
50
+ router as workspace_router,
51
+ )
44
52
  from zenml.zen_server.utils import (
45
53
  handle_exceptions,
46
54
  make_dependable,
@@ -55,29 +63,88 @@ router = APIRouter(
55
63
  )
56
64
 
57
65
 
66
+ @router.post(
67
+ "",
68
+ responses={401: error_response, 409: error_response, 422: error_response},
69
+ )
70
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
71
+ # and can be removed after the migration
72
+ @workspace_router.post(
73
+ "/{workspace_name_or_id}" + PIPELINES,
74
+ responses={401: error_response, 409: error_response, 422: error_response},
75
+ deprecated=True,
76
+ tags=["pipelines"],
77
+ )
78
+ @handle_exceptions
79
+ def create_pipeline(
80
+ pipeline: PipelineRequest,
81
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
82
+ _: AuthContext = Security(authorize),
83
+ ) -> PipelineResponse:
84
+ """Creates a pipeline, optionally in a specific workspace.
85
+
86
+ Args:
87
+ pipeline: Pipeline to create.
88
+ workspace_name_or_id: Optional name or ID of the workspace.
89
+
90
+ Returns:
91
+ The created pipeline.
92
+ """
93
+ if workspace_name_or_id:
94
+ workspace = zen_store().get_workspace(workspace_name_or_id)
95
+ pipeline.workspace = workspace.id
96
+
97
+ # We limit pipeline namespaces, not pipeline versions
98
+ skip_entitlements = (
99
+ zen_store().count_pipelines(
100
+ PipelineFilter(name=pipeline.name, workspace=pipeline.workspace)
101
+ )
102
+ > 0
103
+ )
104
+
105
+ return verify_permissions_and_create_entity(
106
+ request_model=pipeline,
107
+ create_method=zen_store().create_pipeline,
108
+ skip_entitlements=skip_entitlements,
109
+ )
110
+
111
+
58
112
  @router.get(
59
113
  "",
60
114
  responses={401: error_response, 404: error_response, 422: error_response},
61
115
  )
116
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
117
+ # and can be removed after the migration
118
+ @workspace_router.get(
119
+ "/{workspace_name_or_id}" + PIPELINES,
120
+ responses={401: error_response, 404: error_response, 422: error_response},
121
+ deprecated=True,
122
+ tags=["pipelines"],
123
+ )
62
124
  @handle_exceptions
63
125
  def list_pipelines(
64
126
  pipeline_filter_model: PipelineFilter = Depends(
65
127
  make_dependable(PipelineFilter)
66
128
  ),
129
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
67
130
  hydrate: bool = False,
68
131
  _: AuthContext = Security(authorize),
69
132
  ) -> Page[PipelineResponse]:
70
- """Gets a list of pipelines.
133
+ """Gets a list of pipelines, optionally filtered by workspace.
71
134
 
72
135
  Args:
73
136
  pipeline_filter_model: Filter model used for pagination, sorting,
74
137
  filtering.
138
+ workspace_name_or_id: Optional name or ID of the workspace to filter by.
75
139
  hydrate: Flag deciding whether to hydrate the output model(s)
76
140
  by including metadata fields in the response.
77
141
 
78
142
  Returns:
79
- List of pipeline objects.
143
+ List of pipeline objects matching the filter criteria.
80
144
  """
145
+ if workspace_name_or_id:
146
+ pipeline_filter_model.workspace = workspace_name_or_id
147
+
81
148
  return verify_permissions_and_list_entities(
82
149
  filter_model=pipeline_filter_model,
83
150
  resource_type=ResourceType.PIPELINE,
@@ -160,7 +227,9 @@ def delete_pipeline(
160
227
 
161
228
  should_decrement = (
162
229
  ResourceType.PIPELINE in server_config().reportable_resources
163
- and zen_store().count_pipelines(PipelineFilter(name=pipeline.name))
230
+ and zen_store().count_pipelines(
231
+ PipelineFilter(name=pipeline.name, workspace=pipeline.workspace.id)
232
+ )
164
233
  == 0
165
234
  )
166
235
  if should_decrement:
@@ -81,7 +81,6 @@ def list_flavors(
81
81
 
82
82
  @plugin_router.get(
83
83
  "/{name}",
84
- response_model=BasePluginFlavorResponse,
85
84
  responses={401: error_response, 404: error_response, 422: error_response},
86
85
  )
87
86
  @handle_exceptions
@@ -0,0 +1,99 @@
1
+ # Copyright (c) ZenML GmbH 2025. 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
+ """Endpoint definitions for run metadata."""
15
+
16
+ from typing import Any, List, Optional, Union
17
+ from uuid import UUID
18
+
19
+ from fastapi import APIRouter, Security
20
+
21
+ from zenml.constants import API, RUN_METADATA, VERSION_1
22
+ from zenml.enums import MetadataResourceTypes
23
+ from zenml.models import RunMetadataRequest
24
+ from zenml.zen_server.auth import AuthContext, authorize
25
+ from zenml.zen_server.exceptions import error_response
26
+ from zenml.zen_server.rbac.models import Action
27
+ from zenml.zen_server.rbac.utils import (
28
+ batch_verify_permissions_for_models,
29
+ verify_permission_for_model,
30
+ )
31
+ from zenml.zen_server.routers.workspaces_endpoints import (
32
+ router as workspace_router,
33
+ )
34
+ from zenml.zen_server.utils import handle_exceptions, zen_store
35
+
36
+ router = APIRouter(
37
+ prefix=API + VERSION_1 + RUN_METADATA,
38
+ tags=["run_metadata"],
39
+ responses={401: error_response, 403: error_response},
40
+ )
41
+
42
+
43
+ @router.post(
44
+ "",
45
+ responses={401: error_response, 409: error_response, 422: error_response},
46
+ )
47
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
48
+ # and can be removed after the migration
49
+ @workspace_router.post(
50
+ "/{workspace_name_or_id}" + RUN_METADATA,
51
+ responses={401: error_response, 409: error_response, 422: error_response},
52
+ deprecated=True,
53
+ tags=["run_metadata"],
54
+ )
55
+ @handle_exceptions
56
+ def create_run_metadata(
57
+ run_metadata: RunMetadataRequest,
58
+ workspace_name_or_id: Optional[Union[str, UUID]] = None,
59
+ auth_context: AuthContext = Security(authorize),
60
+ ) -> None:
61
+ """Creates run metadata.
62
+
63
+ Args:
64
+ run_metadata: The run metadata to create.
65
+ workspace_name_or_id: Optional name or ID of the workspace.
66
+ auth_context: Authentication context.
67
+
68
+ Raises:
69
+ RuntimeError: If the resource type is not supported.
70
+ """
71
+ if workspace_name_or_id:
72
+ workspace = zen_store().get_workspace(workspace_name_or_id)
73
+ run_metadata.workspace = workspace.id
74
+
75
+ run_metadata.user = auth_context.user.id
76
+
77
+ verify_models: List[Any] = []
78
+ for resource in run_metadata.resources:
79
+ if resource.type == MetadataResourceTypes.PIPELINE_RUN:
80
+ verify_models.append(zen_store().get_run(resource.id))
81
+ elif resource.type == MetadataResourceTypes.STEP_RUN:
82
+ verify_models.append(zen_store().get_run_step(resource.id))
83
+ elif resource.type == MetadataResourceTypes.ARTIFACT_VERSION:
84
+ verify_models.append(zen_store().get_artifact_version(resource.id))
85
+ elif resource.type == MetadataResourceTypes.MODEL_VERSION:
86
+ verify_models.append(zen_store().get_model_version(resource.id))
87
+ elif resource.type == MetadataResourceTypes.SCHEDULE:
88
+ verify_models.append(zen_store().get_schedule(resource.id))
89
+ else:
90
+ raise RuntimeError(f"Unknown resource type: {resource.type}")
91
+
92
+ batch_verify_permissions_for_models(
93
+ models=verify_models,
94
+ action=Action.UPDATE,
95
+ )
96
+
97
+ verify_permission_for_model(model=run_metadata, action=Action.CREATE)
98
+
99
+ zen_store().create_run_metadata(run_metadata)