Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f5d863b
Improving the list outputs and adding new formats
znegrin Jul 30, 2025
78af737
Merge develop into feat/improved-cli-tables
znegrin Jul 30, 2025
4ecfdfc
Fix type annotation for overflow parameter in table_utils
znegrin Jul 30, 2025
6403d92
Update service connector table to bring back previous data
znegrin Aug 1, 2025
4514cfc
Merge branch 'develop' into feat/improved-cli-tables
znegrin Aug 1, 2025
8f361b6
Fix docstring issues in CLI table functions
znegrin Aug 1, 2025
cd2b987
Fix remaining docstring issues in CLI functions
znegrin Aug 1, 2025
6604636
Fix missing parameter and return documentation in CLI docstrings
znegrin Aug 1, 2025
cea4272
Fix mypy type annotation issues across all CLI files
znegrin Aug 1, 2025
ebebd80
Apply code formatting to CLI files
znegrin Aug 1, 2025
038940d
Merge branch 'develop' into feat/improved-cli-tables
bcdurak Aug 4, 2025
7bed4be
fix one test
bcdurak Aug 4, 2025
bf13b44
removed unused import
bcdurak Aug 6, 2025
fbeef0c
new module for the CLI
bcdurak Aug 6, 2025
15d2247
merged develop
bcdurak Aug 6, 2025
783304d
formatting
bcdurak Aug 6, 2025
a0b63dd
Merge branch 'develop' into feat/improved-cli-tables
bcdurak Aug 6, 2025
a36632a
new changes
bcdurak Aug 7, 2025
ff9acec
removing warning suppresion
bcdurak Aug 7, 2025
6fb4e3c
Merge branch 'develop' into feat/improved-cli-tables
bcdurak Aug 7, 2025
79e75a7
checkpoint
bcdurak Aug 7, 2025
4eea33f
some other fixes
bcdurak Aug 7, 2025
8fa6b5a
merged
bcdurak Aug 7, 2025
c383943
docstring changes
bcdurak Aug 27, 2025
783f8eb
merged develop, resolved conflicts
bcdurak Aug 29, 2025
81045c5
removed unused stuff
bcdurak Aug 29, 2025
277e774
new formatting
bcdurak Sep 1, 2025
932d61d
docstrings and linting
bcdurak Sep 1, 2025
6ef6bc7
Merge branch 'develop' into feat/improved-cli-tables
bcdurak Sep 1, 2025
39a7c43
formatting linting
bcdurak Sep 1, 2025
06e2ad5
formatting
bcdurak Sep 1, 2025
494df98
add id to pipeline runs
bcdurak Sep 1, 2025
ffe3bf1
some more formatting
bcdurak Sep 1, 2025
1ea0f32
removed unneccessary tests
bcdurak Sep 1, 2025
0341fd5
Merge branch 'develop' into feat/improved-cli-tables
bcdurak Sep 11, 2025
44a7b1c
fixed merge conflicts
bcdurak Sep 17, 2025
99399c0
some checkpoint
bcdurak Sep 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 77 additions & 24 deletions src/zenml/cli/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@

from zenml.cli import utils as cli_utils
from zenml.cli.cli import TagGroup, cli
from zenml.cli.utils import (
enhanced_list_options,
format_date_for_table,
prepare_list_data,
)
from zenml.client import Client
from zenml.console import console
from zenml.enums import CliCategories
from zenml.logger import get_logger
from zenml.models import ArtifactFilter, ArtifactVersionFilter
Expand All @@ -35,25 +41,39 @@ def artifact() -> None:
"""Commands for interacting with artifacts."""


@cli_utils.list_options(ArtifactFilter)
@enhanced_list_options(ArtifactFilter)
@artifact.command("list", help="List all artifacts.")
def list_artifacts(**kwargs: Any) -> None:
"""List all artifacts.

Args:
**kwargs: Keyword arguments to filter artifacts by.
"""
artifacts = Client().list_artifacts(**kwargs)
# Extract table options from kwargs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh really

table_kwargs = cli_utils.extract_table_options(kwargs)

with console.status("Listing artifacts..."):
artifacts = Client().list_artifacts(**kwargs)

if not artifacts:
cli_utils.declare("No artifacts found.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there are no entities found but the requested output format is JSON, I would expect either Null or []/{} written to stdout. WDYT?

return

to_print = []
for artifact in artifacts:
to_print.append(_artifact_to_print(artifact))
# Prepare data based on output format
output_format = (
table_kwargs.get("output") or cli_utils.get_default_output_format()
)
artifact_data = []

# Use centralized data preparation
artifact_data = prepare_list_data(
artifacts, output_format, _artifact_to_print
)

cli_utils.print_table(to_print)
# Handle table output with enhanced system and pagination
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please remove all those garbage AI comments from this PR. I haven't found a single useful one yet.

cli_utils.handle_table_output(
artifact_data, page=artifacts, **table_kwargs
)


@artifact.command("update", help="Update an artifact.")
Expand Down Expand Up @@ -115,25 +135,39 @@ def version() -> None:
"""Commands for interacting with artifact versions."""


@cli_utils.list_options(ArtifactVersionFilter)
@enhanced_list_options(ArtifactVersionFilter)
@version.command("list", help="List all artifact versions.")
def list_artifact_versions(**kwargs: Any) -> None:
"""List all artifact versions.

Args:
**kwargs: Keyword arguments to filter artifact versions by.
"""
artifact_versions = Client().list_artifact_versions(**kwargs)
# Extract table options from kwargs
table_kwargs = cli_utils.extract_table_options(kwargs)

with console.status("Listing artifact versions..."):
artifact_versions = Client().list_artifact_versions(**kwargs)

if not artifact_versions:
cli_utils.declare("No artifact versions found.")
return

to_print = []
for artifact_version in artifact_versions:
to_print.append(_artifact_version_to_print(artifact_version))
# Prepare data based on output format
output_format = (
table_kwargs.get("output") or cli_utils.get_default_output_format()
)
artifact_version_data = []

# Use centralized data preparation
artifact_version_data = prepare_list_data(
artifact_versions, output_format, _artifact_version_to_print
)

cli_utils.print_table(to_print)
# Handle table output with enhanced system and pagination
cli_utils.handle_table_output(
artifact_version_data, page=artifact_versions, **table_kwargs
)


@version.command("update", help="Update an artifact version.")
Expand Down Expand Up @@ -296,26 +330,45 @@ def prune_artifacts(
cli_utils.declare("All unused artifacts and artifact versions deleted.")


def _artifact_to_print(artifact: ArtifactResponse) -> Dict[str, Any]:
"""Convert an artifact response to a dictionary suitable for table display.

For table output, keep it compact with essential artifact information.
Full details are available in JSON/YAML output formats.
"""
return {
"name": artifact.name,
"tags": [t.name for t in artifact.tags] if artifact.tags else [],
"created": format_date_for_table(artifact.created),
}


def _artifact_to_print_full(artifact: ArtifactResponse) -> Dict[str, Any]:
"""Convert artifact response to complete dictionary for JSON/YAML."""
return artifact.model_dump(mode="json")


def _artifact_version_to_print(
artifact_version: ArtifactVersionResponse,
) -> Dict[str, Any]:
"""Convert artifact version response to dictionary for table display.

For table output, keep it compact with essential version information.
Full details are available in JSON/YAML output formats.
"""
return {
"id": artifact_version.id,
"name": artifact_version.artifact.name,
"version": artifact_version.version,
"uri": artifact_version.uri,
"type": artifact_version.type,
"materializer": artifact_version.materializer,
"data_type": artifact_version.data_type,
"tags": [t.name for t in artifact_version.tags],
"tags": [t.name for t in artifact_version.tags]
if artifact_version.tags
else [],
"created": format_date_for_table(artifact_version.created),
}


def _artifact_to_print(
artifact_version: ArtifactResponse,
def _artifact_version_to_print_full(
artifact_version: ArtifactVersionResponse,
) -> Dict[str, Any]:
return {
"id": artifact_version.id,
"name": artifact_version.name,
"tags": [t.name for t in artifact_version.tags],
}
"""Convert artifact version response to complete dictionary for JSON/YAML."""
return artifact_version.model_dump(mode="json")
46 changes: 39 additions & 7 deletions src/zenml/cli/authorized_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
# permissions and limitations under the License.
"""CLI functionality to interact with authorized devices."""

from typing import Any
from typing import Any, Dict

import click

from zenml.cli import utils as cli_utils
from zenml.cli.cli import TagGroup, cli
from zenml.cli.utils import list_options
from zenml.cli.utils import (
format_date_for_table,
list_options,
prepare_list_data,
)
from zenml.client import Client
from zenml.console import console
from zenml.enums import CliCategories
Expand All @@ -29,6 +33,19 @@
logger = get_logger(__name__)


def _authorized_device_to_print(device: Any) -> Dict[str, Any]:
"""Convert an authorized device response to a dictionary for table display."""
return {
"status": device.status.value
if hasattr(device.status, "value")
else str(device.status),
"ip_address": device.ip_address or "",
"hostname": device.hostname or "",
"os": device.os or "",
"created": format_date_for_table(device.created),
}


@cli.group(cls=TagGroup, tag=CliCategories.MANAGEMENT_TOOLS)
def authorized_device() -> None:
"""Interact with authorized devices."""
Expand Down Expand Up @@ -66,16 +83,31 @@ def list_authorized_devices(**kwargs: Any) -> None:
Args:
**kwargs: Keyword arguments to filter authorized devices.
"""
with console.status("Listing authorized devices...\n"):
# Extract table options from kwargs
table_kwargs = cli_utils.extract_table_options(kwargs)

with console.status("Listing authorized devices..."):
devices = Client().list_authorized_devices(**kwargs)

if not devices.items:
cli_utils.declare("No authorized devices found for this filter.")
cli_utils.declare("No authorized devices found.")
return

cli_utils.print_pydantic_models(
devices,
columns=["id", "status", "ip_address", "hostname", "os"],
# Prepare data based on output format
output_format = (
table_kwargs.get("output") or cli_utils.get_default_output_format()
)

# Use centralized data preparation
device_data = prepare_list_data(
devices.items, output_format, _authorized_device_to_print
)

# Handle table output with enhanced system and pagination
cli_utils.handle_table_output(
data=device_data,
page=devices,
**table_kwargs,
)


Expand Down
52 changes: 44 additions & 8 deletions src/zenml/cli/code_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@
# permissions and limitations under the License.
"""CLI functionality to interact with code repositories."""

from typing import Any, List, Optional
from typing import Any, Dict, List, Optional

import click

from zenml.cli import utils as cli_utils
from zenml.cli.cli import TagGroup, cli
from zenml.cli.utils import list_options
from zenml.cli.utils import (
enhanced_list_options,
format_date_for_table,
prepare_list_data,
)
from zenml.client import Client
from zenml.code_repositories import BaseCodeRepository
from zenml.config.source import Source
Expand All @@ -32,6 +36,22 @@
logger = get_logger(__name__)


def _code_repository_to_print(repo: Any) -> Dict[str, Any]:
"""Convert a code repository response to a dictionary for table display."""
return {
"name": repo.name,
"type": repo.source.type
if hasattr(repo, "source") and repo.source
else "Unknown",
"url": repo.source.url
if hasattr(repo, "source")
and repo.source
and hasattr(repo.source, "url")
else "",
"created": format_date_for_table(repo.created),
}


@cli.group(cls=TagGroup, tag=CliCategories.MANAGEMENT_TOOLS)
def code_repository() -> None:
"""Interact with code repositories."""
Expand Down Expand Up @@ -189,23 +209,39 @@ def describe_code_repository(name_id_or_prefix: str) -> None:


@code_repository.command("list", help="List all connected code repositories.")
@list_options(CodeRepositoryFilter)
@enhanced_list_options(CodeRepositoryFilter)
def list_code_repositories(**kwargs: Any) -> None:
"""List all connected code repositories.

Args:
**kwargs: Keyword arguments to filter code repositories.
"""
with console.status("Listing code repositories...\n"):
# Extract table options from kwargs
table_kwargs = cli_utils.extract_table_options(kwargs)

with console.status("Listing code repositories..."):
repos = Client().list_code_repositories(**kwargs)

if not repos.items:
cli_utils.declare("No code repositories found for this filter.")
cli_utils.declare("No code repositories found.")
return

cli_utils.print_pydantic_models(
repos,
exclude_columns=["created", "updated", "user", "project"],
# Prepare data based on output format
output_format = (
table_kwargs.get("output") or cli_utils.get_default_output_format()
)
repo_data = []

# Use centralized data preparation
repo_data = prepare_list_data(
repos.items, output_format, _code_repository_to_print
)

# Handle table output with enhanced system
cli_utils.handle_table_output(
data=repo_data,
page=repos,
**table_kwargs,
)


Expand Down
Loading
Loading