Skip to content

Typer's CliRunner.invoke() method with color=False (the default) is not properly disabling ANSI color codes in the output during CI/CD testing #9

@rahlk

Description

@rahlk

Describe the bug
Typer's CliRunner.invoke() method with color=False (the default) is not properly disabling ANSI color codes in the output during testing. The output still contains escape sequences like \x1b[1m and \x1b[0m, causing test assertions to fail when checking for plain text strings.

To Reproduce
Steps to reproduce the behavior:

  1. Create a Typer app with Rich integration (default behavior)
  2. Write a test using typer.testing.CliRunner
  3. Call cli_runner.invoke(app, ["--help"]) (color=False is the default)
  4. Assert that plain text appears in result.output
  5. Test fails because output contains ANSI escape sequences

Minimal reproduction example:

import typer
from typer.testing import CliRunner

app = typer.Typer()

@app.command()
def hello():
    """Say hello."""
    typer.echo("Hello World!")

def test_help():
    runner = CliRunner()
    result = runner.invoke(app, ["--help"])
    # This should work but fails due to ANSI codes
    assert "Usage:" in result.output

# Output contains: '\x1b[1m                                                                                \x1b[0m\n\x1b[1m \x1b[0m\x1b[1...'

Expected behavior
When color=False is set (or defaulted), the CliRunner should produce plain text output without any ANSI escape sequences, making it suitable for string matching in tests.

Environment:

  • Typer version: 0.16.0
  • Python version: 3.12.11
  • OS: Linux (GitHub Actions environment)
  • Rich integration: Enabled (default)

Logs

AssertionError: assert 'Usage: codeanalyzer [OPTIONS] COMMAND [ARGS]...' in '\x1b[1m                                                                                \x1b[0m\n\x1b[1m \x1b[0m\x1b[1...   \x1b[2m│\x1b[0m\n\x1b[2m╰──────────────────────────────────────────────────────────────────────────────╯\x1b[0m\n\n'

Raw output contains escape sequences:
- \x1b[1m (bold)
- \x1b[0m (reset)
- \x1b[2m (dim)

Current Workaround

import re

def strip_ansi(text):
    return re.sub(r'\x1b\[[0-9;]*[mK]', '', text)

def test_help():
    runner = CliRunner()
    result = runner.invoke(app, ["--help"])
    clean_output = strip_ansi(result.output)
    assert "Usage:" in clean_output

Additional context

  • This issue primarily manifests in CI environments (GitHub Actions) but may also occur locally depending on terminal capabilities
  • The issue appears to be related to Rich's automatic color detection overriding the color=False parameter
  • Other CLI testing frameworks (like Click's CliRunner) properly respect the color parameter
  • Setting environment variables like NO_COLOR=1 or TERM=dumb may provide additional workarounds but shouldn't be necessary when color=False is explicitly set

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions