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
zenml/VERSION CHANGED
@@ -1 +1 @@
1
- 0.75.0.dev20250312
1
+ 0.75.0.dev20250314
zenml/__init__.py CHANGED
@@ -49,9 +49,11 @@ from zenml.pipelines import get_pipeline_context, pipeline
49
49
  from zenml.steps import step, get_step_context
50
50
  from zenml.steps.utils import log_step_metadata
51
51
  from zenml.utils.metadata_utils import log_metadata
52
+ from zenml.utils.tag_utils import Tag, add_tags, remove_tags
52
53
  from zenml.entrypoints import entrypoint
53
54
 
54
55
  __all__ = [
56
+ "add_tags",
55
57
  "ArtifactConfig",
56
58
  "ExternalArtifact",
57
59
  "get_pipeline_context",
@@ -118,7 +118,10 @@ class AnalyticsContext:
118
118
  self.external_user_id = auth_context.user.external_user_id
119
119
 
120
120
  self.external_server_id = server_config().external_server_id
121
+ self.project_id = None
121
122
  else:
123
+ from zenml.client import Client
124
+
122
125
  # If the code is running on the client, use the default user.
123
126
  active_user = gc.zen_store.get_user()
124
127
  self.user_id = active_user.id
@@ -126,6 +129,7 @@ class AnalyticsContext:
126
129
  active_user.is_service_account
127
130
  )
128
131
  self.external_user_id = active_user.external_user_id
132
+ self.project_id = Client().active_project.id
129
133
 
130
134
  # Fetch the `client_id`
131
135
  if self.in_server:
@@ -304,6 +308,9 @@ class AnalyticsContext:
304
308
  if self.server_metadata:
305
309
  properties.update(self.server_metadata)
306
310
 
311
+ if self.project_id:
312
+ properties.setdefault("project_id", str(self.project_id))
313
+
307
314
  for k, v in properties.items():
308
315
  if isinstance(v, UUID):
309
316
  properties[k] = str(v)
zenml/analytics/enums.py CHANGED
@@ -65,8 +65,8 @@ class AnalyticsEvent(str, Enum):
65
65
  # Examples
66
66
  RUN_ZENML_GO = "ZenML go"
67
67
 
68
- # Workspaces
69
- CREATED_WORKSPACE = "Workspace created"
68
+ # Projects
69
+ CREATED_PROJECT = "Project created"
70
70
 
71
71
  # Flavor
72
72
  CREATED_FLAVOR = "Flavor created"
zenml/artifacts/utils.py CHANGED
@@ -182,8 +182,7 @@ def _store_artifact_data_and_prepare_request(
182
182
  uri=materializer.uri,
183
183
  materializer=source_utils.resolve(materializer.__class__),
184
184
  data_type=source_utils.resolve(data_type),
185
- user=Client().active_user.id,
186
- workspace=Client().active_workspace.id,
185
+ project=Client().active_project.id,
187
186
  artifact_store_id=artifact_store.id,
188
187
  visualizations=visualizations,
189
188
  has_custom_name=has_custom_name,
@@ -350,8 +349,7 @@ def register_artifact(
350
349
  uri=folder_or_file_uri,
351
350
  materializer=source_utils.resolve(PreexistingDataMaterializer),
352
351
  data_type=source_utils.resolve(Path),
353
- user=Client().active_user.id,
354
- workspace=Client().active_workspace.id,
352
+ project=Client().active_project.id,
355
353
  artifact_store_id=artifact_store.id,
356
354
  has_custom_name=has_custom_name,
357
355
  metadata=validate_metadata(artifact_metadata)
zenml/cli/__init__.py CHANGED
@@ -106,7 +106,7 @@ zenml go
106
106
  Cleaning up
107
107
  -----------
108
108
 
109
- If you wish to delete all data relating to your workspace from the
109
+ If you wish to delete all data relating to your project from the
110
110
  directory, use the ``zenml clean`` command. This will:
111
111
 
112
112
  - delete all pipelines, pipeline runs and associated metadata
@@ -367,8 +367,7 @@ information regarding a specific flavor, you can utilize the command:
367
367
  zenml orchestrator flavor describe FLAVOR_NAME
368
368
  ```
369
369
 
370
- If you wish to list the orchestrators that have already been registered
371
- within your ZenML workspace / repository, type:
370
+ If you wish to list the orchestrators that have already been registered, type:
372
371
 
373
372
  ```bash
374
373
  zenml orchestrator list
@@ -1446,8 +1445,7 @@ simply pass along the `--set` flag.
1446
1445
  zenml stack register STACK_NAME ... --set
1447
1446
  ```
1448
1447
 
1449
- To list the stacks that you have registered within your current ZenML
1450
- workspace, type:
1448
+ To list the stacks that you have registered, type:
1451
1449
 
1452
1450
  ```bash
1453
1451
  zenml stack list
@@ -2070,9 +2068,10 @@ Finally, to delete a secret, use the `delete` command:
2070
2068
  zenml secret delete SECRET_NAME
2071
2069
  ```
2072
2070
 
2073
- Secrets can be scoped to a workspace or a user. By default, secrets
2074
- are scoped to the current workspace. To scope a secret to a user, use the
2075
- `--scope user` argument in the `register` command.
2071
+ Secrets can be either private or public. Private secrets are only accessible
2072
+ to the current user. Public secrets are accessible to all other users. By
2073
+ default, secrets are public. To make a secret private, use the `--private` flag
2074
+ in the `create` or `update` commands.
2076
2075
 
2077
2076
  Auth management
2078
2077
  ---------------
@@ -2525,5 +2524,5 @@ from zenml.cli.service_connectors import * # noqa
2525
2524
  from zenml.cli.stack import * # noqa
2526
2525
  from zenml.cli.stack_components import * # noqa
2527
2526
  from zenml.cli.user_management import * # noqa
2528
- from zenml.cli.workspace import * # noqa
2527
+ from zenml.cli.project import * # noqa
2529
2528
  from zenml.cli.tag import * # noqa
zenml/cli/base.py CHANGED
@@ -622,7 +622,7 @@ def info(
622
622
  "python_version": environment.python_version(),
623
623
  "environment": get_environment(),
624
624
  "system_info": environment.get_system_info(),
625
- "active_workspace": client.active_workspace.name,
625
+ "active_project": client.active_project.name,
626
626
  "active_stack": client.active_stack_model.name,
627
627
  "active_user": client.active_user.name,
628
628
  "telemetry_status": "enabled" if gc.analytics_opt_in else "disabled",
@@ -674,7 +674,7 @@ def info(
674
674
  "--skip_default_registrations",
675
675
  is_flag=True,
676
676
  default=False,
677
- help="Skip registering default workspace, user and stack.",
677
+ help="Skip registering default project, user and stack.",
678
678
  type=bool,
679
679
  )
680
680
  def migrate_database(skip_default_registrations: bool = False) -> None:
@@ -205,7 +205,7 @@ def list_code_repositories(**kwargs: Any) -> None:
205
205
 
206
206
  cli_utils.print_pydantic_models(
207
207
  repos,
208
- exclude_columns=["created", "updated", "user", "workspace"],
208
+ exclude_columns=["created", "updated", "user", "project"],
209
209
  )
210
210
 
211
211
 
zenml/cli/login.py CHANGED
@@ -291,6 +291,11 @@ def connect_to_pro_server(
291
291
  login = True
292
292
 
293
293
  if login or refresh:
294
+ # If we reached this point, then we need to start a new login flow.
295
+ # We also need to remove all existing API tokens associated with the
296
+ # target ZenML Pro API, otherwise they will continue to be used after
297
+ # the re-login flow.
298
+ credentials_store.clear_all_pro_tokens(pro_api_url)
294
299
  try:
295
300
  token = web_login(
296
301
  pro_api_url=pro_api_url,
@@ -976,6 +981,7 @@ def logout(
976
981
  )
977
982
 
978
983
  pro_api_url = pro_api_url or ZENML_PRO_API_URL
984
+ pro_api_url = pro_api_url.rstrip("/")
979
985
  if credentials_store.has_valid_pro_authentication(pro_api_url):
980
986
  credentials_store.clear_pro_credentials(pro_api_url)
981
987
  cli_utils.declare("Logged out from ZenML Pro.")
zenml/cli/model.py CHANGED
@@ -91,9 +91,7 @@ def list_models(**kwargs: Any) -> None:
91
91
  Args:
92
92
  **kwargs: Keyword arguments to filter models.
93
93
  """
94
- models = Client().zen_store.list_models(
95
- model_filter_model=ModelFilter(**kwargs)
96
- )
94
+ models = Client().list_models(**kwargs)
97
95
 
98
96
  if not models:
99
97
  cli_utils.declare("No models found.")
@@ -399,24 +397,18 @@ def version() -> None:
399
397
 
400
398
 
401
399
  @cli_utils.list_options(ModelVersionFilter)
402
- @click.option(
403
- "--model-name",
404
- "-n",
405
- help="The name of the parent model.",
406
- type=str,
407
- required=False,
408
- )
409
400
  @version.command("list", help="List model versions with filter.")
410
- def list_model_versions(model_name: str, **kwargs: Any) -> None:
401
+ @click.argument("model_name_or_id")
402
+ def list_model_versions(model_name_or_id: str, **kwargs: Any) -> None:
411
403
  """List model versions with filter in the Model Control Plane.
412
404
 
413
405
  Args:
414
- model_name: The name of the parent model.
406
+ model_name_or_id: The name or ID of the parent model.
415
407
  **kwargs: Keyword arguments to filter models.
416
408
  """
417
- model_versions = Client().zen_store.list_model_versions(
418
- model_name_or_id=model_name,
419
- model_version_filter_model=ModelVersionFilter(**kwargs),
409
+ model_versions = Client().list_model_versions(
410
+ model_name_or_id=model_name_or_id,
411
+ **kwargs,
420
412
  )
421
413
 
422
414
  if not model_versions:
zenml/cli/pipeline.py CHANGED
@@ -382,7 +382,7 @@ def list_pipelines(**kwargs: Any) -> None:
382
382
 
383
383
  cli_utils.print_pydantic_models(
384
384
  pipelines,
385
- exclude_columns=["id", "created", "updated", "user", "workspace"],
385
+ exclude_columns=["id", "created", "updated", "user", "project"],
386
386
  )
387
387
 
388
388
 
@@ -447,7 +447,7 @@ def list_schedules(**kwargs: Any) -> None:
447
447
 
448
448
  cli_utils.print_pydantic_models(
449
449
  schedules,
450
- exclude_columns=["id", "created", "updated", "user", "workspace"],
450
+ exclude_columns=["id", "created", "updated", "user", "project"],
451
451
  )
452
452
 
453
453
 
@@ -600,7 +600,7 @@ def list_pipeline_builds(**kwargs: Any) -> None:
600
600
  "created",
601
601
  "updated",
602
602
  "user",
603
- "workspace",
603
+ "project",
604
604
  "images",
605
605
  "stack_checksum",
606
606
  ],
zenml/cli/project.py ADDED
@@ -0,0 +1,172 @@
1
+ # Copyright (c) ZenML GmbH 2022. 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
+ """Functionality to administer projects of the ZenML CLI and server."""
15
+
16
+ from typing import Any, Optional
17
+
18
+ import click
19
+
20
+ from zenml.cli import utils as cli_utils
21
+ from zenml.cli.cli import TagGroup, cli
22
+ from zenml.cli.utils import (
23
+ check_zenml_pro_project_availability,
24
+ is_sorted_or_filtered,
25
+ list_options,
26
+ )
27
+ from zenml.client import Client
28
+ from zenml.console import console
29
+ from zenml.enums import CliCategories
30
+ from zenml.models import ProjectFilter
31
+
32
+
33
+ @cli.group(cls=TagGroup, tag=CliCategories.MANAGEMENT_TOOLS)
34
+ def project() -> None:
35
+ """Commands for project management."""
36
+
37
+
38
+ @project.command("list")
39
+ @list_options(ProjectFilter)
40
+ @click.pass_context
41
+ def list_projects(ctx: click.Context, **kwargs: Any) -> None:
42
+ """List all projects.
43
+
44
+ Args:
45
+ ctx: The click context object
46
+ **kwargs: Keyword arguments to filter the list of projects.
47
+ """
48
+ check_zenml_pro_project_availability()
49
+ client = Client()
50
+ with console.status("Listing projects...\n"):
51
+ projects = client.list_projects(**kwargs)
52
+ if projects:
53
+ cli_utils.print_pydantic_models(
54
+ projects,
55
+ exclude_columns=["id", "created", "updated"],
56
+ active_models=[Client().active_project],
57
+ show_active=not is_sorted_or_filtered(ctx),
58
+ )
59
+ else:
60
+ cli_utils.declare("No projects found for the given filter.")
61
+
62
+
63
+ @project.command("register")
64
+ @click.option(
65
+ "--set",
66
+ "set_project",
67
+ is_flag=True,
68
+ help="Immediately set this project as active.",
69
+ type=click.BOOL,
70
+ )
71
+ @click.option(
72
+ "--display-name",
73
+ "display_name",
74
+ type=str,
75
+ required=False,
76
+ help="The display name of the project.",
77
+ )
78
+ @click.argument("project_name", type=str, required=True)
79
+ def register_project(
80
+ project_name: str,
81
+ set_project: bool = False,
82
+ display_name: Optional[str] = None,
83
+ ) -> None:
84
+ """Register a new project.
85
+
86
+ Args:
87
+ project_name: The name of the project to register.
88
+ set_project: Whether to set the project as active.
89
+ display_name: The display name of the project.
90
+ """
91
+ check_zenml_pro_project_availability()
92
+ client = Client()
93
+ with console.status("Creating project...\n"):
94
+ try:
95
+ client.create_project(
96
+ project_name,
97
+ description="",
98
+ display_name=display_name,
99
+ )
100
+ cli_utils.declare("Project created successfully.")
101
+ except Exception as e:
102
+ cli_utils.error(str(e))
103
+
104
+ if set_project:
105
+ client.set_active_project(project_name)
106
+ cli_utils.declare(f"The active project has been set to {project_name}")
107
+
108
+
109
+ @project.command("set")
110
+ @click.argument("project_name_or_id", type=str, required=True)
111
+ def set_project(project_name_or_id: str) -> None:
112
+ """Set the active project.
113
+
114
+ Args:
115
+ project_name_or_id: The name or ID of the project to set as active.
116
+ """
117
+ check_zenml_pro_project_availability()
118
+ client = Client()
119
+ with console.status("Setting project...\n"):
120
+ try:
121
+ client.set_active_project(project_name_or_id)
122
+ cli_utils.declare(
123
+ f"The active project has been set to {project_name_or_id}"
124
+ )
125
+ except Exception as e:
126
+ cli_utils.error(str(e))
127
+
128
+
129
+ @project.command("describe")
130
+ @click.argument("project_name_or_id", type=str, required=False)
131
+ def describe_project(project_name_or_id: Optional[str] = None) -> None:
132
+ """Get the project.
133
+
134
+ Args:
135
+ project_name_or_id: The name or ID of the project to set as active.
136
+ """
137
+ check_zenml_pro_project_availability()
138
+ client = Client()
139
+ if not project_name_or_id:
140
+ active_project = client.active_project
141
+ cli_utils.print_pydantic_models(
142
+ [active_project], exclude_columns=["created", "updated"]
143
+ )
144
+ else:
145
+ try:
146
+ project_ = client.get_project(project_name_or_id)
147
+ except KeyError as err:
148
+ cli_utils.error(str(err))
149
+ else:
150
+ cli_utils.print_pydantic_models(
151
+ [project_], exclude_columns=["created", "updated"]
152
+ )
153
+
154
+
155
+ @project.command("delete")
156
+ @click.argument("project_name_or_id", type=str, required=True)
157
+ def delete_project(project_name_or_id: str) -> None:
158
+ """Delete a project.
159
+
160
+ Args:
161
+ project_name_or_id: The name or ID of the project to delete.
162
+ """
163
+ check_zenml_pro_project_availability()
164
+ client = Client()
165
+ with console.status("Deleting project...\n"):
166
+ try:
167
+ client.delete_project(project_name_or_id)
168
+ cli_utils.declare(
169
+ f"Project '{project_name_or_id}' deleted successfully."
170
+ )
171
+ except Exception as e:
172
+ cli_utils.error(str(e))
zenml/cli/secret.py CHANGED
@@ -38,7 +38,6 @@ from zenml.console import console
38
38
  from zenml.constants import SECRET_VALUES
39
39
  from zenml.enums import (
40
40
  CliCategories,
41
- SecretScope,
42
41
  )
43
42
  from zenml.exceptions import EntityExistsError, ZenKeyError
44
43
  from zenml.logger import get_logger
@@ -59,11 +58,12 @@ def secret() -> None:
59
58
  )
60
59
  @click.argument("name", type=click.STRING)
61
60
  @click.option(
62
- "--scope",
63
- "-s",
64
- "scope",
65
- type=click.Choice([scope.value for scope in list(SecretScope)]),
66
- default=SecretScope.WORKSPACE.value,
61
+ "--private",
62
+ "-p",
63
+ "private",
64
+ is_flag=True,
65
+ help="Whether the secret is private. A private secret is only accessible "
66
+ "to the user who creates it.",
67
67
  )
68
68
  @click.option(
69
69
  "--interactive",
@@ -84,13 +84,13 @@ def secret() -> None:
84
84
  )
85
85
  @click.argument("args", nargs=-1, type=click.UNPROCESSED)
86
86
  def create_secret(
87
- name: str, scope: str, interactive: bool, values: str, args: List[str]
87
+ name: str, private: bool, interactive: bool, values: str, args: List[str]
88
88
  ) -> None:
89
89
  """Create a secret.
90
90
 
91
91
  Args:
92
92
  name: The name of the secret to create.
93
- scope: The scope of the secret to create.
93
+ private: Whether the secret is private.
94
94
  interactive: Whether to use interactive mode to enter the secret values.
95
95
  values: Secret key-value pairs to be passed as JSON or YAML.
96
96
  args: The arguments to pass to the secret.
@@ -152,7 +152,7 @@ def create_secret(
152
152
  with console.status(f"Saving secret `{name}`..."):
153
153
  try:
154
154
  client.create_secret(
155
- name=name, values=parsed_args, scope=SecretScope(scope)
155
+ name=name, values=parsed_args, private=private
156
156
  )
157
157
  declare(f"Secret '{name}' successfully created.")
158
158
  except EntityExistsError as e:
@@ -186,7 +186,7 @@ def list_secrets(**kwargs: Any) -> None:
186
186
  dict(
187
187
  name=secret.name,
188
188
  id=str(secret.id),
189
- scope=secret.scope.value,
189
+ private=secret.private,
190
190
  )
191
191
  for secret in secrets.items
192
192
  ]
@@ -200,22 +200,26 @@ def list_secrets(**kwargs: Any) -> None:
200
200
  type=click.STRING,
201
201
  )
202
202
  @click.option(
203
- "--scope",
204
- "-s",
205
- type=click.Choice([scope.value for scope in list(SecretScope)]),
206
- default=None,
203
+ "--private",
204
+ "-p",
205
+ "private",
206
+ type=click.BOOL,
207
+ required=False,
208
+ help="Use this flag to explicitly fetch a private secret or a public secret.",
207
209
  )
208
- def get_secret(name_id_or_prefix: str, scope: Optional[str] = None) -> None:
210
+ def get_secret(name_id_or_prefix: str, private: Optional[bool] = None) -> None:
209
211
  """Get a secret and print it to the console.
210
212
 
211
213
  Args:
212
214
  name_id_or_prefix: The name of the secret to get.
213
- scope: The scope of the secret to get.
215
+ private: Private status of the secret to filter for.
214
216
  """
215
- secret = _get_secret(name_id_or_prefix, scope)
217
+ secret = _get_secret(name_id_or_prefix, private)
218
+ scope = ""
219
+ if private is not None:
220
+ scope = "private " if private else "public "
216
221
  declare(
217
- f"Fetched secret with name `{secret.name}` and ID `{secret.id}` in "
218
- f"scope `{secret.scope.value}`:"
222
+ f"Fetched {scope}secret with name `{secret.name}` and ID `{secret.id}`:"
219
223
  )
220
224
  if not secret.secret_values:
221
225
  warning(f"Secret with name `{name_id_or_prefix}` is empty.")
@@ -224,25 +228,22 @@ def get_secret(name_id_or_prefix: str, scope: Optional[str] = None) -> None:
224
228
 
225
229
 
226
230
  def _get_secret(
227
- name_id_or_prefix: str, scope: Optional[str] = None
231
+ name_id_or_prefix: str, private: Optional[bool] = None
228
232
  ) -> SecretResponse:
229
233
  """Get a secret with a given name, prefix or id.
230
234
 
231
235
  Args:
232
236
  name_id_or_prefix: The name of the secret to get.
233
- scope: The scope of the secret to get.
237
+ private: Private status of the secret to filter for.
234
238
 
235
239
  Returns:
236
240
  The secret response model.
237
241
  """
238
242
  client = Client()
239
243
  try:
240
- if scope:
241
- return client.get_secret(
242
- name_id_or_prefix=name_id_or_prefix, scope=SecretScope(scope)
243
- )
244
- else:
245
- return client.get_secret(name_id_or_prefix=name_id_or_prefix)
244
+ return client.get_secret(
245
+ name_id_or_prefix=name_id_or_prefix, private=private
246
+ )
246
247
  except ZenKeyError as e:
247
248
  error(
248
249
  f"Error fetching secret with name id or prefix "
@@ -267,9 +268,12 @@ def _get_secret(
267
268
  type=click.STRING,
268
269
  )
269
270
  @click.option(
270
- "--new-scope",
271
- "-s",
272
- type=click.Choice([scope.value for scope in list(SecretScope)]),
271
+ "--private",
272
+ "-p",
273
+ "private",
274
+ type=click.BOOL,
275
+ required=False,
276
+ help="Update the private status of the secret.",
273
277
  )
274
278
  @click.option(
275
279
  "--interactive",
@@ -293,7 +297,7 @@ def _get_secret(
293
297
  def update_secret(
294
298
  name_or_id: str,
295
299
  extra_args: List[str],
296
- new_scope: Optional[str] = None,
300
+ private: Optional[bool] = None,
297
301
  remove_keys: List[str] = [],
298
302
  interactive: bool = False,
299
303
  values: str = "",
@@ -302,7 +306,7 @@ def update_secret(
302
306
 
303
307
  Args:
304
308
  name_or_id: The name or id of the secret to update.
305
- new_scope: The new scope of the secret.
309
+ private: Private status of the secret to update.
306
310
  extra_args: The arguments to pass to the secret.
307
311
  interactive: Whether to use interactive mode to update the secret.
308
312
  remove_keys: The keys to remove from the secret.
@@ -331,10 +335,7 @@ def update_secret(
331
335
  except NotImplementedError as e:
332
336
  error(f"Centralized secrets management is disabled: {str(e)}")
333
337
 
334
- declare(
335
- f"Updating secret with name '{secret.name}' and ID '{secret.id}' in "
336
- f"scope '{secret.scope.value}:"
337
- )
338
+ declare(f"Updating secret with name '{secret.name}' and ID '{secret.id}'")
338
339
 
339
340
  if "name" in parsed_args:
340
341
  error("The word 'name' cannot be used as a key for a secret.")
@@ -388,7 +389,7 @@ def update_secret(
388
389
 
389
390
  client.update_secret(
390
391
  name_id_or_prefix=secret.id,
391
- new_scope=SecretScope(new_scope) if new_scope else None,
392
+ update_private=private,
392
393
  add_or_update_values=secret_args_add_update,
393
394
  remove_values=remove_keys,
394
395
  )
@@ -492,10 +493,12 @@ def delete_secret(name_or_id: str, yes: bool = False) -> None:
492
493
  type=click.STRING,
493
494
  )
494
495
  @click.option(
495
- "--scope",
496
- "-s",
497
- type=click.Choice([scope.value for scope in list(SecretScope)]),
498
- default=None,
496
+ "--private",
497
+ "-p",
498
+ "private",
499
+ type=click.BOOL,
500
+ required=False,
501
+ help="Use this flag to explicitly fetch a private secret or a public secret.",
499
502
  )
500
503
  @click.option(
501
504
  "--filename",
@@ -509,7 +512,7 @@ def delete_secret(name_or_id: str, yes: bool = False) -> None:
509
512
  )
510
513
  def export_secret(
511
514
  name_id_or_prefix: str,
512
- scope: Optional[str] = None,
515
+ private: Optional[bool] = None,
513
516
  filename: Optional[str] = None,
514
517
  ) -> None:
515
518
  """Export a secret as a YAML file.
@@ -519,12 +522,12 @@ def export_secret(
519
522
 
520
523
  Args:
521
524
  name_id_or_prefix: The name of the secret to export.
522
- scope: The scope of the secret to export.
525
+ private: Private status of the secret to export.
523
526
  filename: The name of the file to export the secret to.
524
527
  """
525
528
  from zenml.utils.yaml_utils import write_yaml
526
529
 
527
- secret = _get_secret(name_id_or_prefix=name_id_or_prefix, scope=scope)
530
+ secret = _get_secret(name_id_or_prefix=name_id_or_prefix, private=private)
528
531
  if not secret.secret_values:
529
532
  warning(f"Secret with name `{name_id_or_prefix}` is empty.")
530
533
  return
@@ -410,7 +410,6 @@ def list_api_keys(service_account_name_or_id: str, **kwargs: Any) -> None:
410
410
  exclude_columns=[
411
411
  "created",
412
412
  "updated",
413
- "workspace",
414
413
  "key",
415
414
  "retain_period_minutes",
416
415
  ],