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.
- zenml/VERSION +1 -1
- zenml/__init__.py +2 -0
- zenml/analytics/context.py +7 -0
- zenml/analytics/enums.py +2 -2
- zenml/artifacts/utils.py +2 -4
- zenml/cli/__init__.py +8 -9
- zenml/cli/base.py +2 -2
- zenml/cli/code_repository.py +1 -1
- zenml/cli/login.py +6 -0
- zenml/cli/model.py +7 -15
- zenml/cli/pipeline.py +3 -3
- zenml/cli/project.py +172 -0
- zenml/cli/secret.py +47 -44
- zenml/cli/service_accounts.py +0 -1
- zenml/cli/service_connectors.py +15 -17
- zenml/cli/stack.py +0 -3
- zenml/cli/stack_components.py +2 -2
- zenml/cli/tag.py +3 -5
- zenml/cli/utils.py +25 -23
- zenml/client.py +749 -475
- zenml/config/global_config.py +48 -37
- zenml/config/pipeline_configurations.py +3 -2
- zenml/config/pipeline_run_configuration.py +2 -1
- zenml/config/secret_reference_mixin.py +1 -1
- zenml/constants.py +6 -6
- zenml/enums.py +0 -7
- zenml/event_hub/event_hub.py +3 -1
- zenml/exceptions.py +0 -24
- zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
- zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +7 -6
- zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
- zenml/integrations/mlflow/steps/mlflow_registry.py +3 -3
- zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
- zenml/integrations/wandb/__init__.py +1 -1
- zenml/integrations/wandb/experiment_trackers/wandb_experiment_tracker.py +29 -9
- zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +5 -3
- zenml/model/model.py +10 -10
- zenml/model_registries/base_model_registry.py +1 -1
- zenml/models/__init__.py +45 -28
- zenml/models/v2/base/base.py +0 -5
- zenml/models/v2/base/filter.py +2 -2
- zenml/models/v2/base/scoped.py +135 -156
- zenml/models/v2/core/action.py +12 -12
- zenml/models/v2/core/api_key.py +1 -1
- zenml/models/v2/core/artifact.py +31 -18
- zenml/models/v2/core/artifact_version.py +57 -40
- zenml/models/v2/core/code_repository.py +12 -12
- zenml/models/v2/core/component.py +22 -33
- zenml/models/v2/core/device.py +3 -2
- zenml/models/v2/core/event_source.py +14 -14
- zenml/models/v2/core/flavor.py +19 -47
- zenml/models/v2/core/logs.py +1 -2
- zenml/models/v2/core/model.py +23 -20
- zenml/models/v2/core/model_version.py +51 -42
- zenml/models/v2/core/pipeline.py +16 -16
- zenml/models/v2/core/pipeline_build.py +14 -14
- zenml/models/v2/core/pipeline_deployment.py +12 -14
- zenml/models/v2/core/pipeline_run.py +21 -29
- zenml/models/v2/core/project.py +203 -0
- zenml/models/v2/core/run_metadata.py +2 -2
- zenml/models/v2/core/run_template.py +16 -17
- zenml/models/v2/core/schedule.py +12 -21
- zenml/models/v2/core/secret.py +94 -128
- zenml/models/v2/core/server_settings.py +2 -2
- zenml/models/v2/core/service.py +57 -26
- zenml/models/v2/core/service_connector.py +14 -16
- zenml/models/v2/core/stack.py +24 -26
- zenml/models/v2/core/step_run.py +16 -28
- zenml/models/v2/core/tag.py +41 -15
- zenml/models/v2/core/trigger.py +13 -13
- zenml/models/v2/core/trigger_execution.py +2 -2
- zenml/models/v2/core/user.py +2 -2
- zenml/models/v2/misc/statistics.py +45 -0
- zenml/models/v2/misc/tag.py +27 -0
- zenml/orchestrators/cache_utils.py +7 -7
- zenml/orchestrators/input_utils.py +1 -0
- zenml/orchestrators/step_launcher.py +1 -2
- zenml/orchestrators/step_run_utils.py +2 -4
- zenml/orchestrators/step_runner.py +10 -1
- zenml/orchestrators/utils.py +4 -4
- zenml/pipelines/build_utils.py +2 -4
- zenml/pipelines/pipeline_decorator.py +3 -2
- zenml/pipelines/pipeline_definition.py +8 -9
- zenml/pipelines/run_utils.py +4 -4
- zenml/service_connectors/service_connector.py +0 -10
- zenml/service_connectors/service_connector_utils.py +0 -2
- zenml/stack/authentication_mixin.py +1 -1
- zenml/stack/flavor.py +3 -14
- zenml/stack/stack.py +0 -1
- zenml/stack/stack_component.py +1 -5
- zenml/steps/base_step.py +10 -2
- zenml/steps/step_context.py +19 -0
- zenml/utils/string_utils.py +1 -1
- zenml/utils/tag_utils.py +642 -0
- zenml/zen_server/cloud_utils.py +21 -0
- zenml/zen_server/exceptions.py +0 -6
- zenml/zen_server/rbac/endpoint_utils.py +134 -46
- zenml/zen_server/rbac/models.py +65 -3
- zenml/zen_server/rbac/rbac_interface.py +9 -0
- zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
- zenml/zen_server/rbac/utils.py +155 -30
- zenml/zen_server/rbac/zenml_cloud_rbac.py +39 -11
- zenml/zen_server/routers/actions_endpoints.py +3 -5
- zenml/zen_server/routers/artifact_endpoint.py +0 -5
- zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
- zenml/zen_server/routers/auth_endpoints.py +22 -7
- zenml/zen_server/routers/code_repositories_endpoints.py +54 -3
- zenml/zen_server/routers/devices_endpoints.py +0 -4
- zenml/zen_server/routers/event_source_endpoints.py +0 -5
- zenml/zen_server/routers/flavors_endpoints.py +0 -5
- zenml/zen_server/routers/logs_endpoints.py +0 -1
- zenml/zen_server/routers/model_versions_endpoints.py +100 -23
- zenml/zen_server/routers/models_endpoints.py +50 -69
- zenml/zen_server/routers/pipeline_builds_endpoints.py +55 -3
- zenml/zen_server/routers/pipeline_deployments_endpoints.py +56 -4
- zenml/zen_server/routers/pipelines_endpoints.py +70 -3
- zenml/zen_server/routers/plugin_endpoints.py +0 -1
- zenml/zen_server/routers/projects_endpoints.py +283 -0
- zenml/zen_server/routers/run_metadata_endpoints.py +97 -0
- zenml/zen_server/routers/run_templates_endpoints.py +64 -3
- zenml/zen_server/routers/runs_endpoints.py +58 -8
- zenml/zen_server/routers/schedule_endpoints.py +67 -6
- zenml/zen_server/routers/secrets_endpoints.py +38 -4
- zenml/zen_server/routers/server_endpoints.py +53 -1
- zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
- zenml/zen_server/routers/service_connectors_endpoints.py +94 -14
- zenml/zen_server/routers/service_endpoints.py +18 -7
- zenml/zen_server/routers/stack_components_endpoints.py +66 -7
- zenml/zen_server/routers/stacks_endpoints.py +95 -6
- zenml/zen_server/routers/steps_endpoints.py +17 -11
- zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
- zenml/zen_server/routers/tags_endpoints.py +6 -17
- zenml/zen_server/routers/triggers_endpoints.py +5 -8
- zenml/zen_server/routers/users_endpoints.py +9 -12
- zenml/zen_server/template_execution/utils.py +8 -7
- zenml/zen_server/utils.py +21 -0
- zenml/zen_server/zen_server_api.py +7 -2
- zenml/zen_stores/base_zen_store.py +50 -69
- zenml/zen_stores/migrations/versions/12eff0206201_rename_workspace_to_project.py +768 -0
- zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
- zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
- zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
- zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
- zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
- zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
- zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
- zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
- zenml/zen_stores/migrations/versions/cbc6acd71f92_add_workspace_display_name.py +58 -0
- zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
- zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
- zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
- zenml/zen_stores/rest_zen_store.py +223 -230
- zenml/zen_stores/schemas/__init__.py +2 -2
- zenml/zen_stores/schemas/action_schemas.py +15 -8
- zenml/zen_stores/schemas/api_key_schemas.py +8 -1
- zenml/zen_stores/schemas/artifact_schemas.py +35 -10
- zenml/zen_stores/schemas/code_repository_schemas.py +22 -17
- zenml/zen_stores/schemas/component_schemas.py +9 -14
- zenml/zen_stores/schemas/event_source_schemas.py +15 -8
- zenml/zen_stores/schemas/flavor_schemas.py +14 -20
- zenml/zen_stores/schemas/model_schemas.py +18 -17
- zenml/zen_stores/schemas/pipeline_build_schemas.py +7 -7
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +10 -8
- zenml/zen_stores/schemas/pipeline_run_schemas.py +9 -12
- zenml/zen_stores/schemas/pipeline_schemas.py +9 -9
- zenml/zen_stores/schemas/{workspace_schemas.py → project_schemas.py} +53 -65
- zenml/zen_stores/schemas/run_metadata_schemas.py +5 -5
- zenml/zen_stores/schemas/run_template_schemas.py +17 -13
- zenml/zen_stores/schemas/schedule_schema.py +16 -21
- zenml/zen_stores/schemas/secret_schemas.py +15 -25
- zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
- zenml/zen_stores/schemas/service_schemas.py +7 -8
- zenml/zen_stores/schemas/stack_schemas.py +12 -15
- zenml/zen_stores/schemas/step_run_schemas.py +14 -15
- zenml/zen_stores/schemas/tag_schemas.py +30 -2
- zenml/zen_stores/schemas/trigger_schemas.py +15 -8
- zenml/zen_stores/schemas/user_schemas.py +12 -2
- zenml/zen_stores/schemas/utils.py +16 -0
- zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
- zenml/zen_stores/sql_zen_store.py +2984 -2369
- zenml/zen_stores/template_utils.py +1 -1
- zenml/zen_stores/zen_store_interface.py +136 -126
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/METADATA +1 -1
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/RECORD +188 -173
- zenml/cli/workspace.py +0 -86
- zenml/models/v2/core/workspace.py +0 -131
- zenml/zen_server/routers/workspaces_endpoints.py +0 -1469
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250314.dist-info}/WHEEL +0 -0
- {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.
|
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",
|
zenml/analytics/context.py
CHANGED
@@ -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
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
|
-
|
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
|
-
|
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
|
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
|
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
|
2074
|
-
|
2075
|
-
|
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.
|
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
|
-
"
|
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
|
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:
|
zenml/cli/code_repository.py
CHANGED
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().
|
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
|
-
|
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
|
-
|
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().
|
418
|
-
model_name_or_id=
|
419
|
-
|
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", "
|
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", "
|
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
|
-
"
|
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
|
-
"--
|
63
|
-
"-
|
64
|
-
"
|
65
|
-
|
66
|
-
|
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,
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
"--
|
204
|
-
"-
|
205
|
-
|
206
|
-
|
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,
|
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
|
-
|
215
|
+
private: Private status of the secret to filter for.
|
214
216
|
"""
|
215
|
-
secret = _get_secret(name_id_or_prefix,
|
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}
|
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,
|
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
|
-
|
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
|
-
|
241
|
-
|
242
|
-
|
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
|
-
"--
|
271
|
-
"-
|
272
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
"--
|
496
|
-
"-
|
497
|
-
|
498
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|