Skip to content

Commit 7fef101

Browse files
authored
feat: beautify show cli command with colorful structured output (#404)
* feat: enhance flow string representation with structured output * feat: improve show cli command with colorful structured output * fix: improve error handling in string representation of Flow * refactor: clean up flow format helper logic * feat: implement color highlights using rich for flow formatting * refactor: make reusable helpers in flow format method
1 parent d107a00 commit 7fef101

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description = "With CocoIndex, users declare the transformation, CocoIndex creat
99
authors = [{ name = "CocoIndex", email = "[email protected]" }]
1010
readme = "README.md"
1111
requires-python = ">=3.11"
12-
dependencies = ["sentence-transformers>=3.3.1", "click>=8.1.8"]
12+
dependencies = ["sentence-transformers>=3.3.1", "click>=8.1.8", "rich>=14.0.0"]
1313
license = "Apache-2.0"
1414
urls = { Homepage = "https://cocoindex.io/" }
1515

python/cocoindex/cli.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import click
33
import datetime
4+
from rich.console import Console
45

56
from . import flow, lib
67
from .setup import sync_setup, drop_setup, flow_names_with_setup, apply_setup_changes
@@ -52,11 +53,14 @@ def ls(show_all: bool):
5253

5354
@cli.command()
5455
@click.argument("flow_name", type=str, required=False)
55-
def show(flow_name: str | None):
56+
@click.option("--color/--no-color", default=True)
57+
def show(flow_name: str | None, color: bool):
5658
"""
57-
Show the flow spec.
59+
Show the flow spec in a readable format with colored output.
5860
"""
59-
click.echo(str(_flow_by_name(flow_name)))
61+
flow = _flow_by_name(flow_name)
62+
console = Console(no_color=not color)
63+
console.print(flow._render_text())
6064

6165
@cli.command()
6266
def setup():

python/cocoindex/flow.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
import re
99
import inspect
1010
import datetime
11+
import json
1112

1213
from typing import Any, Callable, Sequence, TypeVar
1314
from threading import Lock
1415
from enum import Enum
1516
from dataclasses import dataclass
17+
from rich.text import Text
18+
from rich.console import Console
1619

1720
from . import _engine
1821
from . import index
@@ -451,8 +454,58 @@ def _lazy_engine_flow() -> _engine.Flow:
451454
return engine_flow
452455
self._lazy_engine_flow = _lazy_engine_flow
453456

457+
def _format_flow(self, flow_dict: dict) -> Text:
458+
output = Text()
459+
460+
def add_line(content, indent=0, style=None, end="\n"):
461+
output.append(" " * indent)
462+
output.append(content, style=style)
463+
output.append(end)
464+
465+
def format_key_value(key, value, indent):
466+
if isinstance(value, (dict, list)):
467+
add_line(f"- {key}:", indent, style="green")
468+
format_data(value, indent + 2)
469+
else:
470+
add_line(f"- {key}:", indent, style="green", end="")
471+
add_line(f" {value}", style="yellow")
472+
473+
def format_data(data, indent=0):
474+
if isinstance(data, dict):
475+
for key, value in data.items():
476+
format_key_value(key, value, indent)
477+
elif isinstance(data, list):
478+
for i, item in enumerate(data):
479+
format_key_value(f"[{i}]", item, indent)
480+
else:
481+
add_line(str(data), indent, style="yellow")
482+
483+
# Header
484+
flow_name = flow_dict.get("name", "Unnamed")
485+
add_line(f"Flow: {flow_name}", style="bold cyan")
486+
487+
# Section
488+
for section_title, section_key in [
489+
("Sources:", "import_ops"),
490+
("Processing:", "reactive_ops"),
491+
("Targets:", "export_ops"),
492+
]:
493+
add_line("")
494+
add_line(section_title, style="bold cyan")
495+
format_data(flow_dict.get(section_key, []), indent=0)
496+
497+
return output
498+
499+
def _render_text(self) -> Text:
500+
flow_spec_str = str(self._lazy_engine_flow())
501+
try:
502+
flow_dict = json.loads(flow_spec_str)
503+
return self._format_flow(flow_dict)
504+
except json.JSONDecodeError:
505+
return Text(flow_spec_str)
506+
454507
def __str__(self):
455-
return str(self._lazy_engine_flow())
508+
return str(self._render_text())
456509

457510
def __repr__(self):
458511
return repr(self._lazy_engine_flow())

0 commit comments

Comments
 (0)