zenml-nightly 0.75.0.dev20250313__py3-none-any.whl → 0.75.0.dev20250315__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/analytics/context.py +4 -4
- zenml/analytics/enums.py +2 -2
- zenml/artifacts/utils.py +2 -2
- zenml/cli/__init__.py +8 -9
- zenml/cli/base.py +2 -2
- zenml/cli/code_repository.py +1 -1
- zenml/cli/login.py +21 -18
- zenml/cli/pipeline.py +3 -3
- zenml/cli/project.py +172 -0
- zenml/cli/server.py +5 -5
- zenml/cli/service_accounts.py +0 -1
- zenml/cli/service_connectors.py +15 -16
- zenml/cli/stack.py +0 -2
- zenml/cli/stack_components.py +2 -2
- zenml/cli/utils.py +3 -3
- zenml/client.py +352 -341
- zenml/config/global_config.py +41 -43
- zenml/config/server_config.py +9 -9
- zenml/constants.py +5 -3
- zenml/event_hub/event_hub.py +1 -1
- zenml/integrations/gcp/__init__.py +1 -0
- zenml/integrations/gcp/flavors/vertex_orchestrator_flavor.py +5 -0
- zenml/integrations/gcp/flavors/vertex_step_operator_flavor.py +5 -28
- zenml/integrations/gcp/orchestrators/vertex_orchestrator.py +125 -78
- zenml/integrations/gcp/service_connectors/gcp_service_connector.py +7 -6
- zenml/integrations/gcp/vertex_custom_job_parameters.py +50 -0
- zenml/integrations/mlflow/steps/mlflow_registry.py +3 -3
- 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 +2 -0
- zenml/login/credentials.py +26 -27
- zenml/login/credentials_store.py +5 -5
- zenml/login/pro/client.py +9 -9
- zenml/login/pro/utils.py +8 -8
- zenml/login/pro/{tenant → workspace}/__init__.py +1 -1
- zenml/login/pro/{tenant → workspace}/client.py +25 -25
- zenml/login/pro/{tenant → workspace}/models.py +27 -28
- zenml/model/model.py +2 -2
- zenml/model_registries/base_model_registry.py +1 -1
- zenml/models/__init__.py +29 -29
- zenml/models/v2/base/filter.py +1 -1
- zenml/models/v2/base/scoped.py +49 -53
- zenml/models/v2/core/action.py +12 -12
- zenml/models/v2/core/artifact.py +15 -15
- zenml/models/v2/core/artifact_version.py +15 -15
- zenml/models/v2/core/code_repository.py +12 -12
- zenml/models/v2/core/event_source.py +12 -12
- zenml/models/v2/core/model.py +26 -18
- zenml/models/v2/core/model_version.py +15 -15
- zenml/models/v2/core/pipeline.py +15 -15
- 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 +16 -16
- zenml/models/v2/core/project.py +203 -0
- zenml/models/v2/core/run_metadata.py +2 -2
- zenml/models/v2/core/run_template.py +15 -15
- zenml/models/v2/core/schedule.py +12 -12
- zenml/models/v2/core/secret.py +1 -1
- zenml/models/v2/core/service.py +14 -14
- zenml/models/v2/core/step_run.py +13 -13
- zenml/models/v2/core/tag.py +96 -3
- zenml/models/v2/core/trigger.py +13 -13
- zenml/models/v2/core/trigger_execution.py +2 -2
- zenml/models/v2/core/user.py +0 -17
- zenml/models/v2/misc/server_models.py +6 -6
- zenml/models/v2/misc/statistics.py +4 -4
- zenml/orchestrators/cache_utils.py +7 -7
- zenml/orchestrators/input_utils.py +1 -1
- zenml/orchestrators/step_launcher.py +1 -1
- zenml/orchestrators/step_run_utils.py +3 -3
- zenml/orchestrators/utils.py +4 -4
- zenml/pipelines/build_utils.py +2 -2
- zenml/pipelines/pipeline_definition.py +5 -5
- zenml/pipelines/run_utils.py +1 -1
- zenml/service_connectors/service_connector.py +0 -3
- zenml/service_connectors/service_connector_utils.py +0 -1
- zenml/stack/stack.py +0 -1
- zenml/steps/base_step.py +10 -2
- zenml/utils/dashboard_utils.py +1 -1
- zenml/utils/tag_utils.py +0 -12
- zenml/zen_server/cloud_utils.py +3 -3
- zenml/zen_server/feature_gate/endpoint_utils.py +1 -1
- zenml/zen_server/feature_gate/zenml_cloud_feature_gate.py +1 -1
- zenml/zen_server/rbac/endpoint_utils.py +17 -17
- zenml/zen_server/rbac/models.py +47 -22
- zenml/zen_server/rbac/rbac_sql_zen_store.py +3 -3
- zenml/zen_server/rbac/utils.py +23 -25
- zenml/zen_server/rbac/zenml_cloud_rbac.py +7 -74
- zenml/zen_server/routers/artifact_version_endpoints.py +10 -10
- zenml/zen_server/routers/auth_endpoints.py +6 -6
- zenml/zen_server/routers/code_repositories_endpoints.py +12 -14
- zenml/zen_server/routers/model_versions_endpoints.py +13 -15
- zenml/zen_server/routers/models_endpoints.py +7 -9
- zenml/zen_server/routers/pipeline_builds_endpoints.py +14 -16
- zenml/zen_server/routers/pipeline_deployments_endpoints.py +13 -15
- zenml/zen_server/routers/pipelines_endpoints.py +16 -18
- zenml/zen_server/routers/{workspaces_endpoints.py → projects_endpoints.py} +111 -68
- zenml/zen_server/routers/run_metadata_endpoints.py +7 -9
- zenml/zen_server/routers/run_templates_endpoints.py +15 -17
- zenml/zen_server/routers/runs_endpoints.py +12 -14
- zenml/zen_server/routers/schedule_endpoints.py +12 -14
- zenml/zen_server/routers/secrets_endpoints.py +1 -3
- zenml/zen_server/routers/server_endpoints.py +7 -7
- zenml/zen_server/routers/service_connectors_endpoints.py +11 -13
- zenml/zen_server/routers/service_endpoints.py +7 -9
- zenml/zen_server/routers/stack_components_endpoints.py +9 -11
- zenml/zen_server/routers/stacks_endpoints.py +9 -11
- zenml/zen_server/routers/steps_endpoints.py +6 -6
- zenml/zen_server/routers/users_endpoints.py +5 -43
- zenml/zen_server/template_execution/utils.py +4 -4
- zenml/zen_server/utils.py +10 -10
- zenml/zen_server/zen_server_api.py +6 -5
- zenml/zen_stores/base_zen_store.py +38 -42
- zenml/zen_stores/migrations/versions/12eff0206201_rename_workspace_to_project.py +768 -0
- zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +3 -3
- zenml/zen_stores/migrations/versions/cbc6acd71f92_add_workspace_display_name.py +58 -0
- zenml/zen_stores/rest_zen_store.py +55 -63
- zenml/zen_stores/schemas/__init__.py +2 -2
- zenml/zen_stores/schemas/action_schemas.py +9 -9
- zenml/zen_stores/schemas/artifact_schemas.py +15 -17
- zenml/zen_stores/schemas/code_repository_schemas.py +16 -18
- zenml/zen_stores/schemas/event_source_schemas.py +9 -9
- zenml/zen_stores/schemas/model_schemas.py +15 -17
- zenml/zen_stores/schemas/pipeline_build_schemas.py +7 -7
- zenml/zen_stores/schemas/pipeline_deployment_schemas.py +7 -7
- zenml/zen_stores/schemas/pipeline_run_schemas.py +9 -9
- zenml/zen_stores/schemas/pipeline_schemas.py +9 -9
- zenml/zen_stores/schemas/{workspace_schemas.py → project_schemas.py} +47 -41
- zenml/zen_stores/schemas/run_metadata_schemas.py +5 -5
- zenml/zen_stores/schemas/run_template_schemas.py +9 -9
- zenml/zen_stores/schemas/schedule_schema.py +9 -9
- zenml/zen_stores/schemas/service_schemas.py +7 -7
- zenml/zen_stores/schemas/step_run_schemas.py +7 -7
- zenml/zen_stores/schemas/trigger_schemas.py +9 -9
- zenml/zen_stores/schemas/user_schemas.py +0 -12
- zenml/zen_stores/sql_zen_store.py +318 -275
- zenml/zen_stores/zen_store_interface.py +56 -70
- {zenml_nightly-0.75.0.dev20250313.dist-info → zenml_nightly-0.75.0.dev20250315.dist-info}/METADATA +1 -1
- {zenml_nightly-0.75.0.dev20250313.dist-info → zenml_nightly-0.75.0.dev20250315.dist-info}/RECORD +143 -140
- zenml/cli/workspace.py +0 -160
- zenml/models/v2/core/workspace.py +0 -131
- {zenml_nightly-0.75.0.dev20250313.dist-info → zenml_nightly-0.75.0.dev20250315.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.75.0.dev20250313.dist-info → zenml_nightly-0.75.0.dev20250315.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.75.0.dev20250313.dist-info → zenml_nightly-0.75.0.dev20250315.dist-info}/entry_points.txt +0 -0
zenml/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.75.0.
|
1
|
+
0.75.0.dev20250315
|
zenml/analytics/context.py
CHANGED
@@ -118,7 +118,7 @@ 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.
|
121
|
+
self.project_id = None
|
122
122
|
else:
|
123
123
|
from zenml.client import Client
|
124
124
|
|
@@ -129,7 +129,7 @@ class AnalyticsContext:
|
|
129
129
|
active_user.is_service_account
|
130
130
|
)
|
131
131
|
self.external_user_id = active_user.external_user_id
|
132
|
-
self.
|
132
|
+
self.project_id = Client().active_project.id
|
133
133
|
|
134
134
|
# Fetch the `client_id`
|
135
135
|
if self.in_server:
|
@@ -308,8 +308,8 @@ class AnalyticsContext:
|
|
308
308
|
if self.server_metadata:
|
309
309
|
properties.update(self.server_metadata)
|
310
310
|
|
311
|
-
if self.
|
312
|
-
properties.setdefault("
|
311
|
+
if self.project_id:
|
312
|
+
properties.setdefault("project_id", str(self.project_id))
|
313
313
|
|
314
314
|
for k, v in properties.items():
|
315
315
|
if isinstance(v, UUID):
|
zenml/analytics/enums.py
CHANGED
zenml/artifacts/utils.py
CHANGED
@@ -182,7 +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
|
-
|
185
|
+
project=Client().active_project.id,
|
186
186
|
artifact_store_id=artifact_store.id,
|
187
187
|
visualizations=visualizations,
|
188
188
|
has_custom_name=has_custom_name,
|
@@ -349,7 +349,7 @@ def register_artifact(
|
|
349
349
|
uri=folder_or_file_uri,
|
350
350
|
materializer=source_utils.resolve(PreexistingDataMaterializer),
|
351
351
|
data_type=source_utils.resolve(Path),
|
352
|
-
|
352
|
+
project=Client().active_project.id,
|
353
353
|
artifact_store_id=artifact_store.id,
|
354
354
|
has_custom_name=has_custom_name,
|
355
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
@@ -246,7 +246,7 @@ def connect_to_pro_server(
|
|
246
246
|
"""
|
247
247
|
from zenml.login.credentials_store import get_credentials_store
|
248
248
|
from zenml.login.pro.client import ZenMLProClient
|
249
|
-
from zenml.login.pro.
|
249
|
+
from zenml.login.pro.workspace.models import WorkspaceStatus
|
250
250
|
|
251
251
|
pro_api_url = pro_api_url or ZENML_PRO_API_URL
|
252
252
|
pro_api_url = pro_api_url.rstrip("/")
|
@@ -295,7 +295,7 @@ def connect_to_pro_server(
|
|
295
295
|
# We also need to remove all existing API tokens associated with the
|
296
296
|
# target ZenML Pro API, otherwise they will continue to be used after
|
297
297
|
# the re-login flow.
|
298
|
-
credentials_store.clear_all_pro_tokens(
|
298
|
+
credentials_store.clear_all_pro_tokens()
|
299
299
|
try:
|
300
300
|
token = web_login(
|
301
301
|
pro_api_url=pro_api_url,
|
@@ -310,13 +310,14 @@ def connect_to_pro_server(
|
|
310
310
|
"your session expires."
|
311
311
|
)
|
312
312
|
|
313
|
-
|
313
|
+
workspace_id: Optional[str] = None
|
314
314
|
if token.device_metadata:
|
315
|
-
|
315
|
+
# TODO: is this still correct?
|
316
|
+
workspace_id = token.device_metadata.get("tenant_id")
|
316
317
|
|
317
|
-
if
|
318
|
+
if workspace_id is None and pro_server is None:
|
318
319
|
# This is not really supposed to happen, because the implementation
|
319
|
-
# of the web login workflow should always return a
|
320
|
+
# of the web login workflow should always return a workspace ID, but
|
320
321
|
# we're handling it just in case.
|
321
322
|
cli_utils.declare(
|
322
323
|
"A valid server was not selected during the login process. "
|
@@ -328,14 +329,14 @@ def connect_to_pro_server(
|
|
328
329
|
|
329
330
|
# The server selected during the web login process overrides any
|
330
331
|
# server argument passed to the command.
|
331
|
-
server_id = UUID(
|
332
|
+
server_id = UUID(workspace_id)
|
332
333
|
|
333
334
|
client = ZenMLProClient(pro_api_url)
|
334
335
|
|
335
336
|
if server_id:
|
336
|
-
server = client.
|
337
|
+
server = client.workspace.get(server_id)
|
337
338
|
elif server_url:
|
338
|
-
servers = client.
|
339
|
+
servers = client.workspace.list(url=server_url, member_only=True)
|
339
340
|
if not servers:
|
340
341
|
raise AuthorizationException(
|
341
342
|
f"The '{server_url}' URL belongs to a ZenML Pro server, "
|
@@ -345,7 +346,9 @@ def connect_to_pro_server(
|
|
345
346
|
|
346
347
|
server = servers[0]
|
347
348
|
elif server_name:
|
348
|
-
servers = client.
|
349
|
+
servers = client.workspace.list(
|
350
|
+
workspace_name=server_name, member_only=True
|
351
|
+
)
|
349
352
|
if not servers:
|
350
353
|
raise AuthorizationException(
|
351
354
|
f"No ZenML Pro server with the name '{server_name}' exists "
|
@@ -361,15 +364,15 @@ def connect_to_pro_server(
|
|
361
364
|
|
362
365
|
server_id = server.id
|
363
366
|
|
364
|
-
if server.status ==
|
367
|
+
if server.status == WorkspaceStatus.PENDING:
|
365
368
|
with console.status(
|
366
369
|
f"Waiting for your `{server.name}` ZenML Pro server to be set up..."
|
367
370
|
):
|
368
371
|
timeout = 180 # 3 minutes
|
369
372
|
while True:
|
370
373
|
time.sleep(5)
|
371
|
-
server = client.
|
372
|
-
if server.status !=
|
374
|
+
server = client.workspace.get(server_id)
|
375
|
+
if server.status != WorkspaceStatus.PENDING:
|
373
376
|
break
|
374
377
|
timeout -= 5
|
375
378
|
if timeout <= 0:
|
@@ -380,7 +383,7 @@ def connect_to_pro_server(
|
|
380
383
|
f"ZenML Pro dashboard at {server.dashboard_url}."
|
381
384
|
)
|
382
385
|
|
383
|
-
if server.status ==
|
386
|
+
if server.status == WorkspaceStatus.FAILED:
|
384
387
|
cli_utils.error(
|
385
388
|
f"Your `{server.name}` ZenML Pro server is currently in a "
|
386
389
|
"failed state. Please manage the server state by visiting the "
|
@@ -388,7 +391,7 @@ def connect_to_pro_server(
|
|
388
391
|
"your server administrator."
|
389
392
|
)
|
390
393
|
|
391
|
-
elif server.status ==
|
394
|
+
elif server.status == WorkspaceStatus.DEACTIVATED:
|
392
395
|
cli_utils.error(
|
393
396
|
f"Your `{server.name}` ZenML Pro server is currently "
|
394
397
|
"deactivated. Please manage the server state by visiting the "
|
@@ -396,7 +399,7 @@ def connect_to_pro_server(
|
|
396
399
|
"your server administrator."
|
397
400
|
)
|
398
401
|
|
399
|
-
elif server.status ==
|
402
|
+
elif server.status == WorkspaceStatus.AVAILABLE:
|
400
403
|
if not server.url:
|
401
404
|
cli_utils.error(
|
402
405
|
f"The ZenML Pro server '{server.name}' is not currently "
|
@@ -418,7 +421,7 @@ def connect_to_pro_server(
|
|
418
421
|
connect_to_server(server.url, api_key=api_key, pro_server=True)
|
419
422
|
|
420
423
|
# Update the stored server info with more accurate data taken from the
|
421
|
-
# ZenML Pro
|
424
|
+
# ZenML Pro workspace object.
|
422
425
|
credentials_store.update_server_info(server.url, server)
|
423
426
|
|
424
427
|
cli_utils.declare(f"Connected to ZenML Pro server: {server.name}.")
|
@@ -836,7 +839,7 @@ def login(
|
|
836
839
|
pro_api_url=pro_api_url,
|
837
840
|
)
|
838
841
|
|
839
|
-
elif current_non_local_server:
|
842
|
+
elif current_non_local_server and not refresh:
|
840
843
|
# The server argument is not provided, so we default to
|
841
844
|
# re-authenticating to the current non-local server that the client is
|
842
845
|
# connected to.
|
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/server.py
CHANGED
@@ -220,7 +220,7 @@ def status() -> None:
|
|
220
220
|
)
|
221
221
|
if pro_credentials:
|
222
222
|
pro_client = ZenMLProClient(pro_credentials.url)
|
223
|
-
pro_servers = pro_client.
|
223
|
+
pro_servers = pro_client.workspace.list(
|
224
224
|
url=store_cfg.url, member_only=True
|
225
225
|
)
|
226
226
|
if pro_servers:
|
@@ -575,7 +575,7 @@ def server_list(
|
|
575
575
|
from zenml.login.credentials_store import get_credentials_store
|
576
576
|
from zenml.login.pro.client import ZenMLProClient
|
577
577
|
from zenml.login.pro.constants import ZENML_PRO_API_URL
|
578
|
-
from zenml.login.pro.
|
578
|
+
from zenml.login.pro.workspace.models import WorkspaceRead, WorkspaceStatus
|
579
579
|
|
580
580
|
pro_api_url = pro_api_url or ZENML_PRO_API_URL
|
581
581
|
pro_api_url = pro_api_url.rstrip("/")
|
@@ -601,10 +601,10 @@ def server_list(
|
|
601
601
|
# that the user has never connected to (and are therefore not stored in
|
602
602
|
# the credentials store).
|
603
603
|
|
604
|
-
accessible_pro_servers: List[
|
604
|
+
accessible_pro_servers: List[WorkspaceRead] = []
|
605
605
|
try:
|
606
606
|
client = ZenMLProClient(pro_api_url)
|
607
|
-
accessible_pro_servers = client.
|
607
|
+
accessible_pro_servers = client.workspace.list(member_only=not all)
|
608
608
|
except AuthorizationException as e:
|
609
609
|
cli_utils.warning(f"ZenML Pro authorization error: {e}")
|
610
610
|
|
@@ -638,7 +638,7 @@ def server_list(
|
|
638
638
|
accessible_pro_servers = [
|
639
639
|
s
|
640
640
|
for s in accessible_pro_servers
|
641
|
-
if s.status ==
|
641
|
+
if s.status == WorkspaceStatus.AVAILABLE
|
642
642
|
]
|
643
643
|
|
644
644
|
if not accessible_pro_servers:
|
zenml/cli/service_accounts.py
CHANGED
zenml/cli/service_connectors.py
CHANGED
@@ -1902,29 +1902,28 @@ def login_service_connector(
|
|
1902
1902
|
"list-resources",
|
1903
1903
|
help="""List all resources accessible by service connectors.
|
1904
1904
|
|
1905
|
-
This command can be used to list all resources that can be accessed by
|
1906
|
-
|
1905
|
+
This command can be used to list all resources that can be accessed by the
|
1906
|
+
currently registered service connectors. You can filter the list by connector
|
1907
1907
|
type and/or resource type.
|
1908
1908
|
|
1909
1909
|
Use this command to answer questions like:
|
1910
1910
|
|
1911
1911
|
- show a list of all Kubernetes clusters that can be accessed by way of service
|
1912
|
-
connectors
|
1913
|
-
- show a list of all connectors
|
1914
|
-
|
1912
|
+
connectors
|
1913
|
+
- show a list of all connectors along with all the resources they can access or
|
1914
|
+
the error state they are in, if any
|
1915
1915
|
|
1916
|
-
NOTE: since this command exercises all service connectors
|
1917
|
-
may take a while to complete.
|
1916
|
+
NOTE: since this command exercises all service connectors currently registered
|
1917
|
+
with ZenML, it may take a while to complete.
|
1918
1918
|
|
1919
1919
|
Examples:
|
1920
1920
|
|
1921
|
-
- show a list of all S3 buckets that can be accessed by service connectors
|
1922
|
-
configured in your workspace:
|
1921
|
+
- show a list of all S3 buckets that can be accessed by service connectors:
|
1923
1922
|
|
1924
1923
|
$ zenml service-connector list-resources --resource-type s3-bucket
|
1925
1924
|
|
1926
|
-
- show a list of all resources that the AWS connectors
|
1927
|
-
access:
|
1925
|
+
- show a list of all resources that the AWS connectors currently registered
|
1926
|
+
with ZenML can access:
|
1928
1927
|
|
1929
1928
|
$ zenml service-connector list-resources --connector-type aws
|
1930
1929
|
|
@@ -1982,10 +1981,10 @@ def list_service_connector_resources(
|
|
1982
1981
|
if not resource_type and not resource_id:
|
1983
1982
|
cli_utils.warning(
|
1984
1983
|
"Fetching all service connector resources can take a long time, "
|
1985
|
-
"depending on the number of connectors
|
1986
|
-
"
|
1987
|
-
"
|
1988
|
-
"
|
1984
|
+
"depending on the number of connectors currently registered with "
|
1985
|
+
"ZenML. Consider using the '--connector-type', '--resource-type' "
|
1986
|
+
"and '--resource-id' options to narrow down the list of resources "
|
1987
|
+
"to fetch."
|
1989
1988
|
)
|
1990
1989
|
|
1991
1990
|
with console.status(
|
@@ -2030,7 +2029,7 @@ def list_service_connector_resources(
|
|
2030
2029
|
|
2031
2030
|
click.echo(
|
2032
2031
|
f"The {resource_str} can be accessed by"
|
2033
|
-
f"{connector_str} service connectors
|
2032
|
+
f"{connector_str} service connectors:"
|
2034
2033
|
)
|
2035
2034
|
|
2036
2035
|
cli_utils.print_service_connector_resource_table(
|
zenml/cli/stack.py
CHANGED
@@ -503,7 +503,6 @@ def register_stack(
|
|
503
503
|
try:
|
504
504
|
created_stack = client.zen_store.create_stack(
|
505
505
|
stack=StackRequest(
|
506
|
-
workspace=client.active_workspace.id,
|
507
506
|
name=stack_name,
|
508
507
|
components=components,
|
509
508
|
service_connectors=[service_connector]
|
@@ -1913,7 +1912,6 @@ def _get_stack_component_info(
|
|
1913
1912
|
"Enter the subscription ID:"
|
1914
1913
|
)
|
1915
1914
|
config["resource_group"] = Prompt.ask("Enter the resource group:")
|
1916
|
-
config["workspace"] = Prompt.ask("Enter the workspace name:")
|
1917
1915
|
elif flavor == "vertex":
|
1918
1916
|
config["location"] = query_region(
|
1919
1917
|
StackDeploymentProvider.GCP, "Vertex AI job"
|
zenml/cli/stack_components.py
CHANGED
@@ -1424,8 +1424,8 @@ def connect_stack_component_with_service_connector(
|
|
1424
1424
|
|
1425
1425
|
cli_utils.error(
|
1426
1426
|
f"No compatible valid resources were found for the "
|
1427
|
-
f"'{component_model.name}' {display_name}
|
1428
|
-
f"
|
1427
|
+
f"'{component_model.name}' {display_name}. "
|
1428
|
+
f"{additional_info}You can create a new "
|
1429
1429
|
"connector using the 'zenml service-connector register' "
|
1430
1430
|
"command or list the compatible resources using the "
|
1431
1431
|
f"'zenml service-connector list-resources{command_args}' "
|
zenml/cli/utils.py
CHANGED
@@ -2268,12 +2268,12 @@ def print_pipeline_runs_table(
|
|
2268
2268
|
print_table(runs_dicts)
|
2269
2269
|
|
2270
2270
|
|
2271
|
-
def
|
2272
|
-
"""Check if the ZenML Pro
|
2271
|
+
def check_zenml_pro_project_availability() -> None:
|
2272
|
+
"""Check if the ZenML Pro project feature is available."""
|
2273
2273
|
client = Client()
|
2274
2274
|
if not client.zen_store.get_store_info().is_pro_server():
|
2275
2275
|
warning(
|
2276
|
-
"The ZenML
|
2276
|
+
"The ZenML projects feature is available only on ZenML Pro. "
|
2277
2277
|
"Please visit https://zenml.io/pro to learn more."
|
2278
2278
|
)
|
2279
2279
|
|