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
@@ -0,0 +1,642 @@
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
+ """Utility functions for tags."""
15
+
16
+ from typing import (
17
+ TYPE_CHECKING,
18
+ List,
19
+ Optional,
20
+ TypeVar,
21
+ Union,
22
+ overload,
23
+ )
24
+ from uuid import UUID
25
+
26
+ from pydantic import BaseModel
27
+
28
+ from zenml.enums import ColorVariants, TaggableResourceTypes
29
+ from zenml.logger import get_logger
30
+
31
+ add_tags_warning = """
32
+ # Automatic tagging to a pipeline run (within a step)
33
+ add_tags(tags=[...])
34
+
35
+ # Manual tagging to a pipeline run
36
+ add_tags(tags=[...], run=...)
37
+
38
+ # Manual tagging to a pipeline
39
+ add_tags(tags=[...], pipeline=...)
40
+
41
+ # Manual tagging to a run template
42
+ add_tags(tags=[...], run_template=...)
43
+
44
+ # Manual tagging to an artifact
45
+ add_tags(tags=[...], artifact=...)
46
+
47
+ # Automatic tagging to an artifact version(within a step)
48
+ add_tags(tags=[...], infer_artifact=True) # step with single output
49
+ add_tags(tags=[...], artifact_name=..., infer_artifact=True) # specific output of a step
50
+
51
+ # Manual tagging to an artifact version
52
+ add_tags(tags=[...], artifact_name=..., artifact_version=...)
53
+ add_tags(tags=[...], artifact_version_id=...)
54
+ """
55
+
56
+ remove_tags_warning = """
57
+ # Automatic tag removal from a pipeline run (within a step)
58
+ remove_tags(tags=[...])
59
+
60
+ # Manual tag removal from a pipeline run
61
+ remove_tags(tags=[...], run=...)
62
+
63
+ # Manual tag removal from a pipeline
64
+ remove_tags(tags=[...], pipeline=...)
65
+
66
+ # Manual tag removal from a run template
67
+ remove_tags(tags=[...], run_template=...)
68
+
69
+ # Manual tag removal from an artifact
70
+ remove_tags(tags=[...], artifact=...)
71
+
72
+ # Automatic tag removal from an artifact version (within a step)
73
+ remove_tags(tags=[...], infer_artifact=True) # step with single output
74
+ remove_tags(tags=[...], artifact_name=..., infer_artifact=True) # specific output of a step
75
+
76
+ # Manual tag removal from an artifact version
77
+ remove_tags(tags=[...], artifact_name=..., artifact_version=...)
78
+ remove_tags(tags=[...], artifact_version_id=...)
79
+ """
80
+
81
+
82
+ if TYPE_CHECKING:
83
+ from zenml.models import TagRequest
84
+ from zenml.zen_stores.schemas.base_schemas import BaseSchema
85
+
86
+ AnySchema = TypeVar("AnySchema", bound=BaseSchema)
87
+
88
+ logger = get_logger(__name__)
89
+
90
+
91
+ class Tag(BaseModel):
92
+ """A model representing a tag."""
93
+
94
+ name: str
95
+ color: Optional[ColorVariants] = None
96
+ exclusive: Optional[bool] = None
97
+ cascade: Optional[bool] = None
98
+
99
+ def to_request(self) -> "TagRequest":
100
+ """Convert the tag to a TagRequest.
101
+
102
+ Returns:
103
+ The tag as a TagRequest.
104
+ """
105
+ from zenml.models import TagRequest
106
+
107
+ request = TagRequest(name=self.name)
108
+ if self.color is not None:
109
+ request.color = self.color
110
+
111
+ if self.exclusive is not None:
112
+ request.exclusive = self.exclusive
113
+ return request
114
+
115
+
116
+ @overload
117
+ def add_tags(
118
+ tags: List[Union[str, Tag]],
119
+ ) -> None: ...
120
+
121
+
122
+ @overload
123
+ def add_tags(
124
+ *,
125
+ tags: List[Union[str, Tag]],
126
+ run: Union[UUID, str],
127
+ ) -> None: ...
128
+
129
+
130
+ @overload
131
+ def add_tags(
132
+ *,
133
+ tags: List[Union[str, Tag]],
134
+ artifact: Union[UUID, str],
135
+ ) -> None: ...
136
+
137
+
138
+ @overload
139
+ def add_tags(
140
+ *,
141
+ tags: List[Union[str, Tag]],
142
+ artifact_version_id: UUID,
143
+ ) -> None: ...
144
+
145
+
146
+ @overload
147
+ def add_tags(
148
+ *,
149
+ tags: List[Union[str, Tag]],
150
+ artifact_name: str,
151
+ artifact_version: Optional[str] = None,
152
+ ) -> None: ...
153
+
154
+
155
+ @overload
156
+ def add_tags(
157
+ *,
158
+ tags: List[Union[str, Tag]],
159
+ infer_artifact: bool = False,
160
+ artifact_name: Optional[str] = None,
161
+ ) -> None: ...
162
+
163
+
164
+ @overload
165
+ def add_tags(
166
+ *,
167
+ tags: List[Union[str, Tag]],
168
+ pipeline: Union[UUID, str],
169
+ ) -> None: ...
170
+
171
+
172
+ @overload
173
+ def add_tags(
174
+ *,
175
+ tags: List[Union[str, Tag]],
176
+ run_template: Union[UUID, str],
177
+ ) -> None: ...
178
+
179
+
180
+ def add_tags(
181
+ tags: List[Union[str, Tag]],
182
+ # Pipelines
183
+ pipeline: Optional[Union[UUID, str]] = None,
184
+ # Runs
185
+ run: Optional[Union[UUID, str]] = None,
186
+ # Run Templates
187
+ run_template: Optional[Union[UUID, str]] = None,
188
+ # Artifacts
189
+ artifact: Optional[Union[UUID, str]] = None,
190
+ # Artifact Versions
191
+ artifact_version_id: Optional[UUID] = None,
192
+ artifact_name: Optional[str] = None,
193
+ artifact_version: Optional[str] = None,
194
+ infer_artifact: bool = False,
195
+ ) -> None:
196
+ """Add tags to various resource types in a generalized way.
197
+
198
+ Args:
199
+ tags: The tags to add.
200
+ pipeline: The ID or the name of the pipeline.
201
+ run: The id, name or prefix of the run.
202
+ run_template: The ID or the name of the run template.
203
+ artifact: The ID or the name of the artifact.
204
+ artifact_version_id: The ID of the artifact version.
205
+ artifact_name: The name of the artifact.
206
+ artifact_version: The version of the artifact.
207
+ infer_artifact: Flag deciding whether the artifact version should be
208
+ inferred from the step context.
209
+
210
+ Raises:
211
+ ValueError: If no identifiers are provided and the function is not
212
+ called from within a step, or if exclusive is provided for a
213
+ resource type that doesn't support it.
214
+ """
215
+ from zenml.client import Client
216
+ from zenml.models.v2.misc.tag import TagResource
217
+
218
+ client = Client()
219
+ resource_id = None
220
+ resource_type = None
221
+
222
+ # Tag a pipeline
223
+ if pipeline is not None:
224
+ pipeline_model = client.get_pipeline(name_id_or_prefix=pipeline)
225
+ resource_id = pipeline_model.id
226
+ resource_type = TaggableResourceTypes.PIPELINE
227
+
228
+ # Tag a run by ID
229
+ elif run is not None:
230
+ run_model = client.get_pipeline_run(name_id_or_prefix=run)
231
+ resource_id = run_model.id
232
+ resource_type = TaggableResourceTypes.PIPELINE_RUN
233
+
234
+ # Tag a run template
235
+ elif run_template is not None:
236
+ run_template_model = client.get_run_template(
237
+ name_id_or_prefix=run_template
238
+ )
239
+ resource_id = run_template_model.id
240
+ resource_type = TaggableResourceTypes.RUN_TEMPLATE
241
+
242
+ # Tag an artifact
243
+ elif artifact is not None:
244
+ artifact_model = client.get_artifact(name_id_or_prefix=artifact)
245
+ resource_id = artifact_model.id
246
+ resource_type = TaggableResourceTypes.ARTIFACT
247
+
248
+ # Tag an artifact version by its name and version
249
+ elif artifact_name is not None and artifact_version is not None:
250
+ artifact_version_model = client.get_artifact_version(
251
+ name_id_or_prefix=artifact_name, version=artifact_version
252
+ )
253
+ resource_id = artifact_version_model.id
254
+ resource_type = TaggableResourceTypes.ARTIFACT_VERSION
255
+
256
+ # Tag an artifact version by its ID
257
+ elif artifact_version_id is not None:
258
+ resource_id = artifact_version_id
259
+ resource_type = TaggableResourceTypes.ARTIFACT_VERSION
260
+
261
+ # Tag an artifact version through the step context
262
+ elif infer_artifact is True:
263
+ resource_type = TaggableResourceTypes.ARTIFACT_VERSION
264
+
265
+ try:
266
+ from zenml.steps.step_context import get_step_context
267
+
268
+ step_context = get_step_context()
269
+ except RuntimeError:
270
+ raise ValueError(
271
+ "When you are using the `infer_artifact` option when you call "
272
+ "`add_tags`, it must be called inside a step with outputs."
273
+ "Otherwise, you can provide a `artifact_version_id` or a "
274
+ "combination of `artifact_name` and `artifact_version`."
275
+ )
276
+
277
+ step_output_names = list(step_context._outputs.keys())
278
+
279
+ if artifact_name is not None:
280
+ # If a name provided, ensure it is in the outputs
281
+ if artifact_name not in step_output_names:
282
+ raise ValueError(
283
+ f"The provided artifact name`{artifact_name}` does not "
284
+ f"exist in the step outputs: {step_output_names}."
285
+ )
286
+ else:
287
+ # If no name provided, ensure there is only one output
288
+ if len(step_output_names) > 1:
289
+ raise ValueError(
290
+ "There is more than one output. If you would like to use "
291
+ "the `infer_artifact` option, you need to define an "
292
+ "`artifact_name`."
293
+ )
294
+
295
+ if len(step_output_names) == 0:
296
+ raise ValueError("The step does not have any outputs.")
297
+
298
+ artifact_name = step_output_names[0]
299
+
300
+ step_context.add_output_tags(
301
+ tags=[t.name if isinstance(t, Tag) else t for t in tags],
302
+ output_name=artifact_name,
303
+ )
304
+
305
+ # If every additional value is None, that means we are calling it bare bones
306
+ # and this call needs to happen during a step execution. We will use the
307
+ # step context to fetch the run and attach the tags accordingly.
308
+ elif all(
309
+ v is None
310
+ for v in [
311
+ run,
312
+ artifact_version_id,
313
+ artifact_name,
314
+ artifact_version,
315
+ pipeline,
316
+ run_template,
317
+ ]
318
+ ):
319
+ try:
320
+ from zenml.steps.step_context import get_step_context
321
+
322
+ step_context = get_step_context()
323
+ except RuntimeError:
324
+ raise ValueError(
325
+ f"""
326
+ You are calling 'add_tags()' outside of a step execution.
327
+ If you would like to add tags to a ZenML entity outside
328
+ of the step execution, please provide the required
329
+ identifiers.\n{add_tags_warning}
330
+ """
331
+ )
332
+
333
+ # Tag the pipeline run, not the step
334
+ resource_id = step_context.pipeline_run.id
335
+ resource_type = TaggableResourceTypes.PIPELINE_RUN
336
+
337
+ else:
338
+ raise ValueError(
339
+ f"""
340
+ Unsupported way to call the `add_tags`. Possible combinations "
341
+ include: \n{add_tags_warning}
342
+ """
343
+ )
344
+
345
+ # Create tag resources and add tags
346
+ for tag in tags:
347
+ try:
348
+ if isinstance(tag, Tag):
349
+ tag_model = client.get_tag(tag.name)
350
+
351
+ if tag.exclusive != tag_model.exclusive:
352
+ raise ValueError(
353
+ f"The tag `{tag.name}` is an "
354
+ f"{'exclusive' if tag_model.exclusive else 'non-exclusive'} "
355
+ "tag. Please update it before attaching it to a resource."
356
+ )
357
+ if tag.cascade is not None:
358
+ raise ValueError(
359
+ "Cascading tags can only be used with the "
360
+ "pipeline decorator."
361
+ )
362
+ else:
363
+ tag_model = client.get_tag(tag)
364
+
365
+ except KeyError:
366
+ if isinstance(tag, Tag):
367
+ tag_model = client.create_tag(
368
+ name=tag.name,
369
+ exclusive=tag.exclusive
370
+ if tag.exclusive is not None
371
+ else False,
372
+ )
373
+
374
+ if tag.cascade is not None:
375
+ raise ValueError(
376
+ "Cascading tags can only be used with the "
377
+ "pipeline decorator."
378
+ )
379
+ else:
380
+ tag_model = client.create_tag(name=tag)
381
+
382
+ if tag_model.exclusive and resource_type not in [
383
+ TaggableResourceTypes.PIPELINE_RUN,
384
+ TaggableResourceTypes.ARTIFACT_VERSION,
385
+ TaggableResourceTypes.RUN_TEMPLATE,
386
+ ]:
387
+ logger.warning(
388
+ "The tag will be added, however, please keep in mind that "
389
+ "the functionality of having exclusive tags is only "
390
+ "applicable for pipeline runs, artifact versions and run "
391
+ f"templates, not {resource_type.value}s."
392
+ )
393
+
394
+ if resource_id:
395
+ client.attach_tag(
396
+ tag_name_or_id=tag_model.name,
397
+ resources=[TagResource(id=resource_id, type=resource_type)],
398
+ )
399
+
400
+
401
+ @overload
402
+ def remove_tags(
403
+ tags: List[str],
404
+ ) -> None: ...
405
+
406
+
407
+ @overload
408
+ def remove_tags(
409
+ *,
410
+ tags: List[str],
411
+ pipeline: Union[UUID, str],
412
+ ) -> None: ...
413
+
414
+
415
+ @overload
416
+ def remove_tags(
417
+ *,
418
+ tags: List[str],
419
+ run: Union[UUID, str],
420
+ ) -> None: ...
421
+
422
+
423
+ @overload
424
+ def remove_tags(
425
+ *,
426
+ tags: List[str],
427
+ run_template: Union[UUID, str],
428
+ ) -> None: ...
429
+
430
+
431
+ @overload
432
+ def remove_tags(
433
+ *,
434
+ tags: List[str],
435
+ artifact: Union[UUID, str],
436
+ ) -> None: ...
437
+
438
+
439
+ @overload
440
+ def remove_tags(
441
+ *,
442
+ tags: List[str],
443
+ artifact_version_id: UUID,
444
+ ) -> None: ...
445
+
446
+
447
+ @overload
448
+ def remove_tags(
449
+ *,
450
+ tags: List[str],
451
+ artifact_name: str,
452
+ artifact_version: Optional[str] = None,
453
+ ) -> None: ...
454
+
455
+
456
+ @overload
457
+ def remove_tags(
458
+ *,
459
+ tags: List[str],
460
+ infer_artifact: bool = False,
461
+ artifact_name: Optional[str] = None,
462
+ ) -> None: ...
463
+
464
+
465
+ def remove_tags(
466
+ tags: List[str],
467
+ # Pipelines
468
+ pipeline: Optional[Union[UUID, str]] = None,
469
+ # Runs
470
+ run: Optional[Union[UUID, str]] = None,
471
+ # Run Templates
472
+ run_template: Optional[Union[UUID, str]] = None,
473
+ # Artifacts
474
+ artifact: Optional[Union[UUID, str]] = None,
475
+ # Artifact Versions
476
+ artifact_version_id: Optional[UUID] = None,
477
+ artifact_name: Optional[str] = None,
478
+ artifact_version: Optional[str] = None,
479
+ infer_artifact: bool = False,
480
+ ) -> None:
481
+ """Remove tags from various resource types in a generalized way.
482
+
483
+ Args:
484
+ tags: The tags to remove.
485
+ pipeline: The ID or the name of the pipeline.
486
+ run: The id, name or prefix of the run.
487
+ run_template: The ID or the name of the run template.
488
+ artifact: The ID or the name of the artifact.
489
+ artifact_version_id: The ID of the artifact version.
490
+ artifact_name: The name of the artifact.
491
+ artifact_version: The version of the artifact.
492
+ infer_artifact: Flag deciding whether the artifact version should be
493
+ inferred from the step context.
494
+
495
+ Raises:
496
+ ValueError: If no identifiers are provided and the function is not
497
+ called from within a step.
498
+ """
499
+ from zenml.client import Client
500
+ from zenml.models.v2.misc.tag import TagResource
501
+
502
+ client = Client()
503
+ resource_id = None
504
+ resource_type = None
505
+
506
+ # Remove tags from a pipeline
507
+ if pipeline is not None:
508
+ pipeline_model = client.get_pipeline(name_id_or_prefix=pipeline)
509
+ resource_id = pipeline_model.id
510
+ resource_type = TaggableResourceTypes.PIPELINE
511
+
512
+ # Remove tags from a run template
513
+ elif run_template is not None:
514
+ run_template_model = client.get_run_template(
515
+ name_id_or_prefix=run_template
516
+ )
517
+ resource_id = run_template_model.id
518
+ resource_type = TaggableResourceTypes.RUN_TEMPLATE
519
+
520
+ # Remove tags from a run
521
+ elif run is not None:
522
+ run_model = client.get_pipeline_run(name_id_or_prefix=run)
523
+ resource_id = run_model.id
524
+ resource_type = TaggableResourceTypes.PIPELINE_RUN
525
+
526
+ # Remove tags from an artifact
527
+ elif artifact is not None:
528
+ artifact_model = client.get_artifact(name_id_or_prefix=artifact)
529
+ resource_id = artifact_model.id
530
+ resource_type = TaggableResourceTypes.ARTIFACT
531
+
532
+ # Remove tags from an artifact version by its name and version
533
+ elif artifact_name is not None and artifact_version is not None:
534
+ artifact_version_model = client.get_artifact_version(
535
+ name_id_or_prefix=artifact_name, version=artifact_version
536
+ )
537
+ resource_id = artifact_version_model.id
538
+ resource_type = TaggableResourceTypes.ARTIFACT_VERSION
539
+
540
+ # Remove tags from an artifact version by its ID
541
+ elif artifact_version_id is not None:
542
+ resource_id = artifact_version_id
543
+ resource_type = TaggableResourceTypes.ARTIFACT_VERSION
544
+
545
+ # Remove tags from an artifact version through the step context
546
+ elif infer_artifact is True:
547
+ try:
548
+ from zenml.steps.step_context import get_step_context
549
+
550
+ step_context = get_step_context()
551
+ except RuntimeError:
552
+ raise ValueError(
553
+ "When you are using the `infer_artifact` option when you call "
554
+ "`remove_tags`, it must be called inside a step with outputs."
555
+ "Otherwise, you can provide a `artifact_version_id` or a "
556
+ "combination of `artifact_name` and `artifact_version`."
557
+ )
558
+
559
+ step_output_names = list(step_context._outputs.keys())
560
+
561
+ if artifact_name is not None:
562
+ # If a name provided, ensure it is in the outputs
563
+ if artifact_name not in step_output_names:
564
+ raise ValueError(
565
+ f"The provided artifact name`{artifact_name}` does not "
566
+ f"exist in the step outputs: {step_output_names}."
567
+ )
568
+ else:
569
+ # If no name provided, ensure there is only one output
570
+ if len(step_output_names) > 1:
571
+ raise ValueError(
572
+ "There is more than one output. If you would like to use "
573
+ "the `infer_artifact` option, you need to define an "
574
+ "`artifact_name`."
575
+ )
576
+
577
+ if len(step_output_names) == 0:
578
+ raise ValueError("The step does not have any outputs.")
579
+
580
+ artifact_name = step_output_names[0]
581
+
582
+ step_context.remove_output_tags(
583
+ tags=tags,
584
+ output_name=artifact_name,
585
+ )
586
+ return
587
+
588
+ # If every additional value is None, that means we are calling it bare bones
589
+ # and this call needs to happen during a step execution. We will use the
590
+ # step context to fetch the run and detach the tags accordingly.
591
+ elif all(
592
+ v is None
593
+ for v in [
594
+ run,
595
+ artifact_version_id,
596
+ artifact_name,
597
+ artifact_version,
598
+ pipeline,
599
+ run_template,
600
+ ]
601
+ ):
602
+ try:
603
+ from zenml.steps.step_context import get_step_context
604
+
605
+ step_context = get_step_context()
606
+ except RuntimeError:
607
+ raise ValueError(
608
+ f"""
609
+ You are calling 'remove_tags()' outside of a step execution.
610
+ If you would like to remove tags from a ZenML entity outside
611
+ of the step execution, please provide the required
612
+ identifiers. \n{remove_tags_warning}
613
+ """
614
+ )
615
+
616
+ # Tag the pipeline run, not the step
617
+ resource_id = step_context.pipeline_run.id
618
+ resource_type = TaggableResourceTypes.PIPELINE_RUN
619
+
620
+ else:
621
+ raise ValueError(
622
+ f"""
623
+ Unsupported way to call the `remove_tags`. Possible combinations "
624
+ include: \n{remove_tags_warning}
625
+ """
626
+ )
627
+
628
+ # Remove tags from resource
629
+ for tag_name in tags:
630
+ try:
631
+ # Get the tag
632
+ tag = client.get_tag(tag_name)
633
+
634
+ # Detach tag from resources
635
+ client.detach_tag(
636
+ tag_name_or_id=tag.id,
637
+ resources=[TagResource(id=resource_id, type=resource_type)],
638
+ )
639
+
640
+ except KeyError:
641
+ # Tag doesn't exist, nothing to remove
642
+ pass
@@ -130,6 +130,27 @@ class ZenMLCloudConnection:
130
130
  method="PATCH", endpoint=endpoint, params=params, data=data
131
131
  )
132
132
 
133
+ def delete(
134
+ self,
135
+ endpoint: str,
136
+ params: Optional[Dict[str, Any]] = None,
137
+ data: Optional[Dict[str, Any]] = None,
138
+ ) -> requests.Response:
139
+ """Send a DELETE request using the active session.
140
+
141
+ Args:
142
+ endpoint: The endpoint to send the request to. This will be appended
143
+ to the base URL.
144
+ params: Parameters to include in the request.
145
+ data: Data to include in the request.
146
+
147
+ Returns:
148
+ The response.
149
+ """
150
+ return self.request(
151
+ method="DELETE", endpoint=endpoint, params=params, data=data
152
+ )
153
+
133
154
  @property
134
155
  def session(self) -> requests.Session:
135
156
  """Authenticate to the ZenML Pro Management Plane.
@@ -27,9 +27,6 @@ from zenml.exceptions import (
27
27
  EntityExistsError,
28
28
  IllegalOperationError,
29
29
  MethodNotAllowedError,
30
- SecretExistsError,
31
- StackComponentExistsError,
32
- StackExistsError,
33
30
  SubscriptionUpgradeRequiredError,
34
31
  ValidationError,
35
32
  ZenKeyError,
@@ -72,9 +69,6 @@ error_response = dict(model=ErrorModel)
72
69
  # different status codes (e.g. `ValueError` and the 400 and 422 status codes).
73
70
  REST_API_EXCEPTIONS: List[Tuple[Type[Exception], int]] = [
74
71
  # 409 Conflict
75
- (StackExistsError, 409),
76
- (StackComponentExistsError, 409),
77
- (SecretExistsError, 409),
78
72
  (DuplicateRunNameError, 409),
79
73
  (EntityExistsError, 409),
80
74
  # 403 Forbidden