diff --git a/.github/workflows/test_cli.yaml b/.github/workflows/test_cli.yaml index b5f6c863547..3c0e1546efa 100644 --- a/.github/workflows/test_cli.yaml +++ b/.github/workflows/test_cli.yaml @@ -134,7 +134,7 @@ jobs: - name: Test CLI shell: bash run: | - pytest -v tests/_cli/test_cli* + pytest -v tests/_cli/test_cli* --maxfail=2 test_examples: needs: [changes, build_wheel] diff --git a/marimo/_cli/print.py b/marimo/_cli/print.py index d093dcdfbd5..20e8ea9d3c6 100644 --- a/marimo/_cli/print.py +++ b/marimo/_cli/print.py @@ -2,39 +2,77 @@ from __future__ import annotations -from typing import Any +import os +import sys +from typing import Any, cast from marimo._config.settings import GLOBAL_SETTINGS -# Print helpers + +# Check if we're on Windows and if ANSI colors are supported +def _supports_color() -> bool: + if os.environ.get("NO_COLOR") == "1": + return False + + # Windows 10 build 14931+ supports ANSI color codes + if os.name == "nt": + try: + import ctypes + + kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined] + # Get Windows version + major = sys.getwindowsversion().major # type: ignore[attr-defined] + build = sys.getwindowsversion().build # type: ignore[attr-defined] + + # Check if Windows 10+ and if VIRTUAL_TERMINAL_PROCESSING is enabled + return cast( + bool, + major >= 10 + and build >= 14931 + and kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7), # type: ignore[attr-defined] + ) + except Exception: + return False + return hasattr(sys.stdout, "isatty") and sys.stdout.isatty() + + +_USE_COLOR = _supports_color() def bold(text: str) -> str: - return "\033[1m" + text + "\033[0m" + return "\033[1m" + text + "\033[0m" if _USE_COLOR else text def green(text: str, bold: bool = False) -> str: + if not _USE_COLOR: + return text prefix = "\033[32m" if not bold else "\033[1;32m" return prefix + text + "\033[0m" def yellow(text: str, bold: bool = False) -> str: + if not _USE_COLOR: + return text prefix = "\033[33m" if not bold else "\033[1;33m" return prefix + text + "\033[0m" def orange(text: str, bold: bool = False) -> str: + if not _USE_COLOR: + return text prefix = "\033[33m" if not bold else "\033[1;33m" return prefix + text + "\033[0m" def red(text: str, bold: bool = False) -> str: + if not _USE_COLOR: + return text prefix = "\033[31m" if not bold else "\033[1;31m" return prefix + text + "\033[0m" def muted(text: str) -> str: - return "\033[90m" + text + "\033[0m" + return "\033[90m" + text + "\033[0m" if _USE_COLOR else text def echo(*args: Any, **kwargs: Any) -> None: diff --git a/marimo/_server/print.py b/marimo/_server/print.py index d35bd7ad2b6..b4648738157 100644 --- a/marimo/_server/print.py +++ b/marimo/_server/print.py @@ -38,10 +38,10 @@ def print_startup( f"{green('Create or edit notebooks in your browser', bold=True)} {_utf8('📝')}" ) print_() - print_tabbed(f"➜ {green('URL')}: {_colorized_url(url)}") + print_tabbed(f"{_utf8('➜')} {green('URL')}: {_colorized_url(url)}") if network: print_tabbed( - f"➜ {green('Network')}: {_colorized_url(_get_network_url(url))}" + f"{_utf8('➜')} {green('Network')}: {_colorized_url(_get_network_url(url))}" ) print_()