From 64001cdf63b725ec57804f2632f233d1819d24a9 Mon Sep 17 00:00:00 2001 From: Kenny Hong Date: Tue, 25 Aug 2026 09:44:44 -0700 Subject: [PATCH 1/4] feat(cli): redesign help banner Add selectable animated banner styles and a responsive WinML capsule layout. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- src/winml/modelkit/cli.py | 311 +++++++++++++++++++++++++++++-------- tests/cli/test_help_cli.py | 74 ++++++++- 2 files changed, 317 insertions(+), 68 deletions(-) diff --git a/src/winml/modelkit/cli.py b/src/winml/modelkit/cli.py index 87ff98411..3cfa6e3fc 100644 --- a/src/winml/modelkit/cli.py +++ b/src/winml/modelkit/cli.py @@ -23,6 +23,7 @@ import logging from importlib import import_module from pathlib import Path +from time import sleep from typing import TYPE_CHECKING import click @@ -41,31 +42,39 @@ logger = logging.getLogger(__name__) _COMMANDS_DIR = Path(__file__).parent / "commands" - -# 5-row block-letter art for "WinML CLI". '#' = filled pixel, ' ' = empty. -# All letters use the same █ character so identical shapes (i vs I) look -# consistent regardless of horizontal position. -_LETTER_ART: dict[str, list[str]] = { - "W": ["# #", "# #", "# # #", "## ##", "# #"], - "i": ["###", " # ", " # ", " # ", "###"], - "n": ["# #", "## #", "# # #", "# ##", "# #"], - "M": ["# #", "## ##", "# # #", "# #", "# #"], - "L": ["# ", "# ", "# ", "# ", "#####"], - "C": ["####", "# ", "# ", "# ", "####"], - "I": ["###", " # ", " # ", " # ", "###"], +_BANNER_STYLES = ("capsule", "tiles", "prompt") +_LETTER_ART = { + "W": ("# #", "# #", "# #", "# # #", "# # # #", "## ##", "# #"), + "I": ("#####", " # ", " # ", " # ", " # ", " # ", "#####"), + "N": ("# #", "## #", "# # #", "# # #", "# # #", "# ##", "# #"), + "M": ("# #", "## ##", "# # # #", "# # #", "# #", "# #", "# #"), + "L": ("# ", "# ", "# ", "# ", "# ", "# ", "#######"), +} +_COMPACT_LETTER_ART = { + "W": ("# #", "# #", "# # #", "## ##", "# #"), + "I": ("###", " # ", " # ", " # ", "###"), + "N": ("# #", "## #", "# # #", "# ##", "# #"), + "M": ("# #", "## ##", "# # #", "# #", "# #"), + "L": ("# ", "# ", "# ", "# ", "#####"), } -# Two word segments; rendered with a wider gap between them. -_SEGMENTS: list[list[str]] = [list("WinML"), list("CLI")] -_LETTER_GAP = " " # between letters within a word -_WORD_GAP = " " # between words +_WORDMARK = "WINML" +_LETTER_GAP = " " +# Four 4-column gradient tiles arranged as a Microsoft-style 2x2 mark. +_MARK_ART = ( + "#### ####", + "#### ####", + "#### ####", + " ", + "#### ####", + "#### ####", + "#### ####", +) # Gradient stops (left → right across the full banner width). _GRADIENT: list[tuple[float, tuple[int, int, int]]] = [ - (0.00, (0, 230, 255)), # cyan - (0.25, (0, 100, 255)), # blue - (0.50, (130, 0, 255)), # purple - (0.75, (255, 0, 180)), # pink - (1.00, (255, 80, 80)), # red + (0.00, (45, 145, 255)), + (0.55, (0, 205, 255)), + (1.00, (130, 70, 255)), ] @@ -83,53 +92,209 @@ def _gradient_color(t: float) -> tuple[int, int, int]: return _GRADIENT[-1][1] -def _print_banner(version: str, *, _console: Console | None = None) -> None: - """Print the WinML CLI gradient banner to stderr using Rich.""" - from rich.console import Console # lazy import - keeps startup fast +def _print_banner( + version: str, + style: str = "capsule", + *, + _console: Console | None = None, +) -> None: + """Print the selected WinML CLI banner to stderr using Rich.""" + from rich.console import Console, Group # lazy import - keeps startup fast + from rich.live import Live from rich.text import Text - # Compute total art width across both word segments. - art_w = len(_WORD_GAP) * (len(_SEGMENTS) - 1) - for seg in _SEGMENTS: - art_w += len(_LETTER_GAP) * (len(seg) - 1) - art_w += sum(len(_LETTER_ART[ch][0]) for ch in seg) - bar_w = art_w + 4 margin = " " - con = _console or Console(stderr=True, highlight=False) - con.print() - - for row_idx in range(5): - line = Text(margin) - col = 0 - for seg_idx, seg in enumerate(_SEGMENTS): - if seg_idx > 0: - line.append(_WORD_GAP) - col += len(_WORD_GAP) - for letter_idx, letter in enumerate(seg): - if letter_idx > 0: - line.append(_LETTER_GAP) - col += len(_LETTER_GAP) - for ch in _LETTER_ART[letter][row_idx]: - if ch == "#": - r, g, b = _gradient_color(col / max(art_w - 1, 1)) - line.append("█", style=f"bold rgb({r},{g},{b})") - else: - line.append(" ") - col += 1 - con.print(line) - - con.print() - bar = Text(margin) - for i in range(bar_w): - r, g, b = _gradient_color(i / max(bar_w - 1, 1)) - bar.append("─", style=f"rgb({r},{g},{b})") - con.print(bar) - - con.print() - con.print(f"{margin}[bold rgb(160,100,255)]Windows ML · Model Conversion & Optimization[/]") - con.print(f"{margin}[dim]v{version} · CPU · GPU · NPU[/]") - con.print() + art_rows = tuple( + _LETTER_GAP.join(_LETTER_ART[letter][row] for letter in _WORDMARK) + for row in range(7) + ) + compact_rows = tuple( + _LETTER_GAP.join(_COMPACT_LETTER_ART[letter][row] for letter in _WORDMARK) + for row in range(5) + ) + art_width = len(art_rows[0]) * 2 + compact_width = len(compact_rows[0]) * 2 + mark_width = len(_MARK_ART[0]) * 2 + show_mark = con.width >= compact_width + mark_width + 11 + + def gradient_line(value: str, shimmer_col: int | None = None) -> Text: + line = Text() + for col, char in enumerate(value): + r, g, b = _gradient_color(col / max(len(value) - 1, 1)) + if shimmer_col is not None: + glow = max(0.0, 1.0 - abs(col - shimmer_col) / 5) + r, g, b = ( + round(r + (255 - r) * glow), + round(g + (255 - g) * glow), + round(b + (255 - b) * glow), + ) + line.append(char, style=f"bold rgb({r},{g},{b})") + return line + + def footer(tagline: str, *, include_version: bool = True) -> list[Text]: + lines = [ + Text(), + Text.from_markup(f"{margin}[bold rgb(160,100,255)]Windows ML[/] · {tagline}"), + ] + if include_version: + lines.append(Text.from_markup(f"{margin}[dim]v{version} · CPU · GPU · NPU[/]")) + lines.append(Text()) + return lines + + def wordmark( + shimmer_col: int | None = None, + visible_col: int | None = None, + *, + compact: bool = False, + ) -> list[Text]: + lines = [] + patterns = compact_rows if compact else art_rows + width = compact_width if compact else art_width + shadow_rows = (*patterns, " " * len(patterns[0])) + for row, pattern in enumerate(shadow_rows): + line = Text() + previous = shadow_rows[row - 1] if row else "" + for pixel_col, char in enumerate(pattern): + col = pixel_col * 2 + visible = visible_col is None or col < visible_col + if char == "#" and visible: + r, g, b = _gradient_color(col / max(width - 1, 1)) + if shimmer_col is not None: + glow = max(0.0, 1.0 - abs(col - shimmer_col) / 7) + r, g, b = ( + round(r + (255 - r) * glow), + round(g + (255 - g) * glow), + round(b + (255 - b) * glow), + ) + line.append("██", style=f"bold rgb({r},{g},{b})") + elif row and pixel_col and previous[pixel_col - 1] == "#" and visible: + line.append("▓▓", style="bold rgb(95,45,180)") + else: + line.append(" ") + lines.append(line) + return lines + + def mark() -> list[Text]: + pane_cols = len(_MARK_ART[0]) + lines = [] + for pattern in _MARK_ART: + line = Text() + for col, char in enumerate(pattern): + if char == "#": + r, g, b = _gradient_color(col / max(pane_cols - 1, 1)) + line.append("██", style=f"bold rgb({r},{g},{b})") + else: + line.append(" ") + lines.append(line) + return lines + + def capsule(frame: int | None = None) -> Group: + logo_lines = wordmark(frame, compact=True) + version_text = Text.from_markup(f"[dim]v{version} · CPU · GPU · NPU[/]") + version_line = Text(" " * ((compact_width - len(version_text)) // 2)) + version_line.append_text(version_text) + version_line.append(" " * (compact_width - len(version_line))) + logo_lines.extend([Text(" " * compact_width), version_line]) + mark_lines = mark() if show_mark else [] + content_width = compact_width + (mark_width + 3 if show_mark else 0) + frame_margin = margin if show_mark else "" + + def framed_line(content: Text | None = None) -> Text: + line = gradient_line(f"{frame_margin}┃ ") + if content is None: + line.append(" " * content_width) + else: + line.append_text(content) + line.append(" " * (content_width - len(content))) + line.append(" ┃", style="bold rgb(130,70,255)") + return line + + lines = [ + Text(), + Text.from_markup(f"{margin}[dim]Windows ML CLI[/]"), + gradient_line(f"{frame_margin}┏{'━' * (content_width + 4)}┓", frame), + framed_line(), + ] + for row in range(max(len(logo_lines), len(mark_lines))): + content = Text() + if show_mark: + mark_line = mark_lines[row] if row < len(mark_lines) else Text(" " * mark_width) + content.append_text(mark_line) + content.append(" ") + logo_line = logo_lines[row] if row < len(logo_lines) else Text(" " * compact_width) + content.append_text(logo_line) + lines.append(framed_line(content)) + + lines.extend( + [ + framed_line(), + gradient_line(f"{frame_margin}┗{'━' * (content_width + 4)}┛", frame), + *footer("Model conversion & optimization", include_version=False), + ] + ) + return Group(*lines) + + def tiles(frame: int | None = None) -> Group: + lit_tiles = 4 if frame is None else frame + colors = ("0,230,255", "0,100,255", "130,0,255", "255,0,180") + + def tile(index: int) -> Text: + color = colors[index] if index < lit_tiles else "55,55,65" + return Text("██", style=f"bold rgb({color})") + + lines = [Text()] + for row, logo_line in enumerate(wordmark()): + line = Text(margin) + if row in (1, 2): + indexes = (0, 1) + elif row in (5, 6): + indexes = (2, 3) + else: + indexes = None + if indexes: + line.append_text(tile(indexes[0])) + line.append(" ") + line.append_text(tile(indexes[1])) + else: + line.append(" ") + line.append(" ") + line.append_text(logo_line) + lines.append(line) + lines.extend(footer("Model conversion & optimization")) + return Group(*lines) + + def prompt(frame: int | None = None) -> Group: + lines = [Text(), Text(f"{margin}>_", style="bold bright_cyan"), Text()] + for logo_line in wordmark(visible_col=frame): + line = Text(margin) + line.append_text(logo_line) + lines.append(line) + lines.extend(footer("Build · Optimize · Deploy")) + return Group(*lines) + + if style == "capsule": + render = capsule + frames = range(-4, art_width + 5, 4) + delay = 0.02 + elif style == "tiles": + render = tiles + frames = range(5) + delay = 0.07 + elif style == "prompt": + render = prompt + frames = range(0, art_width + 5, 4) + delay = 0.02 + else: + raise ValueError(f"Unknown banner style: {style}") + + if con.is_terminal and con.color_system is not None and con.width >= art_width + 6: + with Live(render(frames[0]), console=con, auto_refresh=False, transient=True) as live: + for frame in frames[1:]: + live.update(render(frame), refresh=True) + sleep(delay) + + con.print(render()) # Commands that are temporarily disabled from the CLI surface. @@ -284,7 +449,7 @@ def resolve_command( def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: """Emit banner to stderr, then delegate to normal help formatting.""" - _print_banner(__version__) + _print_banner(__version__, ctx.params.get("banner_style", "capsule")) super().format_help(ctx, formatter) def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: @@ -313,6 +478,14 @@ def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> @click.version_option(version=__version__, prog_name="winml") @verbosity_options() @no_color_option() +@click.option( + "--banner-style", + type=click.Choice(_BANNER_STYLES), + default="capsule", + show_default=True, + is_eager=True, + help="Choose the top-level help banner style.", +) @click.option( "--debug", is_flag=True, @@ -321,7 +494,13 @@ def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> hidden=True, ) @click.pass_context -def main(ctx: click.Context, verbose: int, quiet: bool, debug: bool) -> None: +def main( + ctx: click.Context, + verbose: int, + quiet: bool, + banner_style: str, + debug: bool, +) -> None: """WinML CLI - Accelerate Model Deployment on WinML. Universal ONNX export with various WinML execution providers support. diff --git a/tests/cli/test_help_cli.py b/tests/cli/test_help_cli.py index 39dc28d4e..bd1151cb8 100644 --- a/tests/cli/test_help_cli.py +++ b/tests/cli/test_help_cli.py @@ -5,7 +5,7 @@ """CLI surface tests for ``winml`` (no args) and ``winml --help``. Both invocations follow the same contract: exit 0 and render the full -help page, which consists of the gradient banner on stderr and the Click +help page, which consists of the selected banner on stderr and the Click help text (Usage / Options / Commands) on stdout. The tests here pin the *observable output contract* of these two entry points — no mocks, no subcommand execution. @@ -35,16 +35,20 @@ from __future__ import annotations import textwrap +from io import StringIO from typing import TYPE_CHECKING +from unittest.mock import patch import pytest from click.testing import CliRunner, Result +from rich.console import Console from winml.modelkit import __version__ from winml.modelkit.cli import ( _COMMANDS_DIR, _DISABLED_COMMANDS, _parse_click_help, + _print_banner, main, ) @@ -146,6 +150,72 @@ def test_subcommand_help_has_no_banner(self) -> None: assert result.exit_code == 0 assert "Windows ML" not in result.stderr + @pytest.mark.parametrize( + ("style", "marker"), + [ + ("capsule", "┏"), + ("tiles", "██ ██"), + ("prompt", ">_"), + ], + ) + def test_banner_style_can_be_selected(self, style: str, marker: str) -> None: + result = _invoke("--banner-style", style, "--help") + assert result.exit_code == 0 + assert marker in result.stderr + + def test_banner_animation_is_skipped_outside_interactive_terminals(self) -> None: + with patch("winml.modelkit.cli.sleep") as mock_sleep: + _print_banner( + "1.2.3", + _console=Console( + file=StringIO(), + force_terminal=False, + color_system=None, + ), + ) + mock_sleep.assert_not_called() + + @pytest.mark.parametrize("style", ["capsule", "tiles", "prompt"]) + def test_each_banner_style_animates_in_interactive_terminals(self, style: str) -> None: + with patch("winml.modelkit.cli.sleep") as mock_sleep: + _print_banner( + "1.2.3", + style, + _console=Console( + file=StringIO(), + force_terminal=True, + color_system="truecolor", + width=100, + ), + ) + assert mock_sleep.call_count > 1 + + def test_unknown_banner_style_is_rejected(self) -> None: + result = _invoke("--banner-style", "unknown", "--help") + assert result.exit_code != 0 + assert "Invalid value for '--banner-style'" in result.output + + # Each row contains two four-column gradient tiles separated by a gap. + _MARK_SIGNATURE = "████████ ████████" + + def test_capsule_shows_left_mark_on_wide_terminals(self) -> None: + console = Console(file=StringIO(), force_terminal=False, color_system=None, width=90) + _print_banner("1.2.3", "capsule", _console=console) + assert self._MARK_SIGNATURE in console.file.getvalue() + + def test_capsule_hides_left_mark_on_narrow_terminals(self) -> None: + console = Console(file=StringIO(), force_terminal=False, color_system=None, width=80) + _print_banner("1.2.3", "capsule", _console=console) + assert self._MARK_SIGNATURE not in console.file.getvalue() + + def test_capsule_places_version_inside_frame(self) -> None: + console = Console(file=StringIO(), force_terminal=False, color_system=None, width=110) + _print_banner("1.2.3", "capsule", _console=console) + output = console.file.getvalue() + version_line = next(line for line in output.splitlines() if "v1.2.3" in line) + assert version_line.strip().startswith("┃") + assert version_line.strip().endswith("┃") + # =========================================================================== # Commands section @@ -322,7 +392,7 @@ class TestOptionsSection: @pytest.mark.parametrize( "opt", - ["--version", "--verbose", "-v", "--quiet", "-q", "--help", "-h"], + ["--version", "--verbose", "-v", "--quiet", "-q", "--banner-style", "--help", "-h"], ) def test_option_present(self, opt: str) -> None: assert opt in _invoke("--help").output From 88caf7985211905b99adb70613ab5832023c2b3e Mon Sep 17 00:00:00 2001 From: Kenny Hong Date: Wed, 16 Sep 2026 16:49:16 -0700 Subject: [PATCH 2/4] fix(cli): lighten help banner shadow --- src/winml/modelkit/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/winml/modelkit/cli.py b/src/winml/modelkit/cli.py index 3cfa6e3fc..859399978 100644 --- a/src/winml/modelkit/cli.py +++ b/src/winml/modelkit/cli.py @@ -169,7 +169,7 @@ def wordmark( ) line.append("██", style=f"bold rgb({r},{g},{b})") elif row and pixel_col and previous[pixel_col - 1] == "#" and visible: - line.append("▓▓", style="bold rgb(95,45,180)") + line.append("▓▓", style="bold rgb(130,80,210)") else: line.append(" ") lines.append(line) From 91cf545ec4e6a5c7401ee1783396fb0746073c82 Mon Sep 17 00:00:00 2001 From: Qiong Wu Date: Tue, 29 Sep 2026 15:02:07 +0800 Subject: [PATCH 3/4] fix(cli): keep help banners static for reliable terminal scrollback --- src/winml/modelkit/cli.py | 21 ++++----------------- tests/cli/test_help_cli.py | 11 ++++++----- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/winml/modelkit/cli.py b/src/winml/modelkit/cli.py index 859399978..3e1b89284 100644 --- a/src/winml/modelkit/cli.py +++ b/src/winml/modelkit/cli.py @@ -23,7 +23,6 @@ import logging from importlib import import_module from pathlib import Path -from time import sleep from typing import TYPE_CHECKING import click @@ -100,7 +99,6 @@ def _print_banner( ) -> None: """Print the selected WinML CLI banner to stderr using Rich.""" from rich.console import Console, Group # lazy import - keeps startup fast - from rich.live import Live from rich.text import Text margin = " " @@ -138,7 +136,7 @@ def footer(tagline: str, *, include_version: bool = True) -> list[Text]: Text.from_markup(f"{margin}[bold rgb(160,100,255)]Windows ML[/] · {tagline}"), ] if include_version: - lines.append(Text.from_markup(f"{margin}[dim]v{version} · CPU · GPU · NPU[/]")) + lines.append(Text.from_markup(f"{margin}v{version} · CPU · GPU · NPU")) lines.append(Text()) return lines @@ -191,7 +189,7 @@ def mark() -> list[Text]: def capsule(frame: int | None = None) -> Group: logo_lines = wordmark(frame, compact=True) - version_text = Text.from_markup(f"[dim]v{version} · CPU · GPU · NPU[/]") + version_text = Text.from_markup(f"v{version} · CPU · GPU · NPU") version_line = Text(" " * ((compact_width - len(version_text)) // 2)) version_line.append_text(version_text) version_line.append(" " * (compact_width - len(version_line))) @@ -212,7 +210,7 @@ def framed_line(content: Text | None = None) -> Text: lines = [ Text(), - Text.from_markup(f"{margin}[dim]Windows ML CLI[/]"), + Text.from_markup(f"{margin}Windows ML CLI"), gradient_line(f"{frame_margin}┏{'━' * (content_width + 4)}┓", frame), framed_line(), ] @@ -275,25 +273,14 @@ def prompt(frame: int | None = None) -> Group: if style == "capsule": render = capsule - frames = range(-4, art_width + 5, 4) - delay = 0.02 elif style == "tiles": render = tiles - frames = range(5) - delay = 0.07 elif style == "prompt": render = prompt - frames = range(0, art_width + 5, 4) - delay = 0.02 else: raise ValueError(f"Unknown banner style: {style}") - if con.is_terminal and con.color_system is not None and con.width >= art_width + 6: - with Live(render(frames[0]), console=con, auto_refresh=False, transient=True) as live: - for frame in frames[1:]: - live.update(render(frame), refresh=True) - sleep(delay) - + # Static help avoids stale animation frames in terminal scrollback. con.print(render()) diff --git a/tests/cli/test_help_cli.py b/tests/cli/test_help_cli.py index bd1151cb8..b4c03aa92 100644 --- a/tests/cli/test_help_cli.py +++ b/tests/cli/test_help_cli.py @@ -164,7 +164,7 @@ def test_banner_style_can_be_selected(self, style: str, marker: str) -> None: assert marker in result.stderr def test_banner_animation_is_skipped_outside_interactive_terminals(self) -> None: - with patch("winml.modelkit.cli.sleep") as mock_sleep: + with patch("time.sleep") as mock_sleep: _print_banner( "1.2.3", _console=Console( @@ -176,8 +176,9 @@ def test_banner_animation_is_skipped_outside_interactive_terminals(self) -> None mock_sleep.assert_not_called() @pytest.mark.parametrize("style", ["capsule", "tiles", "prompt"]) - def test_each_banner_style_animates_in_interactive_terminals(self, style: str) -> None: - with patch("winml.modelkit.cli.sleep") as mock_sleep: + @pytest.mark.parametrize("width", [80, 81, 82, 100]) + def test_interactive_banner_is_static(self, style: str, width: int) -> None: + with patch("time.sleep") as mock_sleep: _print_banner( "1.2.3", style, @@ -185,10 +186,10 @@ def test_each_banner_style_animates_in_interactive_terminals(self, style: str) - file=StringIO(), force_terminal=True, color_system="truecolor", - width=100, + width=width, ), ) - assert mock_sleep.call_count > 1 + mock_sleep.assert_not_called() def test_unknown_banner_style_is_rejected(self) -> None: result = _invoke("--banner-style", "unknown", "--help") From 17b71f24ea54fab03e95ff1eca06186076aa9875 Mon Sep 17 00:00:00 2001 From: Qiong Wu Date: Tue, 29 Sep 2026 15:37:59 +0800 Subject: [PATCH 4/4] refactor(cli): keep only the static capsule help banner --- src/winml/modelkit/cli.py | 117 +++++-------------------------------- tests/cli/test_help_cli.py | 29 +++------ 2 files changed, 20 insertions(+), 126 deletions(-) diff --git a/src/winml/modelkit/cli.py b/src/winml/modelkit/cli.py index 3e1b89284..86695a456 100644 --- a/src/winml/modelkit/cli.py +++ b/src/winml/modelkit/cli.py @@ -41,14 +41,6 @@ logger = logging.getLogger(__name__) _COMMANDS_DIR = Path(__file__).parent / "commands" -_BANNER_STYLES = ("capsule", "tiles", "prompt") -_LETTER_ART = { - "W": ("# #", "# #", "# #", "# # #", "# # # #", "## ##", "# #"), - "I": ("#####", " # ", " # ", " # ", " # ", " # ", "#####"), - "N": ("# #", "## #", "# # #", "# # #", "# # #", "# ##", "# #"), - "M": ("# #", "## ##", "# # # #", "# # #", "# #", "# #", "# #"), - "L": ("# ", "# ", "# ", "# ", "# ", "# ", "#######"), -} _COMPACT_LETTER_ART = { "W": ("# #", "# #", "# # #", "## ##", "# #"), "I": ("###", " # ", " # ", " # ", "###"), @@ -93,40 +85,27 @@ def _gradient_color(t: float) -> tuple[int, int, int]: def _print_banner( version: str, - style: str = "capsule", *, _console: Console | None = None, ) -> None: - """Print the selected WinML CLI banner to stderr using Rich.""" + """Print the capsule WinML CLI banner to stderr using Rich.""" from rich.console import Console, Group # lazy import - keeps startup fast from rich.text import Text margin = " " con = _console or Console(stderr=True, highlight=False) - art_rows = tuple( - _LETTER_GAP.join(_LETTER_ART[letter][row] for letter in _WORDMARK) - for row in range(7) - ) compact_rows = tuple( _LETTER_GAP.join(_COMPACT_LETTER_ART[letter][row] for letter in _WORDMARK) for row in range(5) ) - art_width = len(art_rows[0]) * 2 compact_width = len(compact_rows[0]) * 2 mark_width = len(_MARK_ART[0]) * 2 show_mark = con.width >= compact_width + mark_width + 11 - def gradient_line(value: str, shimmer_col: int | None = None) -> Text: + def gradient_line(value: str) -> Text: line = Text() for col, char in enumerate(value): r, g, b = _gradient_color(col / max(len(value) - 1, 1)) - if shimmer_col is not None: - glow = max(0.0, 1.0 - abs(col - shimmer_col) / 5) - r, g, b = ( - round(r + (255 - r) * glow), - round(g + (255 - g) * glow), - round(b + (255 - b) * glow), - ) line.append(char, style=f"bold rgb({r},{g},{b})") return line @@ -140,33 +119,20 @@ def footer(tagline: str, *, include_version: bool = True) -> list[Text]: lines.append(Text()) return lines - def wordmark( - shimmer_col: int | None = None, - visible_col: int | None = None, - *, - compact: bool = False, - ) -> list[Text]: + def wordmark() -> list[Text]: lines = [] - patterns = compact_rows if compact else art_rows - width = compact_width if compact else art_width + patterns = compact_rows + width = compact_width shadow_rows = (*patterns, " " * len(patterns[0])) for row, pattern in enumerate(shadow_rows): line = Text() previous = shadow_rows[row - 1] if row else "" for pixel_col, char in enumerate(pattern): col = pixel_col * 2 - visible = visible_col is None or col < visible_col - if char == "#" and visible: + if char == "#": r, g, b = _gradient_color(col / max(width - 1, 1)) - if shimmer_col is not None: - glow = max(0.0, 1.0 - abs(col - shimmer_col) / 7) - r, g, b = ( - round(r + (255 - r) * glow), - round(g + (255 - g) * glow), - round(b + (255 - b) * glow), - ) line.append("██", style=f"bold rgb({r},{g},{b})") - elif row and pixel_col and previous[pixel_col - 1] == "#" and visible: + elif row and pixel_col and previous[pixel_col - 1] == "#": line.append("▓▓", style="bold rgb(130,80,210)") else: line.append(" ") @@ -187,8 +153,8 @@ def mark() -> list[Text]: lines.append(line) return lines - def capsule(frame: int | None = None) -> Group: - logo_lines = wordmark(frame, compact=True) + def capsule() -> Group: + logo_lines = wordmark() version_text = Text.from_markup(f"v{version} · CPU · GPU · NPU") version_line = Text(" " * ((compact_width - len(version_text)) // 2)) version_line.append_text(version_text) @@ -211,7 +177,7 @@ def framed_line(content: Text | None = None) -> Text: lines = [ Text(), Text.from_markup(f"{margin}Windows ML CLI"), - gradient_line(f"{frame_margin}┏{'━' * (content_width + 4)}┓", frame), + gradient_line(f"{frame_margin}┏{'━' * (content_width + 4)}┓"), framed_line(), ] for row in range(max(len(logo_lines), len(mark_lines))): @@ -227,61 +193,13 @@ def framed_line(content: Text | None = None) -> Text: lines.extend( [ framed_line(), - gradient_line(f"{frame_margin}┗{'━' * (content_width + 4)}┛", frame), + gradient_line(f"{frame_margin}┗{'━' * (content_width + 4)}┛"), *footer("Model conversion & optimization", include_version=False), ] ) return Group(*lines) - def tiles(frame: int | None = None) -> Group: - lit_tiles = 4 if frame is None else frame - colors = ("0,230,255", "0,100,255", "130,0,255", "255,0,180") - - def tile(index: int) -> Text: - color = colors[index] if index < lit_tiles else "55,55,65" - return Text("██", style=f"bold rgb({color})") - - lines = [Text()] - for row, logo_line in enumerate(wordmark()): - line = Text(margin) - if row in (1, 2): - indexes = (0, 1) - elif row in (5, 6): - indexes = (2, 3) - else: - indexes = None - if indexes: - line.append_text(tile(indexes[0])) - line.append(" ") - line.append_text(tile(indexes[1])) - else: - line.append(" ") - line.append(" ") - line.append_text(logo_line) - lines.append(line) - lines.extend(footer("Model conversion & optimization")) - return Group(*lines) - - def prompt(frame: int | None = None) -> Group: - lines = [Text(), Text(f"{margin}>_", style="bold bright_cyan"), Text()] - for logo_line in wordmark(visible_col=frame): - line = Text(margin) - line.append_text(logo_line) - lines.append(line) - lines.extend(footer("Build · Optimize · Deploy")) - return Group(*lines) - - if style == "capsule": - render = capsule - elif style == "tiles": - render = tiles - elif style == "prompt": - render = prompt - else: - raise ValueError(f"Unknown banner style: {style}") - - # Static help avoids stale animation frames in terminal scrollback. - con.print(render()) + con.print(capsule()) # Commands that are temporarily disabled from the CLI surface. @@ -436,7 +354,7 @@ def resolve_command( def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: """Emit banner to stderr, then delegate to normal help formatting.""" - _print_banner(__version__, ctx.params.get("banner_style", "capsule")) + _print_banner(__version__) super().format_help(ctx, formatter) def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: @@ -465,14 +383,6 @@ def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> @click.version_option(version=__version__, prog_name="winml") @verbosity_options() @no_color_option() -@click.option( - "--banner-style", - type=click.Choice(_BANNER_STYLES), - default="capsule", - show_default=True, - is_eager=True, - help="Choose the top-level help banner style.", -) @click.option( "--debug", is_flag=True, @@ -485,7 +395,6 @@ def main( ctx: click.Context, verbose: int, quiet: bool, - banner_style: str, debug: bool, ) -> None: """WinML CLI - Accelerate Model Deployment on WinML. diff --git a/tests/cli/test_help_cli.py b/tests/cli/test_help_cli.py index b4c03aa92..5a9ba1309 100644 --- a/tests/cli/test_help_cli.py +++ b/tests/cli/test_help_cli.py @@ -150,19 +150,6 @@ def test_subcommand_help_has_no_banner(self) -> None: assert result.exit_code == 0 assert "Windows ML" not in result.stderr - @pytest.mark.parametrize( - ("style", "marker"), - [ - ("capsule", "┏"), - ("tiles", "██ ██"), - ("prompt", ">_"), - ], - ) - def test_banner_style_can_be_selected(self, style: str, marker: str) -> None: - result = _invoke("--banner-style", style, "--help") - assert result.exit_code == 0 - assert marker in result.stderr - def test_banner_animation_is_skipped_outside_interactive_terminals(self) -> None: with patch("time.sleep") as mock_sleep: _print_banner( @@ -175,13 +162,11 @@ def test_banner_animation_is_skipped_outside_interactive_terminals(self) -> None ) mock_sleep.assert_not_called() - @pytest.mark.parametrize("style", ["capsule", "tiles", "prompt"]) @pytest.mark.parametrize("width", [80, 81, 82, 100]) - def test_interactive_banner_is_static(self, style: str, width: int) -> None: + def test_interactive_banner_is_static(self, width: int) -> None: with patch("time.sleep") as mock_sleep: _print_banner( "1.2.3", - style, _console=Console( file=StringIO(), force_terminal=True, @@ -191,27 +176,27 @@ def test_interactive_banner_is_static(self, style: str, width: int) -> None: ) mock_sleep.assert_not_called() - def test_unknown_banner_style_is_rejected(self) -> None: + def test_removed_banner_style_is_rejected(self) -> None: result = _invoke("--banner-style", "unknown", "--help") assert result.exit_code != 0 - assert "Invalid value for '--banner-style'" in result.output + assert "No such option" in result.output # Each row contains two four-column gradient tiles separated by a gap. _MARK_SIGNATURE = "████████ ████████" def test_capsule_shows_left_mark_on_wide_terminals(self) -> None: console = Console(file=StringIO(), force_terminal=False, color_system=None, width=90) - _print_banner("1.2.3", "capsule", _console=console) + _print_banner("1.2.3", _console=console) assert self._MARK_SIGNATURE in console.file.getvalue() def test_capsule_hides_left_mark_on_narrow_terminals(self) -> None: console = Console(file=StringIO(), force_terminal=False, color_system=None, width=80) - _print_banner("1.2.3", "capsule", _console=console) + _print_banner("1.2.3", _console=console) assert self._MARK_SIGNATURE not in console.file.getvalue() def test_capsule_places_version_inside_frame(self) -> None: console = Console(file=StringIO(), force_terminal=False, color_system=None, width=110) - _print_banner("1.2.3", "capsule", _console=console) + _print_banner("1.2.3", _console=console) output = console.file.getvalue() version_line = next(line for line in output.splitlines() if "v1.2.3" in line) assert version_line.strip().startswith("┃") @@ -393,7 +378,7 @@ class TestOptionsSection: @pytest.mark.parametrize( "opt", - ["--version", "--verbose", "-v", "--quiet", "-q", "--banner-style", "--help", "-h"], + ["--version", "--verbose", "-v", "--quiet", "-q", "--help", "-h"], ) def test_option_present(self, opt: str) -> None: assert opt in _invoke("--help").output