zenml-nightly 0.75.0.dev20250311__py3-none-any.whl → 0.75.0.dev20250313__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zenml/VERSION +1 -1
- zenml/__init__.py +2 -0
- zenml/analytics/context.py +7 -0
- zenml/artifacts/utils.py +0 -2
- zenml/cli/login.py +6 -0
- zenml/cli/model.py +7 -15
- zenml/cli/secret.py +47 -44
- zenml/cli/service_connectors.py +0 -1
- zenml/cli/stack.py +0 -1
- zenml/cli/tag.py +3 -5
- zenml/cli/utils.py +25 -23
- zenml/cli/workspace.py +79 -5
- zenml/client.py +618 -348
- zenml/config/global_config.py +16 -3
- 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 +1 -3
- 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/github/plugins/event_sources/github_webhook_event_source.py +1 -4
- zenml/integrations/mlflow/steps/mlflow_registry.py +1 -1
- zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
- zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +3 -3
- zenml/model/model.py +8 -8
- zenml/models/__init__.py +18 -1
- zenml/models/v2/base/base.py +0 -5
- zenml/models/v2/base/filter.py +1 -1
- zenml/models/v2/base/scoped.py +104 -121
- zenml/models/v2/core/api_key.py +1 -1
- zenml/models/v2/core/artifact.py +31 -18
- zenml/models/v2/core/artifact_version.py +42 -25
- zenml/models/v2/core/component.py +22 -33
- zenml/models/v2/core/device.py +3 -2
- zenml/models/v2/core/event_source.py +2 -2
- zenml/models/v2/core/flavor.py +19 -47
- zenml/models/v2/core/logs.py +1 -2
- zenml/models/v2/core/model.py +7 -4
- zenml/models/v2/core/model_version.py +36 -27
- zenml/models/v2/core/pipeline.py +1 -1
- zenml/models/v2/core/pipeline_build.py +18 -0
- zenml/models/v2/core/pipeline_run.py +5 -13
- zenml/models/v2/core/run_template.py +1 -2
- zenml/models/v2/core/schedule.py +0 -9
- zenml/models/v2/core/secret.py +93 -127
- zenml/models/v2/core/server_settings.py +2 -2
- zenml/models/v2/core/service.py +43 -12
- zenml/models/v2/core/service_connector.py +14 -16
- zenml/models/v2/core/stack.py +24 -26
- zenml/models/v2/core/step_run.py +3 -15
- zenml/models/v2/core/tag.py +41 -15
- zenml/models/v2/core/user.py +19 -2
- zenml/models/v2/misc/statistics.py +45 -0
- zenml/models/v2/misc/tag.py +27 -0
- zenml/orchestrators/cache_utils.py +1 -1
- zenml/orchestrators/input_utils.py +1 -0
- zenml/orchestrators/step_launcher.py +0 -1
- zenml/orchestrators/step_run_utils.py +0 -2
- zenml/orchestrators/step_runner.py +10 -1
- zenml/pipelines/build_utils.py +4 -2
- zenml/pipelines/pipeline_decorator.py +3 -2
- zenml/pipelines/pipeline_definition.py +4 -5
- zenml/pipelines/run_utils.py +3 -3
- zenml/service_connectors/service_connector.py +0 -7
- zenml/service_connectors/service_connector_utils.py +0 -1
- zenml/stack/authentication_mixin.py +1 -1
- zenml/stack/flavor.py +3 -14
- zenml/stack/stack_component.py +1 -5
- 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 +156 -29
- zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -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 +56 -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 +102 -23
- zenml/zen_server/routers/models_endpoints.py +51 -68
- zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
- zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
- zenml/zen_server/routers/pipelines_endpoints.py +73 -4
- zenml/zen_server/routers/plugin_endpoints.py +0 -1
- zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
- zenml/zen_server/routers/run_templates_endpoints.py +66 -3
- zenml/zen_server/routers/runs_endpoints.py +60 -8
- zenml/zen_server/routers/schedule_endpoints.py +69 -6
- zenml/zen_server/routers/secrets_endpoints.py +40 -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 +96 -14
- zenml/zen_server/routers/service_endpoints.py +20 -7
- zenml/zen_server/routers/stack_components_endpoints.py +68 -7
- zenml/zen_server/routers/stacks_endpoints.py +98 -7
- 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 +47 -12
- zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
- zenml/zen_server/template_execution/utils.py +5 -4
- zenml/zen_server/utils.py +21 -0
- zenml/zen_server/zen_server_api.py +4 -0
- zenml/zen_stores/base_zen_store.py +29 -44
- zenml/zen_stores/migrations/versions/0392807467dc_add_build_duration.py +34 -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/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 +172 -171
- zenml/zen_stores/schemas/action_schemas.py +8 -1
- zenml/zen_stores/schemas/api_key_schemas.py +8 -1
- zenml/zen_stores/schemas/artifact_schemas.py +28 -1
- zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
- zenml/zen_stores/schemas/component_schemas.py +9 -14
- zenml/zen_stores/schemas/event_source_schemas.py +8 -1
- zenml/zen_stores/schemas/flavor_schemas.py +14 -20
- zenml/zen_stores/schemas/model_schemas.py +3 -0
- zenml/zen_stores/schemas/pipeline_build_schemas.py +4 -0
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
- zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
- zenml/zen_stores/schemas/run_template_schemas.py +8 -4
- zenml/zen_stores/schemas/schedule_schema.py +9 -14
- 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 +0 -1
- zenml/zen_stores/schemas/stack_schemas.py +12 -15
- zenml/zen_stores/schemas/step_run_schemas.py +7 -8
- zenml/zen_stores/schemas/tag_schemas.py +30 -2
- zenml/zen_stores/schemas/trigger_schemas.py +8 -1
- zenml/zen_stores/schemas/user_schemas.py +24 -2
- zenml/zen_stores/schemas/utils.py +16 -0
- zenml/zen_stores/schemas/workspace_schemas.py +7 -25
- zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
- zenml/zen_stores/sql_zen_store.py +2905 -2280
- zenml/zen_stores/template_utils.py +1 -1
- zenml/zen_stores/zen_store_interface.py +82 -58
- {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
- {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +163 -149
- {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.75.0.dev20250311.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
zenml/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.75.0.
|
1
|
+
0.75.0.dev20250313
|
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.workspace_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.workspace_id = Client().active_workspace.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.workspace_id:
|
312
|
+
properties.setdefault("workspace_id", str(self.workspace_id))
|
313
|
+
|
307
314
|
for k, v in properties.items():
|
308
315
|
if isinstance(v, UUID):
|
309
316
|
properties[k] = str(v)
|
zenml/artifacts/utils.py
CHANGED
@@ -182,7 +182,6 @@ 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
185
|
workspace=Client().active_workspace.id,
|
187
186
|
artifact_store_id=artifact_store.id,
|
188
187
|
visualizations=visualizations,
|
@@ -350,7 +349,6 @@ 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
352
|
workspace=Client().active_workspace.id,
|
355
353
|
artifact_store_id=artifact_store.id,
|
356
354
|
has_custom_name=has_custom_name,
|
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/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
|
zenml/cli/service_connectors.py
CHANGED
zenml/cli/stack.py
CHANGED
zenml/cli/tag.py
CHANGED
@@ -26,8 +26,6 @@ from zenml.exceptions import EntityExistsError
|
|
26
26
|
from zenml.logger import get_logger
|
27
27
|
from zenml.models import (
|
28
28
|
TagFilter,
|
29
|
-
TagRequest,
|
30
|
-
TagUpdate,
|
31
29
|
)
|
32
30
|
from zenml.utils.dict_utils import remove_none_values
|
33
31
|
|
@@ -47,7 +45,7 @@ def list_tags(**kwargs: Any) -> None:
|
|
47
45
|
Args:
|
48
46
|
**kwargs: Keyword arguments to filter models.
|
49
47
|
"""
|
50
|
-
tags = Client().list_tags(
|
48
|
+
tags = Client().list_tags(**kwargs)
|
51
49
|
|
52
50
|
if not tags:
|
53
51
|
cli_utils.declare("No tags found.")
|
@@ -83,7 +81,7 @@ def register_tag(name: str, color: Optional[ColorVariants]) -> None:
|
|
83
81
|
"""
|
84
82
|
request_dict = remove_none_values(dict(name=name, color=color))
|
85
83
|
try:
|
86
|
-
tag = Client().create_tag(
|
84
|
+
tag = Client().create_tag(**request_dict)
|
87
85
|
except (EntityExistsError, ValueError) as e:
|
88
86
|
cli_utils.error(str(e))
|
89
87
|
|
@@ -126,7 +124,7 @@ def update_tag(
|
|
126
124
|
|
127
125
|
tag = Client().update_tag(
|
128
126
|
tag_name_or_id=tag_name_or_id,
|
129
|
-
|
127
|
+
**update_dict,
|
130
128
|
)
|
131
129
|
|
132
130
|
cli_utils.print_pydantic_models(
|
zenml/cli/utils.py
CHANGED
@@ -81,6 +81,7 @@ from zenml.stack.flavor import Flavor
|
|
81
81
|
from zenml.stack.stack_component import StackComponentConfig
|
82
82
|
from zenml.utils import secret_utils
|
83
83
|
from zenml.utils.time_utils import expires_in
|
84
|
+
from zenml.utils.typing_utils import get_origin, is_union
|
84
85
|
|
85
86
|
if TYPE_CHECKING:
|
86
87
|
from uuid import UUID
|
@@ -1778,7 +1779,6 @@ def print_service_connector_configuration(
|
|
1778
1779
|
"AUTH METHOD": connector.auth_method,
|
1779
1780
|
"RESOURCE TYPES": ", ".join(connector.emojified_resource_types),
|
1780
1781
|
"RESOURCE NAME": connector.resource_id or "<multiple>",
|
1781
|
-
"SECRET ID": connector.secret_id or "",
|
1782
1782
|
"SESSION DURATION": expiration,
|
1783
1783
|
"EXPIRES IN": (
|
1784
1784
|
expires_in(
|
@@ -1795,7 +1795,6 @@ def print_service_connector_configuration(
|
|
1795
1795
|
else "N/A"
|
1796
1796
|
),
|
1797
1797
|
"OWNER": user_name,
|
1798
|
-
"WORKSPACE": connector.workspace.name,
|
1799
1798
|
"CREATED_AT": connector.created,
|
1800
1799
|
"UPDATED_AT": connector.updated,
|
1801
1800
|
}
|
@@ -2161,9 +2160,6 @@ def print_debug_stack() -> None:
|
|
2161
2160
|
console.print(f"ID: {str(stack.id)}")
|
2162
2161
|
if stack.user and stack.user.name and stack.user.id: # mypy check
|
2163
2162
|
console.print(f"User: {stack.user.name} / {str(stack.user.id)}")
|
2164
|
-
console.print(
|
2165
|
-
f"Workspace: {stack.workspace.name} / {str(stack.workspace.id)}"
|
2166
|
-
)
|
2167
2163
|
|
2168
2164
|
for component_type, components in stack.components.items():
|
2169
2165
|
component = components[0]
|
@@ -2190,9 +2186,6 @@ def print_debug_stack() -> None:
|
|
2190
2186
|
console.print(
|
2191
2187
|
f"User: {component_response.user.name} / {str(component_response.user.id)}"
|
2192
2188
|
)
|
2193
|
-
console.print(
|
2194
|
-
f"Workspace: {component_response.workspace.name} / {str(component_response.workspace.id)}"
|
2195
|
-
)
|
2196
2189
|
|
2197
2190
|
|
2198
2191
|
def _component_display_name(
|
@@ -2275,22 +2268,13 @@ def print_pipeline_runs_table(
|
|
2275
2268
|
print_table(runs_dicts)
|
2276
2269
|
|
2277
2270
|
|
2278
|
-
def
|
2279
|
-
"""
|
2280
|
-
|
2281
|
-
|
2282
|
-
handle_bool_env_var,
|
2283
|
-
)
|
2284
|
-
|
2285
|
-
disable_warnings = handle_bool_env_var(
|
2286
|
-
ENV_ZENML_DISABLE_WORKSPACE_WARNINGS, False
|
2287
|
-
)
|
2288
|
-
if not disable_warnings:
|
2271
|
+
def check_zenml_pro_workspace_availability() -> None:
|
2272
|
+
"""Check if the ZenML Pro workspace feature is available."""
|
2273
|
+
client = Client()
|
2274
|
+
if not client.zen_store.get_store_info().is_pro_server():
|
2289
2275
|
warning(
|
2290
|
-
"
|
2291
|
-
"
|
2292
|
-
"completed in the coming weeks. For the time being it "
|
2293
|
-
"is recommended to stay within the `default` workspace."
|
2276
|
+
"The ZenML workspace feature is available only on ZenML Pro. "
|
2277
|
+
"Please visit https://zenml.io/pro to learn more."
|
2294
2278
|
)
|
2295
2279
|
|
2296
2280
|
|
@@ -2402,6 +2386,23 @@ def create_data_type_help_text(
|
|
2402
2386
|
return f"{field}"
|
2403
2387
|
|
2404
2388
|
|
2389
|
+
def _is_list_field(field_info: Any) -> bool:
|
2390
|
+
"""Check if a field is a list field.
|
2391
|
+
|
2392
|
+
Args:
|
2393
|
+
field_info: The field info to check.
|
2394
|
+
|
2395
|
+
Returns:
|
2396
|
+
True if the field is a list field, False otherwise.
|
2397
|
+
"""
|
2398
|
+
field_type = field_info.annotation
|
2399
|
+
origin = get_origin(field_type)
|
2400
|
+
return origin is list or (
|
2401
|
+
is_union(origin)
|
2402
|
+
and any(get_origin(arg) is list for arg in field_type.__args__)
|
2403
|
+
)
|
2404
|
+
|
2405
|
+
|
2405
2406
|
def list_options(filter_model: Type[BaseFilter]) -> Callable[[F], F]:
|
2406
2407
|
"""Create a decorator to generate the correct list of filter parameters.
|
2407
2408
|
|
@@ -2430,6 +2431,7 @@ def list_options(filter_model: Type[BaseFilter]) -> Callable[[F], F]:
|
|
2430
2431
|
type=str,
|
2431
2432
|
default=v.default,
|
2432
2433
|
required=False,
|
2434
|
+
multiple=_is_list_field(v),
|
2433
2435
|
help=create_filter_help_text(filter_model, k),
|
2434
2436
|
)
|
2435
2437
|
)
|
zenml/cli/workspace.py
CHANGED
@@ -20,9 +20,9 @@ import click
|
|
20
20
|
from zenml.cli import utils as cli_utils
|
21
21
|
from zenml.cli.cli import TagGroup, cli
|
22
22
|
from zenml.cli.utils import (
|
23
|
+
check_zenml_pro_workspace_availability,
|
23
24
|
is_sorted_or_filtered,
|
24
25
|
list_options,
|
25
|
-
warn_unsupported_non_default_workspace,
|
26
26
|
)
|
27
27
|
from zenml.client import Client
|
28
28
|
from zenml.console import console
|
@@ -35,7 +35,7 @@ def workspace() -> None:
|
|
35
35
|
"""Commands for workspace management."""
|
36
36
|
|
37
37
|
|
38
|
-
@workspace.command("list"
|
38
|
+
@workspace.command("list")
|
39
39
|
@list_options(WorkspaceFilter)
|
40
40
|
@click.pass_context
|
41
41
|
def list_workspaces(ctx: click.Context, **kwargs: Any) -> None:
|
@@ -45,7 +45,7 @@ def list_workspaces(ctx: click.Context, **kwargs: Any) -> None:
|
|
45
45
|
ctx: The click context object
|
46
46
|
**kwargs: Keyword arguments to filter the list of workspaces.
|
47
47
|
"""
|
48
|
-
|
48
|
+
check_zenml_pro_workspace_availability()
|
49
49
|
client = Client()
|
50
50
|
with console.status("Listing workspaces...\n"):
|
51
51
|
workspaces = client.list_workspaces(**kwargs)
|
@@ -60,7 +60,61 @@ def list_workspaces(ctx: click.Context, **kwargs: Any) -> None:
|
|
60
60
|
cli_utils.declare("No workspaces found for the given filter.")
|
61
61
|
|
62
62
|
|
63
|
-
@workspace.command("
|
63
|
+
@workspace.command("register")
|
64
|
+
@click.option(
|
65
|
+
"--set",
|
66
|
+
"set_workspace",
|
67
|
+
is_flag=True,
|
68
|
+
help="Immediately set this workspace as active.",
|
69
|
+
type=click.BOOL,
|
70
|
+
)
|
71
|
+
@click.argument("workspace_name", type=str, required=True)
|
72
|
+
def register_workspace(
|
73
|
+
workspace_name: str, set_workspace: bool = False
|
74
|
+
) -> None:
|
75
|
+
"""Register a new workspace.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
workspace_name: The name of the workspace to register.
|
79
|
+
set_workspace: Whether to set the workspace as active.
|
80
|
+
"""
|
81
|
+
check_zenml_pro_workspace_availability()
|
82
|
+
client = Client()
|
83
|
+
with console.status("Creating workspace...\n"):
|
84
|
+
try:
|
85
|
+
client.create_workspace(workspace_name, description="")
|
86
|
+
cli_utils.declare("Workspace created successfully.")
|
87
|
+
except Exception as e:
|
88
|
+
cli_utils.error(str(e))
|
89
|
+
|
90
|
+
if set_workspace:
|
91
|
+
client.set_active_workspace(workspace_name)
|
92
|
+
cli_utils.declare(
|
93
|
+
f"The active workspace has been set to {workspace_name}"
|
94
|
+
)
|
95
|
+
|
96
|
+
|
97
|
+
@workspace.command("set")
|
98
|
+
@click.argument("workspace_name_or_id", type=str, required=True)
|
99
|
+
def set_workspace(workspace_name_or_id: str) -> None:
|
100
|
+
"""Set the active workspace.
|
101
|
+
|
102
|
+
Args:
|
103
|
+
workspace_name_or_id: The name or ID of the workspace to set as active.
|
104
|
+
"""
|
105
|
+
check_zenml_pro_workspace_availability()
|
106
|
+
client = Client()
|
107
|
+
with console.status("Setting workspace...\n"):
|
108
|
+
try:
|
109
|
+
client.set_active_workspace(workspace_name_or_id)
|
110
|
+
cli_utils.declare(
|
111
|
+
f"The active workspace has been set to {workspace_name_or_id}"
|
112
|
+
)
|
113
|
+
except Exception as e:
|
114
|
+
cli_utils.error(str(e))
|
115
|
+
|
116
|
+
|
117
|
+
@workspace.command("describe")
|
64
118
|
@click.argument("workspace_name_or_id", type=str, required=False)
|
65
119
|
def describe_workspace(workspace_name_or_id: Optional[str] = None) -> None:
|
66
120
|
"""Get the workspace.
|
@@ -68,7 +122,7 @@ def describe_workspace(workspace_name_or_id: Optional[str] = None) -> None:
|
|
68
122
|
Args:
|
69
123
|
workspace_name_or_id: The name or ID of the workspace to set as active.
|
70
124
|
"""
|
71
|
-
|
125
|
+
check_zenml_pro_workspace_availability()
|
72
126
|
client = Client()
|
73
127
|
if not workspace_name_or_id:
|
74
128
|
active_workspace = client.active_workspace
|
@@ -84,3 +138,23 @@ def describe_workspace(workspace_name_or_id: Optional[str] = None) -> None:
|
|
84
138
|
cli_utils.print_pydantic_models(
|
85
139
|
[workspace_], exclude_columns=["created", "updated"]
|
86
140
|
)
|
141
|
+
|
142
|
+
|
143
|
+
@workspace.command("delete")
|
144
|
+
@click.argument("workspace_name_or_id", type=str, required=True)
|
145
|
+
def delete_workspace(workspace_name_or_id: str) -> None:
|
146
|
+
"""Delete a workspace.
|
147
|
+
|
148
|
+
Args:
|
149
|
+
workspace_name_or_id: The name or ID of the workspace to delete.
|
150
|
+
"""
|
151
|
+
check_zenml_pro_workspace_availability()
|
152
|
+
client = Client()
|
153
|
+
with console.status("Deleting workspace...\n"):
|
154
|
+
try:
|
155
|
+
client.delete_workspace(workspace_name_or_id)
|
156
|
+
cli_utils.declare(
|
157
|
+
f"Workspace '{workspace_name_or_id}' deleted successfully."
|
158
|
+
)
|
159
|
+
except Exception as e:
|
160
|
+
cli_utils.error(str(e))
|