Subprocess output with color codes?

Hey folks,

Ultimately I want to be able to run a subprocess, save the output in real time and output any colored output to the terminal. I was doing this via something like this:

    process = subprocess.Popen(
        cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT

As time goes on I read in a byte at a time and save it to a buffer and send it to stdout. I noticed that I never see color codes (ANSI?) make it through. Is there any way to allow those codes to come through so I can forward them to stdout (while still getting the output in a buffer in real time). If I skip trying to save the data, colors work fine.

Here is a simple example to reproduce:

from colorama import Fore, init as colorama_init


print(Fore.GREEN + "Hello world!" + Fore.RESET)

and playing in the interpreter:

In [1]: import subprocess

In [2]: subprocess.check_call('python')
Hello world!
Out[2]: 0

In [3]: subprocess.check_output('python')
Out[3]: b'Hello world!\r\n'

In [4]: subprocess.check_output('python')

And now a picture to show the coloring in check_call, but not in check_output. (Without the coloring, we’re missing the issue).

I’m looking for a cross-platform solution. I’ve read some things about using pty on Linux, but not really seen much about a Win32 solution. Thanks!

What program are you trying to run? Colorama tries to detect if stdout is connected to a terminal, and if not it defaults to automatically stripping the ANSI sequences from the output. That makes parsing the output, writing it to a file etc easier, but isn’t what you want here. Most terminal libraries are going to function similarly. Usually there’s an option to disable/enable colours - in this case init(strip=False).

It sort of varies. The code that calls subprocess is generic. It’s used to run various 3rd party executables and does some internal ‘magic’ to save the output, process it, etc.

Internally its a python script called: run. Simplified down to doing a Popen then reading a byte from the subprocess stdout, writing a byte to its stdout over and over until the subprocess exits. You pass the command and args to it to run the process via run.

Running something like ls -la --color=always via run gets colored output to stdout still. Though using something like run ipython never gets color. Similarly I was actually using rich.console and it’s color was getting lost too.

I’m guessing the colors get lost because something like colorama converts the ANSI escape codes to Win32 api calls which get eaten since we’re in a subprocess, then we lose the escape codes… but honestly no idea.

I think I may have figured out a trick here. If I call:


then setup my rich.Console via:

console = Console(force_terminal=True, force_interactive=True, legacy_windows=False)

Then the script can print in color when run via run

The key is even though colorama wants to do special Win32 handling, if I try really hard to force it (and rich) to do ANSI codes instead (supported on Win10+) they seem to go through.

Thanks folks!