colorama
colorama copied to clipboard
colorama is not working with Travis CI under specific circumstance
Hello there!
This issue is more likely a help wanted
than anything.
I'm writing PyFunceble (in this issue I'm referencing to the dev
branch) and since more than 2 months, I'm trying to find why colorama is not working under a specific circumstance.
So back to our issue:
Case that it is working
As PyFunceble is running for more than 6 months every day under Travis CI, server and sometimes PC, I consider the following as safe to mention.
Locally
If I run PyFunceble
(the executable) locally it's working.
Same if I create a script like the following, it's working.
#!/usr/bin/bash
PyFunceble -d github.com
Travis CI
Under Travis CI if I run PyFunceble
directly for testing, it is working as you can see in the following link.
Case that it is not working
Locally
No case found after months of testing and using.
Travis CI
If we create a .py
file or a bash script, and run PyFunceble
from inside the script, it is not working.
Examples:
- All 50+ Travis CI builds of https://travis-ci.org/Ultimate-Hosts-Blacklist (.py)
- All 15+ Travis CI build of https://travis-ci.org/dead-hosts (.py)
- https://travis-ci.org/mitchellkrogza/Phishing.Database (bash script)
Maybe I forgot to configure something, but I'm still not understanding this issue...
So, does anyone know what am I missing and why it is not working?
Thanks in advance for taking the time to read this issue and for the time you may take to answer this issue.
Have a nice day/night.
Cheers, Nissar
This is probably because the users of PyFunceble
run it in a subprocess, where "stdout" is not a tty, so colorama does not recognize stdout as a wrap-able stream and therefore strips the ANSI color codes.
Consider this simple script (let's put it in a file named "a.py"):
import colorama
colorama.init()
print(colorama.Fore.RED + 'hello' + colorama.Fore.RESET)
And this script that executes "a.py" in a subprocess (let's call it "b.py")
import subprocess
proc = subprocess.Popen("python a.py", stdout=subprocess.PIPE, shell=True)
output, error = proc.communicate()
print(output)
If you run the first script directly (python a.py
) you will get a red "hello". If you run b.py, which runs a.py, you will get a "regular" non-red "hello". The stdout of the subprocess is a pipe, i.e. not a "terminal stream" (tty), so the colors will be stripped.
I can't think of a good work around for you. Technically this is the intended behavior.
Hi @wiggin15, I tried to find a workaround based on your example and I finally found one. I hope that this may help improve colorama or help others who are in the same situation.
a.py
import colorama
print(colorama.Fore.RED + "hello" + colorama.Fore.RESET)
b.py
import sys
from subprocess import PIPE, Popen
def run_command(command, encoding="utf-8"):
"""
Run a command and return each line one by one.
:param command: The command to run
:type command: str|list
:param encoding: The encoding to use to decode the output of the command.
:type encoding: str
:return: A line of the command.
:rtype: str
"""
if isinstance(command, list):
# The given command is a list.
# We convert it to string.
command = " ".join(command)
# We launch the command.
process = Popen(command, stdout=PIPE, shell=True)
while True:
# We loop infinity because we want to get the output
# until there is not output anymore.
# We get the current line from the process stdout.
#
# Note: we use rstrip because we may have spaces after the output.
current_line = process.stdout.readline().rstrip()
if not current_line:
# The current line is empty or equal to None.
# We break the loop.
break
# We decode and return the current line to upstream.
yield current_line.decode(encoding)
if __name__ == "__main__":
# The script is executed directory.
for line in run_command("python a.py"):
# We loop through each line from the commands output.
# We print to stdout.
sys.stdout.write(line + "\n")
Proof:
"Concept"
Because proc.communicate()
return the output after the execution of the command as stated in the Documentation:
Wait for process to terminate.
I used Popen.stdout
instead which allow us to get line "correctly".
Strangely if we use colorama.init()
the coloration does not show up can you explain that @wiggin15 ?
Cheers, Nissar
Reading directly from stdout
attribute or using communicate
method makes no difference. The stdout "PIPE" is still not a tty and will be stripped from colorama. What happens in your case is that you don't actually use colorama, since you don't call colorama.init
so the streams are not wrapped. This will not work on Windows.
Closing as this is old enough but people can alternatively just set the PYCHARM_HOSTED
environment variable.
Stay safe and healthy.