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
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions