zenml-nightly 0.75.0.dev20250312__py3-none-any.whl → 0.75.0.dev20250314__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 (191) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/analytics/enums.py +2 -2
  5. zenml/artifacts/utils.py +2 -4
  6. zenml/cli/__init__.py +8 -9
  7. zenml/cli/base.py +2 -2
  8. zenml/cli/code_repository.py +1 -1
  9. zenml/cli/login.py +6 -0
  10. zenml/cli/model.py +7 -15
  11. zenml/cli/pipeline.py +3 -3
  12. zenml/cli/project.py +172 -0
  13. zenml/cli/secret.py +47 -44
  14. zenml/cli/service_accounts.py +0 -1
  15. zenml/cli/service_connectors.py +15 -17
  16. zenml/cli/stack.py +0 -3
  17. zenml/cli/stack_components.py +2 -2
  18. zenml/cli/tag.py +3 -5
  19. zenml/cli/utils.py +25 -23
  20. zenml/client.py +749 -475
  21. zenml/config/global_config.py +48 -37
  22. zenml/config/pipeline_configurations.py +3 -2
  23. zenml/config/pipeline_run_configuration.py +2 -1
  24. zenml/config/secret_reference_mixin.py +1 -1
  25. zenml/constants.py +6 -6
  26. zenml/enums.py +0 -7
  27. zenml/event_hub/event_hub.py +3 -1
  28. zenml/exceptions.py +0 -24
  29. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  30. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  31. zenml/integrations/gcp/service_connectors/gcp_service_connector.py +7 -6
  32. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  33. zenml/integrations/mlflow/steps/mlflow_registry.py +3 -3
  34. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  35. zenml/integrations/wandb/__init__.py +1 -1
  36. zenml/integrations/wandb/experiment_trackers/wandb_experiment_tracker.py +29 -9
  37. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +5 -3
  38. zenml/model/model.py +10 -10
  39. zenml/model_registries/base_model_registry.py +1 -1
  40. zenml/models/__init__.py +45 -28
  41. zenml/models/v2/base/base.py +0 -5
  42. zenml/models/v2/base/filter.py +2 -2
  43. zenml/models/v2/base/scoped.py +135 -156
  44. zenml/models/v2/core/action.py +12 -12
  45. zenml/models/v2/core/api_key.py +1 -1
  46. zenml/models/v2/core/artifact.py +31 -18
  47. zenml/models/v2/core/artifact_version.py +57 -40
  48. zenml/models/v2/core/code_repository.py +12 -12
  49. zenml/models/v2/core/component.py +22 -33
  50. zenml/models/v2/core/device.py +3 -2
  51. zenml/models/v2/core/event_source.py +14 -14
  52. zenml/models/v2/core/flavor.py +19 -47
  53. zenml/models/v2/core/logs.py +1 -2
  54. zenml/models/v2/core/model.py +23 -20
  55. zenml/models/v2/core/model_version.py +51 -42
  56. zenml/models/v2/core/pipeline.py +16 -16
  57. zenml/models/v2/core/pipeline_build.py +14 -14
  58. zenml/models/v2/core/pipeline_deployment.py +12 -14
  59. zenml/models/v2/core/pipeline_run.py +21 -29
  60. zenml/models/v2/core/project.py +203 -0
  61. zenml/models/v2/core/run_metadata.py +2 -2
  62. zenml/models/v2/core/run_template.py +16 -17
  63. zenml/models/v2/core/schedule.py +12 -21
  64. zenml/models/v2/core/secret.py +94 -128
  65. zenml/models/v2/core/server_settings.py +2 -2
  66. zenml/models/v2/core/service.py +57 -26
  67. zenml/models/v2/core/service_connector.py +14 -16
  68. zenml/models/v2/core/stack.py +24 -26
  69. zenml/models/v2/core/step_run.py +16 -28
  70. zenml/models/v2/core/tag.py +41 -15
  71. zenml/models/v2/core/trigger.py +13 -13
  72. zenml/models/v2/core/trigger_execution.py +2 -2
  73. zenml/models/v2/core/user.py +2 -2
  74. zenml/models/v2/misc/statistics.py +45 -0
  75. zenml/models/v2/misc/tag.py +27 -0
  76. zenml/orchestrators/cache_utils.py +7 -7
  77. zenml/orchestrators/input_utils.py +1 -0
  78. zenml/orchestrators/step_launcher.py +1 -2
  79. zenml/orchestrators/step_run_utils.py +2 -4
  80. zenml/orchestrators/step_runner.py +10 -1
  81. zenml/orchestrators/utils.py +4 -4
  82. zenml/pipelines/build_utils.py +2 -4
  83. zenml/pipelines/pipeline_decorator.py +3 -2
  84. zenml/pipelines/pipeline_definition.py +8 -9
  85. zenml/pipelines/run_utils.py +4 -4
  86. zenml/service_connectors/service_connector.py +0 -10
  87. zenml/service_connectors/service_connector_utils.py +0 -2
  88. zenml/stack/authentication_mixin.py +1 -1
  89. zenml/stack/flavor.py +3 -14
  90. zenml/stack/stack.py +0 -1
  91. zenml/stack/stack_component.py +1 -5
  92. zenml/steps/base_step.py +10 -2
  93. zenml/steps/step_context.py +19 -0
  94. zenml/utils/string_utils.py +1 -1
  95. zenml/utils/tag_utils.py +642 -0
  96. zenml/zen_server/cloud_utils.py +21 -0
  97. zenml/zen_server/exceptions.py +0 -6
  98. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  99. zenml/zen_server/rbac/models.py +65 -3
  100. zenml/zen_server/rbac/rbac_interface.py +9 -0
  101. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  102. zenml/zen_server/rbac/utils.py +155 -30
  103. zenml/zen_server/rbac/zenml_cloud_rbac.py +39 -11
  104. zenml/zen_server/routers/actions_endpoints.py +3 -5
  105. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  106. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  107. zenml/zen_server/routers/auth_endpoints.py +22 -7
  108. zenml/zen_server/routers/code_repositories_endpoints.py +54 -3
  109. zenml/zen_server/routers/devices_endpoints.py +0 -4
  110. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  111. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  112. zenml/zen_server/routers/logs_endpoints.py +0 -1
  113. zenml/zen_server/routers/model_versions_endpoints.py +100 -23
  114. zenml/zen_server/routers/models_endpoints.py +50 -69
  115. zenml/zen_server/routers/pipeline_builds_endpoints.py +55 -3
  116. zenml/zen_server/routers/pipeline_deployments_endpoints.py +56 -4
  117. zenml/zen_server/routers/pipelines_endpoints.py +70 -3
  118. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  119. zenml/zen_server/routers/projects_endpoints.py +283 -0
  120. zenml/zen_server/routers/run_metadata_endpoints.py +97 -0
  121. zenml/zen_server/routers/run_templates_endpoints.py +64 -3
  122. zenml/zen_server/routers/runs_endpoints.py +58 -8
  123. zenml/zen_server/routers/schedule_endpoints.py +67 -6
  124. zenml/zen_server/routers/secrets_endpoints.py +38 -4
  125. zenml/zen_server/routers/server_endpoints.py +53 -1
  126. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  127. zenml/zen_server/routers/service_connectors_endpoints.py +94 -14
  128. zenml/zen_server/routers/service_endpoints.py +18 -7
  129. zenml/zen_server/routers/stack_components_endpoints.py +66 -7
  130. zenml/zen_server/routers/stacks_endpoints.py +95 -6
  131. zenml/zen_server/routers/steps_endpoints.py +17 -11
  132. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  133. zenml/zen_server/routers/tags_endpoints.py +6 -17
  134. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  135. zenml/zen_server/routers/users_endpoints.py +9 -12
  136. zenml/zen_server/template_execution/utils.py +8 -7
  137. zenml/zen_server/utils.py +21 -0
  138. zenml/zen_server/zen_server_api.py +7 -2
  139. zenml/zen_stores/base_zen_store.py +50 -69
  140. zenml/zen_stores/migrations/versions/12eff0206201_rename_workspace_to_project.py +768 -0
  141. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  142. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  143. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  144. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  145. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  146. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  147. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  148. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  149. zenml/zen_stores/migrations/versions/cbc6acd71f92_add_workspace_display_name.py +58 -0
  150. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  151. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  152. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  153. zenml/zen_stores/rest_zen_store.py +223 -230
  154. zenml/zen_stores/schemas/__init__.py +2 -2
  155. zenml/zen_stores/schemas/action_schemas.py +15 -8
  156. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  157. zenml/zen_stores/schemas/artifact_schemas.py +35 -10
  158. zenml/zen_stores/schemas/code_repository_schemas.py +22 -17
  159. zenml/zen_stores/schemas/component_schemas.py +9 -14
  160. zenml/zen_stores/schemas/event_source_schemas.py +15 -8
  161. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  162. zenml/zen_stores/schemas/model_schemas.py +18 -17
  163. zenml/zen_stores/schemas/pipeline_build_schemas.py +7 -7
  164. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +10 -8
  165. zenml/zen_stores/schemas/pipeline_run_schemas.py +9 -12
  166. zenml/zen_stores/schemas/pipeline_schemas.py +9 -9
  167. zenml/zen_stores/schemas/{workspace_schemas.py → project_schemas.py} +53 -65
  168. zenml/zen_stores/schemas/run_metadata_schemas.py +5 -5
  169. zenml/zen_stores/schemas/run_template_schemas.py +17 -13
  170. zenml/zen_stores/schemas/schedule_schema.py +16 -21
  171. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  172. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  173. zenml/zen_stores/schemas/service_schemas.py +7 -8
  174. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  175. zenml/zen_stores/schemas/step_run_schemas.py +14 -15
  176. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  177. zenml/zen_stores/schemas/trigger_schemas.py +15 -8
  178. zenml/zen_stores/schemas/user_schemas.py +12 -2
  179. zenml/zen_stores/schemas/utils.py +16 -0
  180. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  181. zenml/zen_stores/sql_zen_store.py +2984 -2369
  182. zenml/zen_stores/template_utils.py +1 -1
  183. zenml/zen_stores/zen_store_interface.py +136 -126
  184. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/METADATA +1 -1
  185. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/RECORD +188 -173
  186. zenml/cli/workspace.py +0 -86
  187. zenml/models/v2/core/workspace.py +0 -131
  188. zenml/zen_server/routers/workspaces_endpoints.py +0 -1469
  189. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/LICENSE +0 -0
  190. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/WHEEL +0 -0
  191. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/entry_points.txt +0 -0
@@ -66,7 +66,10 @@ from zenml.zen_server.auth import (
66
66
  from zenml.zen_server.exceptions import error_response
67
67
  from zenml.zen_server.rate_limit import rate_limit_requests
68
68
  from zenml.zen_server.rbac.models import Action, ResourceType
69
- from zenml.zen_server.rbac.utils import verify_permission
69
+ from zenml.zen_server.rbac.utils import (
70
+ verify_permission,
71
+ verify_permission_for_model,
72
+ )
70
73
  from zenml.zen_server.utils import (
71
74
  get_ip_location,
72
75
  handle_exceptions,
@@ -544,10 +547,6 @@ def api_token(
544
547
  response=None,
545
548
  ).access_token
546
549
 
547
- verify_permission(
548
- resource_type=ResourceType.PIPELINE_RUN, action=Action.CREATE
549
- )
550
-
551
550
  schedule_id = schedule_id or token.schedule_id
552
551
  pipeline_run_id = pipeline_run_id or token.pipeline_run_id
553
552
  step_run_id = step_run_id or token.step_run_id
@@ -583,15 +582,18 @@ def api_token(
583
582
  f"step run {token.step_run_id}."
584
583
  )
585
584
 
585
+ project_id: Optional[UUID] = None
586
+
586
587
  if schedule_id:
587
588
  # The schedule must exist
588
589
  try:
589
- schedule = zen_store().get_schedule(schedule_id, hydrate=False)
590
+ schedule = zen_store().get_schedule(schedule_id, hydrate=True)
590
591
  except KeyError:
591
592
  raise ValueError(
592
593
  f"Schedule {schedule_id} does not exist and API tokens cannot "
593
594
  "be generated for non-existent schedules for security reasons."
594
595
  )
596
+ project_id = schedule.project.id
595
597
 
596
598
  if not schedule.active:
597
599
  raise ValueError(
@@ -602,7 +604,7 @@ def api_token(
602
604
  if pipeline_run_id:
603
605
  # The pipeline run must exist and the run must not be concluded
604
606
  try:
605
- pipeline_run = zen_store().get_run(pipeline_run_id, hydrate=False)
607
+ pipeline_run = zen_store().get_run(pipeline_run_id, hydrate=True)
606
608
  except KeyError:
607
609
  raise ValueError(
608
610
  f"Pipeline run {pipeline_run_id} does not exist and API tokens "
@@ -610,6 +612,10 @@ def api_token(
610
612
  "security reasons."
611
613
  )
612
614
 
615
+ verify_permission_for_model(model=pipeline_run, action=Action.READ)
616
+
617
+ project_id = pipeline_run.project.id
618
+
613
619
  if pipeline_run.status.is_finished:
614
620
  raise ValueError(
615
621
  f"The execution of pipeline run {pipeline_run_id} has already "
@@ -627,6 +633,8 @@ def api_token(
627
633
  "be generated for non-existent step runs for security reasons."
628
634
  )
629
635
 
636
+ project_id = step_run.project.id
637
+
630
638
  if step_run.status.is_finished:
631
639
  raise ValueError(
632
640
  f"The execution of step run {step_run_id} has already "
@@ -634,6 +642,13 @@ def api_token(
634
642
  "for security reasons."
635
643
  )
636
644
 
645
+ assert project_id is not None
646
+ verify_permission(
647
+ resource_type=ResourceType.PIPELINE_RUN,
648
+ action=Action.CREATE,
649
+ project_id=project_id,
650
+ )
651
+
637
652
  return generate_access_token(
638
653
  user_id=token.user_id,
639
654
  # Keep the original API key and device token scopes
@@ -13,6 +13,7 @@
13
13
  # permissions and limitations under the License.
14
14
  """Endpoint definitions for code repositories."""
15
15
 
16
+ from typing import Optional, Union
16
17
  from uuid import UUID
17
18
 
18
19
  from fastapi import APIRouter, Depends, Security
@@ -20,6 +21,7 @@ from fastapi import APIRouter, Depends, Security
20
21
  from zenml.constants import API, CODE_REPOSITORIES, VERSION_1
21
22
  from zenml.models import (
22
23
  CodeRepositoryFilter,
24
+ CodeRepositoryRequest,
23
25
  CodeRepositoryResponse,
24
26
  CodeRepositoryUpdate,
25
27
  Page,
@@ -27,12 +29,14 @@ from zenml.models import (
27
29
  from zenml.zen_server.auth import AuthContext, authorize
28
30
  from zenml.zen_server.exceptions import error_response
29
31
  from zenml.zen_server.rbac.endpoint_utils import (
32
+ verify_permissions_and_create_entity,
30
33
  verify_permissions_and_delete_entity,
31
34
  verify_permissions_and_get_entity,
32
35
  verify_permissions_and_list_entities,
33
36
  verify_permissions_and_update_entity,
34
37
  )
35
38
  from zenml.zen_server.rbac.models import ResourceType
39
+ from zenml.zen_server.routers.projects_endpoints import workspace_router
36
40
  from zenml.zen_server.utils import (
37
41
  handle_exceptions,
38
42
  make_dependable,
@@ -46,16 +50,61 @@ router = APIRouter(
46
50
  )
47
51
 
48
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
+ "/{project_name_or_id}" + CODE_REPOSITORIES,
61
+ responses={401: error_response, 409: error_response, 422: error_response},
62
+ deprecated=True,
63
+ tags=["code_repositories"],
64
+ )
65
+ @handle_exceptions
66
+ def create_code_repository(
67
+ code_repository: CodeRepositoryRequest,
68
+ project_name_or_id: Optional[Union[str, UUID]] = None,
69
+ _: AuthContext = Security(authorize),
70
+ ) -> CodeRepositoryResponse:
71
+ """Creates a code repository.
72
+
73
+ Args:
74
+ code_repository: Code repository to create.
75
+ project_name_or_id: Optional name or ID of the project.
76
+
77
+ Returns:
78
+ The created code repository.
79
+ """
80
+ if project_name_or_id:
81
+ project = zen_store().get_project(project_name_or_id)
82
+ code_repository.project = project.id
83
+
84
+ return verify_permissions_and_create_entity(
85
+ request_model=code_repository,
86
+ create_method=zen_store().create_code_repository,
87
+ )
88
+
89
+
49
90
  @router.get(
50
91
  "",
51
- response_model=Page[CodeRepositoryResponse],
52
92
  responses={401: error_response, 404: error_response, 422: error_response},
53
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
+ "/{project_name_or_id}" + CODE_REPOSITORIES,
98
+ responses={401: error_response, 404: error_response, 422: error_response},
99
+ deprecated=True,
100
+ tags=["code_repositories"],
101
+ )
54
102
  @handle_exceptions
55
103
  def list_code_repositories(
56
104
  filter_model: CodeRepositoryFilter = Depends(
57
105
  make_dependable(CodeRepositoryFilter)
58
106
  ),
107
+ project_name_or_id: Optional[Union[str, UUID]] = None,
59
108
  hydrate: bool = False,
60
109
  _: AuthContext = Security(authorize),
61
110
  ) -> Page[CodeRepositoryResponse]:
@@ -64,12 +113,16 @@ def list_code_repositories(
64
113
  Args:
65
114
  filter_model: Filter model used for pagination, sorting,
66
115
  filtering.
116
+ project_name_or_id: Optional name or ID of the project.
67
117
  hydrate: Flag deciding whether to hydrate the output model(s)
68
118
  by including metadata fields in the response.
69
119
 
70
120
  Returns:
71
121
  Page of code repository objects.
72
122
  """
123
+ if project_name_or_id:
124
+ filter_model.project = project_name_or_id
125
+
73
126
  return verify_permissions_and_list_entities(
74
127
  filter_model=filter_model,
75
128
  resource_type=ResourceType.CODE_REPOSITORY,
@@ -80,7 +133,6 @@ def list_code_repositories(
80
133
 
81
134
  @router.get(
82
135
  "/{code_repository_id}",
83
- response_model=CodeRepositoryResponse,
84
136
  responses={401: error_response, 404: error_response, 422: error_response},
85
137
  )
86
138
  @handle_exceptions
@@ -108,7 +160,6 @@ def get_code_repository(
108
160
 
109
161
  @router.put(
110
162
  "/{code_repository_id}",
111
- response_model=CodeRepositoryResponse,
112
163
  responses={401: error_response, 404: error_response, 422: error_response},
113
164
  )
114
165
  @handle_exceptions
@@ -54,7 +54,6 @@ router = APIRouter(
54
54
 
55
55
  @router.get(
56
56
  "",
57
- response_model=Page[OAuthDeviceResponse],
58
57
  responses={401: error_response, 404: error_response, 422: error_response},
59
58
  )
60
59
  @handle_exceptions
@@ -85,7 +84,6 @@ def list_authorized_devices(
85
84
 
86
85
  @router.get(
87
86
  "/{device_id}",
88
- response_model=OAuthDeviceResponse,
89
87
  responses={401: error_response, 404: error_response, 422: error_response},
90
88
  )
91
89
  @handle_exceptions
@@ -136,7 +134,6 @@ def get_authorization_device(
136
134
 
137
135
  @router.put(
138
136
  "/{device_id}",
139
- response_model=OAuthDeviceResponse,
140
137
  responses={401: error_response, 404: error_response, 422: error_response},
141
138
  )
142
139
  @handle_exceptions
@@ -173,7 +170,6 @@ def update_authorized_device(
173
170
 
174
171
  @router.put(
175
172
  "/{device_id}" + DEVICE_VERIFY,
176
- response_model=OAuthDeviceResponse,
177
173
  responses={401: error_response, 404: error_response, 422: error_response},
178
174
  )
179
175
  @handle_exceptions
@@ -57,7 +57,6 @@ event_source_router = APIRouter(
57
57
 
58
58
  @event_source_router.get(
59
59
  "",
60
- response_model=Page[EventSourceResponse],
61
60
  responses={401: error_response, 404: error_response, 422: error_response},
62
61
  )
63
62
  @handle_exceptions
@@ -132,7 +131,6 @@ def list_event_sources(
132
131
 
133
132
  @event_source_router.get(
134
133
  "/{event_source_id}",
135
- response_model=EventSourceResponse,
136
134
  responses={401: error_response, 404: error_response, 422: error_response},
137
135
  )
138
136
  @handle_exceptions
@@ -185,7 +183,6 @@ def get_event_source(
185
183
 
186
184
  @event_source_router.post(
187
185
  "",
188
- response_model=EventSourceResponse,
189
186
  responses={401: error_response, 409: error_response, 422: error_response},
190
187
  )
191
188
  @handle_exceptions
@@ -222,14 +219,12 @@ def create_event_source(
222
219
 
223
220
  return verify_permissions_and_create_entity(
224
221
  request_model=event_source,
225
- resource_type=ResourceType.EVENT_SOURCE,
226
222
  create_method=event_source_handler.create_event_source,
227
223
  )
228
224
 
229
225
 
230
226
  @event_source_router.put(
231
227
  "/{event_source_id}",
232
- response_model=EventSourceResponse,
233
228
  responses={401: error_response, 404: error_response, 422: error_response},
234
229
  )
235
230
  @handle_exceptions
@@ -51,7 +51,6 @@ router = APIRouter(
51
51
 
52
52
  @router.get(
53
53
  "",
54
- response_model=Page[FlavorResponse],
55
54
  responses={401: error_response, 404: error_response, 422: error_response},
56
55
  )
57
56
  @handle_exceptions
@@ -81,7 +80,6 @@ def list_flavors(
81
80
 
82
81
  @router.get(
83
82
  "/{flavor_id}",
84
- response_model=FlavorResponse,
85
83
  responses={401: error_response, 404: error_response, 422: error_response},
86
84
  )
87
85
  @handle_exceptions
@@ -107,7 +105,6 @@ def get_flavor(
107
105
 
108
106
  @router.post(
109
107
  "",
110
- response_model=FlavorResponse,
111
108
  responses={401: error_response, 409: error_response, 422: error_response},
112
109
  )
113
110
  @handle_exceptions
@@ -125,14 +122,12 @@ def create_flavor(
125
122
  """
126
123
  return verify_permissions_and_create_entity(
127
124
  request_model=flavor,
128
- resource_type=ResourceType.FLAVOR,
129
125
  create_method=zen_store().create_flavor,
130
126
  )
131
127
 
132
128
 
133
129
  @router.put(
134
130
  "/{flavor_id}",
135
- response_model=FlavorResponse,
136
131
  responses={401: error_response, 409: error_response, 422: error_response},
137
132
  )
138
133
  @handle_exceptions
@@ -42,7 +42,6 @@ router = APIRouter(
42
42
 
43
43
  @router.get(
44
44
  "/{logs_id}",
45
- response_model=LogsResponse,
46
45
  responses={401: error_response, 404: error_response, 422: error_response},
47
46
  )
48
47
  @handle_exceptions
@@ -13,7 +13,7 @@
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
@@ -24,6 +24,7 @@ from zenml.constants import (
24
24
  MODEL_VERSION_ARTIFACTS,
25
25
  MODEL_VERSION_PIPELINE_RUNS,
26
26
  MODEL_VERSIONS,
27
+ MODELS,
27
28
  RUNS,
28
29
  VERSION_1,
29
30
  )
@@ -35,22 +36,31 @@ from zenml.models import (
35
36
  ModelVersionPipelineRunFilter,
36
37
  ModelVersionPipelineRunRequest,
37
38
  ModelVersionPipelineRunResponse,
39
+ ModelVersionRequest,
38
40
  ModelVersionResponse,
39
41
  ModelVersionUpdate,
40
42
  )
41
43
  from zenml.models.v2.base.page import Page
42
44
  from zenml.zen_server.auth import AuthContext, authorize
43
45
  from zenml.zen_server.exceptions import error_response
44
- from zenml.zen_server.rbac.models import Action, ResourceType
46
+ from zenml.zen_server.rbac.endpoint_utils import (
47
+ verify_permissions_and_create_entity,
48
+ verify_permissions_and_delete_entity,
49
+ )
50
+ from zenml.zen_server.rbac.models import Action
45
51
  from zenml.zen_server.rbac.utils import (
46
52
  dehydrate_page,
47
53
  dehydrate_response_model,
48
- get_allowed_resource_ids,
49
54
  verify_permission_for_model,
50
55
  )
56
+ from zenml.zen_server.routers.models_endpoints import (
57
+ router as model_router,
58
+ )
59
+ from zenml.zen_server.routers.projects_endpoints import workspace_router
51
60
  from zenml.zen_server.utils import (
52
61
  handle_exceptions,
53
62
  make_dependable,
63
+ set_filter_project_scope,
54
64
  zen_store,
55
65
  )
56
66
 
@@ -66,9 +76,54 @@ router = APIRouter(
66
76
  )
67
77
 
68
78
 
79
+ @router.post(
80
+ "",
81
+ responses={401: error_response, 409: error_response, 422: error_response},
82
+ )
83
+ # TODO: the workspace scoped endpoint is only kept for dashboard compatibility
84
+ # and can be removed after the migration
85
+ @workspace_router.post(
86
+ "/{project_name_or_id}" + MODELS + "/{model_id}" + MODEL_VERSIONS,
87
+ responses={401: error_response, 409: error_response, 422: error_response},
88
+ deprecated=True,
89
+ tags=["model_versions"],
90
+ )
91
+ @handle_exceptions
92
+ def create_model_version(
93
+ model_version: ModelVersionRequest,
94
+ model_id: Optional[UUID] = None,
95
+ project_name_or_id: Optional[Union[str, UUID]] = None,
96
+ _: AuthContext = Security(authorize),
97
+ ) -> ModelVersionResponse:
98
+ """Creates a model version.
99
+
100
+ Args:
101
+ model_version: Model version to create.
102
+ model_id: Optional ID of the model.
103
+ project_name_or_id: Optional name or ID of the project.
104
+
105
+ Returns:
106
+ The created model version.
107
+ """
108
+ if project_name_or_id:
109
+ project = zen_store().get_project(project_name_or_id)
110
+ model_version.project = project.id
111
+
112
+ if model_id:
113
+ model_version.model = model_id
114
+
115
+ return verify_permissions_and_create_entity(
116
+ request_model=model_version,
117
+ create_method=zen_store().create_model_version,
118
+ )
119
+
120
+
121
+ @model_router.get(
122
+ "/{model_name_or_id}" + MODEL_VERSIONS,
123
+ responses={401: error_response, 404: error_response, 422: error_response},
124
+ )
69
125
  @router.get(
70
126
  "",
71
- response_model=Page[ModelVersionResponse],
72
127
  responses={401: error_response, 404: error_response, 422: error_response},
73
128
  )
74
129
  @handle_exceptions
@@ -76,6 +131,7 @@ def list_model_versions(
76
131
  model_version_filter_model: ModelVersionFilter = Depends(
77
132
  make_dependable(ModelVersionFilter)
78
133
  ),
134
+ model_name_or_id: Optional[Union[str, UUID]] = None,
79
135
  hydrate: bool = False,
80
136
  auth_context: AuthContext = Security(authorize),
81
137
  ) -> Page[ModelVersionResponse]:
@@ -84,19 +140,38 @@ def list_model_versions(
84
140
  Args:
85
141
  model_version_filter_model: Filter model used for pagination, sorting,
86
142
  filtering.
143
+ model_name_or_id: Optional name or ID of the model.
87
144
  hydrate: Flag deciding whether to hydrate the output model(s)
88
145
  by including metadata fields in the response.
89
146
  auth_context: The authentication context.
90
147
 
91
148
  Returns:
92
149
  The model versions according to query filters.
150
+
151
+ Raises:
152
+ ValueError: If the model is missing from the filter.
93
153
  """
94
- allowed_model_ids = get_allowed_resource_ids(
95
- resource_type=ResourceType.MODEL
154
+ if model_name_or_id:
155
+ model_version_filter_model.model = model_name_or_id
156
+
157
+ if not model_version_filter_model.model:
158
+ raise ValueError("Model missing from the filter")
159
+
160
+ # A project scoped request must always be scoped to a specific
161
+ # project. This is required for the RBAC check to work.
162
+ set_filter_project_scope(model_version_filter_model)
163
+ assert isinstance(model_version_filter_model.project, UUID)
164
+
165
+ model = zen_store().get_model_by_name_or_id(
166
+ model_version_filter_model.model,
167
+ project=model_version_filter_model.project,
96
168
  )
169
+
170
+ # Check read permissions on the model
171
+ verify_permission_for_model(model, action=Action.READ)
172
+
97
173
  model_version_filter_model.configure_rbac(
98
- authenticated_user_id=auth_context.user.id,
99
- model_id=allowed_model_ids,
174
+ authenticated_user_id=auth_context.user.id
100
175
  )
101
176
 
102
177
  model_versions = zen_store().list_model_versions(
@@ -108,7 +183,6 @@ def list_model_versions(
108
183
 
109
184
  @router.get(
110
185
  "/{model_version_id}",
111
- response_model=ModelVersionResponse,
112
186
  responses={401: error_response, 404: error_response, 422: error_response},
113
187
  )
114
188
  @handle_exceptions
@@ -137,7 +211,6 @@ def get_model_version(
137
211
 
138
212
  @router.put(
139
213
  "/{model_version_id}",
140
- response_model=ModelVersionResponse,
141
214
  responses={401: error_response, 404: error_response, 422: error_response},
142
215
  )
143
216
  @handle_exceptions
@@ -184,9 +257,11 @@ def delete_model_version(
184
257
  Args:
185
258
  model_version_id: The name or ID of the model version to delete.
186
259
  """
187
- model_version = zen_store().get_model_version(model_version_id)
188
- verify_permission_for_model(model_version, action=Action.DELETE)
189
- zen_store().delete_model_version(model_version_id)
260
+ verify_permissions_and_delete_entity(
261
+ id=model_version_id,
262
+ get_method=zen_store().get_model_version,
263
+ delete_method=zen_store().delete_model_version,
264
+ )
190
265
 
191
266
 
192
267
  ##########################
@@ -220,17 +295,18 @@ def create_model_version_artifact_link(
220
295
  model_version = zen_store().get_model_version(
221
296
  model_version_artifact_link.model_version
222
297
  )
223
- verify_permission_for_model(model_version, action=Action.UPDATE)
224
298
 
225
- mv = zen_store().create_model_version_artifact_link(
226
- model_version_artifact_link
299
+ return verify_permissions_and_create_entity(
300
+ request_model=model_version_artifact_link,
301
+ create_method=zen_store().create_model_version_artifact_link,
302
+ # Check for UPDATE permissions on the model version instead of the
303
+ # model version artifact link
304
+ surrogate_models=[model_version],
227
305
  )
228
- return mv
229
306
 
230
307
 
231
308
  @model_version_artifacts_router.get(
232
309
  "",
233
- response_model=Page[ModelVersionArtifactResponse],
234
310
  responses={401: error_response, 404: error_response, 422: error_response},
235
311
  )
236
312
  @handle_exceptions
@@ -342,17 +418,18 @@ def create_model_version_pipeline_run_link(
342
418
  model_version = zen_store().get_model_version(
343
419
  model_version_pipeline_run_link.model_version, hydrate=False
344
420
  )
345
- verify_permission_for_model(model_version, action=Action.UPDATE)
346
421
 
347
- mv = zen_store().create_model_version_pipeline_run_link(
348
- model_version_pipeline_run_link
422
+ return verify_permissions_and_create_entity(
423
+ request_model=model_version_pipeline_run_link,
424
+ create_method=zen_store().create_model_version_pipeline_run_link,
425
+ # Check for UPDATE permissions on the model version instead of the
426
+ # model version pipeline run link
427
+ surrogate_models=[model_version],
349
428
  )
350
- return mv
351
429
 
352
430
 
353
431
  @model_version_pipeline_runs_router.get(
354
432
  "",
355
- response_model=Page[ModelVersionPipelineRunResponse],
356
433
  responses={401: error_response, 404: error_response, 422: error_response},
357
434
  )
358
435
  @handle_exceptions