Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ANSI colored output: How to determine how python was called?

0 views
Skip to first unread message

Pearu Peterson

unread,
May 20, 2002, 6:35:00 AM5/20/02
to

Hi,

In my python program I want to output ANSI colored text only if the
terminal where the program was executed can support ANSI colored text. In
all other cases the program should output ordinary text.

My initial approach was to check the TERM environment variable, for
example,

if os.environ.get('TERM',None) in ['rxvt','xterm']:
print '\x1b[31mHello!\x1b[0m' # red Hello!
else:
print 'Hello!'

But then I found that when this program is called through

commands.getstatusoutput(..)

and its friends, then the above test fails in the sense that red `Hello!'
is printed but I would like to have here an ordinary `Hello!'.

So, my question is:

Are there alternative (hopefully better) ways to decide whether the
output "device" of python stdout supports ANSI colored text or not?

Thanks,
Pearu

Michael Hudson

unread,
May 20, 2002, 11:53:26 AM5/20/02
to
Pearu Peterson <pe...@cens.ioc.ee> writes:

Chuck an os.isatty(0) in there?

Cheers,
M.

--
Q: Isn't it okay to just read Slashdot for the links?
A: No. Reading Slashdot for the links is like having "just one hit"
off the crack pipe.
-- http://www.cs.washington.edu/homes/klee/misc/slashdot.html#faq

Donn Cave

unread,
May 20, 2002, 12:19:33 PM5/20/02
to
Quoth Pearu Peterson <pe...@cens.ioc.ee>:

The problem you encountered with commands.getstatusoutput() is
easily solved -

if sys.stdout.isatty() and os.environ.get(...

As for the other problem, you'll never account for all the color
terminal emulators that way - many of them will show up as vt102,
or who knows what. The original "xterm" was not color capable.
It might be nice to pull something else out of the environment too,
for the sake of people who are missing the boat on TERM - maybe
LS_COLORS, which is already used by GNU ls, or something specific
to your application.

Donn Cave, do...@u.washington.edu

Pearu Peterson

unread,
May 20, 2002, 3:42:29 PM5/20/02
to

On 20 May 2002, Donn Cave wrote:

> Quoth Pearu Peterson <pe...@cens.ioc.ee>:
>
> | In my python program I want to output ANSI colored text only if the
> | terminal where the program was executed can support ANSI colored text. In
> | all other cases the program should output ordinary text.
> |
> | My initial approach was to check the TERM environment variable, for
> | example,
> |
> | if os.environ.get('TERM',None) in ['rxvt','xterm']:
> | print '\x1b[31mHello!\x1b[0m' # red Hello!
> | else:
> | print 'Hello!'
> |
> | But then I found that when this program is called through
> |
> | commands.getstatusoutput(..)
> |
> | and its friends, then the above test fails in the sense that red `Hello!'
> | is printed but I would like to have here an ordinary `Hello!'.
> |
> | So, my question is:
> |
> | Are there alternative (hopefully better) ways to decide whether the
> | output "device" of python stdout supports ANSI colored text or not?
>
> The problem you encountered with commands.getstatusoutput() is
> easily solved -
>
> if sys.stdout.isatty() and os.environ.get(...

Thanks!

> As for the other problem, you'll never account for all the color
> terminal emulators that way - many of them will show up as vt102,
> or who knows what. The original "xterm" was not color capable.
> It might be nice to pull something else out of the environment too,
> for the sake of people who are missing the boat on TERM - maybe
> LS_COLORS, which is already used by GNU ls, or something specific
> to your application.

In debian woody and Suse linux only TERM and COLORTERM are defined by
default that I found to be related variables to this coloring issue.
And COLORTERM seems to be interpreted differently in these two linux
systems: in woody I have COLORTERM=rxvt while in Suse COLORTERM=1.

I checked that colorgcc is more liberal on coloring output than I
with TERM in [rxvt,xterm]. So, I think, I'll keep it in that way until
some old HP user will complain about the junk in its terminal ;)

Pearu

François Pinard

unread,
May 20, 2002, 4:58:21 PM5/20/02
to
[Donn Cave]

> Quoth Pearu Peterson <pe...@cens.ioc.ee>:

> | Are there alternative (hopefully better) ways to decide whether the
> | output "device" of python stdout supports ANSI colored text or not?

> It might be nice to pull something else out of the environment too, for


> the sake of people who are missing the boat on TERM - maybe LS_COLORS,
> which is already used by GNU ls, or something specific to your application.

The normal way to check for colour terminal support is through terminal
info capabilities (terminfo). Check for `op', 'AF', `AB', `Sf', `Sb',
'Co', `pa' and `NC' capabilities, in particular. I forgot details as of
now, but remember I had to fight a bit to get everything right.

--
François Pinard http://www.iro.umontreal.ca/~pinard


Donn Cave

unread,
May 20, 2002, 6:01:58 PM5/20/02
to
Quoth pin...@iro.umontreal.ca (=?iso-8859-1?q?Fran=E7ois?= Pinard):
...

| The normal way to check for colour terminal support is through terminal
| info capabilities (terminfo). Check for `op', 'AF', `AB', `Sf', `Sb',
| 'Co', `pa' and `NC' capabilities, in particular. I forgot details as of
| now, but remember I had to fight a bit to get everything right.

That is indeed the only bona fide declaration of color capabilities,
but it's good for only a small subset of the color capable terminal
emulations. If they're coming in as "vt102", it won't help.

I personally could benefit from it, as I have my own terminfo description
and could easily add those color attributes - but then lynx and other
color aware applications will do really horrible things with them,
distasteful and unreadable. So I use the colors in place of underline
and bold modes, and leave the color attributes undefined. GNU ls
really does it right, as far as I'm concerned - there's a flag to
say whether you'd like to use color, and then an optional environment
variable to control the actual choice of colors (colors vary greatly
between one emulation and another, and of sometimes you have a black
background instead of white, so some control of the colors may be
needed just to get a readable display.)

Donn Cave, do...@u.washington.edu

Pearu Peterson

unread,
May 20, 2002, 6:15:30 PM5/20/02
to

On 20 May 2002, François Pinard wrote:

> [Donn Cave]
>
> > Quoth Pearu Peterson <pe...@cens.ioc.ee>:
>
> > | Are there alternative (hopefully better) ways to decide whether the
> > | output "device" of python stdout supports ANSI colored text or not?
>
> > It might be nice to pull something else out of the environment too, for
> > the sake of people who are missing the boat on TERM - maybe LS_COLORS,
> > which is already used by GNU ls, or something specific to your application.
>

> The normal way to check for colour terminal support is through terminal
> info capabilities (terminfo). Check for `op', 'AF', `AB', `Sf', `Sb',
> 'Co', `pa' and `NC' capabilities, in particular. I forgot details as of
> now, but remember I had to fight a bit to get everything right.

Thanks for the hint.

I now discovered the Python curses module. It seems that

sys.stdout.isatty() and curses.wrapper(lambda s:curses.has_colors())

gives a reliable answer for if the terminal supports colors or not.
However, when using it, the screen "blinks" (the terminal is blanked
and then its contents is restored) as curses.wrapper(..) initializes and
deinitializes the ncurses library. I have not found yet if this
"blink" could be avoided.

Pearu

Fernando Pérez

unread,
May 20, 2002, 7:41:22 PM5/20/02
to
Pearu Peterson wrote:

> So, my question is:
>
> Are there alternative (hopefully better) ways to decide whether the
> output "device" of python stdout supports ANSI colored text or not?
>
> Thanks,
> Pearu

Good luck Pearu. Let me know if you find a _robust_ solution to this problem.
IPython uses a lot of colors (by the way, feel free to grab the classes I've
made for it which automate color table management, scheme switching, etc.).
And support in various terminals is very spotty and inconsistent. Even xterm
isn't fully compliant, and rxvt (I think) has a few quirks. I've found
konsole and gnome-terminal to have much better behavior. The CDE dt-terminal
is its own bag of problems.

As far as I can tell, there's no sane way of determining from inside the code
if a given terminal will put out garbage or if it will put out properly
colored text. And when you are trying to run colored text through pagers like
more/less, a whole new can of worms opens up! This weekend I added colored
object introspection to IPython which works beautifully on my Mandrake 8.2
laptop, just to find out that the Redhat 7.2 machines in my office spit out
pure garbage with it!

So if you can figure out a permanent, solid solution please drop me a line on
it.

Cheers,

f.

Geoff Gerrietts

unread,
May 20, 2002, 8:45:10 PM5/20/02
to
Quoting Pearu Peterson (pe...@cens.ioc.ee):
>
> So, my question is:
>
> Are there alternative (hopefully better) ways to decide whether the
> output "device" of python stdout supports ANSI colored text or not?

The way I've done this is something of a hack, but it's been a hack
that has worked for me. My understanding is that it's fairly portable
to Unix systems, but it doesn't port at all to non-unix systems, and I
can't vouch personally for how well it ports. It works well for me
under Linux.

The solution (if you can call it that, "ugly hack" might be more apt)
is to use the tput utility and let the terminal handling libraries
figure this stuff out for me. I liked this solution better than going
with curses.

Here's the test program I wrote when figuring all this crap out:

import os

# 0 black ; 1 red ; 2 green ; 3 yellow ; 4 blue ; 5 magenta ; 6 cyan ; 7 white

NUMCOL = os.popen("tput colors 2>/dev/null", "r").read()
SAVE_C = os.popen("tput sc 2>/dev/null", "r").read()
RESETC = os.popen("tput rc 2>/dev/null", "r").read()
YEL_FG = os.popen("tput setaf 3 2>/dev/null", "r").read()
BLK_BG = os.popen("tput setb 0 2>/dev/null", "r").read()
NORMAL = os.popen("tput sgr0 2>/dev/null", "r").read()
BOLD = os.popen("tput bold 2>/dev/null", "r").read()

print NUMCOL
print BLK_BG, YEL_FG, "wassup", BOLD, "hoser", NORMAL

If I'm remembering right, NUMCOL is set to 2 on a terminal that only
supports monochrome.

Discussion on this topic is plentiful across the net, but really solid
sources are hard to find. I wish I had the URLs for you, but I can
tell you that the best sources I've found have been in mailing list
threads where people are trying to get colour into their highly
customized prompt strings.

Sad, but true: in Linux as in Windows, the dominant force driving
technological discovery is making the desktop "look cool". :)

Best of luck,
--G.

--
Geoff Gerrietts "By doing just a little every day, I can gradually
let the task completely overwhelm me."
<geoff at gerrietts net> --Ashleigh Brilliant


François Pinard

unread,
May 20, 2002, 10:53:47 PM5/20/02
to
[Donn Cave]

> Quoth pin...@iro.umontreal.ca (=?iso-8859-1?q?Fran=E7ois?= Pinard):
> ...
> | The normal way to check for colour terminal support is through terminal

> | info capabilities (terminfo). [...]

> That is indeed the only bona fide declaration of color capabilities,
> but it's good for only a small subset of the color capable terminal
> emulations. If they're coming in as "vt102", it won't help.

If a terminal declaration is improper, it is likely to be suboptimal.
A terminal emulator should ideally have its own, adequate terminfo entry.

> [...] but then lynx and other color aware applications will do really


> horrible things with them, distasteful and unreadable.

When such things happen, either the terminfo description is improper, or
the application has bugs with terminal handling. One should either correct
the terminfo description, or debug the program. We probably agree on the
fact these areas are not that much fun, and diagnosing terminfo-related
problems require patience, study, and some dedication :-).

> [...] and of sometimes you have a black background instead of white, so


> some control of the colors may be needed just to get a readable display.

So true! :-)

Donn Cave

unread,
May 21, 2002, 1:56:51 AM5/21/02
to
Quoth pin...@iro.umontreal.ca (=?iso-8859-1?q?Fran=E7ois?= Pinard):

| [Donn Cave]
|
|> Quoth pin...@iro.umontreal.ca (=?iso-8859-1?q?Fran=E7ois?= Pinard):
|> ...
|> | The normal way to check for colour terminal support is through terminal
|> | info capabilities (terminfo). [...]
|
|> That is indeed the only bona fide declaration of color capabilities,
|> but it's good for only a small subset of the color capable terminal
|> emulations. If they're coming in as "vt102", it won't help.
|
| If a terminal declaration is improper, it is likely to be suboptimal.
| A terminal emulator should ideally have its own, adequate terminfo entry.
|
|> [...] but then lynx and other color aware applications will do really
|> horrible things with them, distasteful and unreadable.
|
| When such things happen, either the terminfo description is improper, or
| the application has bugs with terminal handling. One should either correct
| the terminfo description, or debug the program. We probably agree on the
| fact these areas are not that much fun, and diagnosing terminfo-related
| problems require patience, study, and some dedication :-).

I think if you saw what I've seen, we'd agree on more.

Within the limitations of ANSI terminal emulation color, the only
reliably satisfactory approach is to put the entire color scheme
under the control of the user. At this point, you don't need any
special information from terminfo (of course it's good to check.)
If you have a fairly recent version of Pine, that's an example.

Aside from terminfo inaccuracies and application bugs, there are
also bugs and misfeatures in terminal emulators, especially when
you get into interesting combinations with the less commonly used
background color options.

Donn Cave, do...@drizzle.com

Pearu Peterson

unread,
May 21, 2002, 3:20:48 AM5/21/02
to

On 20 May 2002, Fernando Pérez wrote:

> Pearu Peterson wrote:
>
> > So, my question is:
> >
> > Are there alternative (hopefully better) ways to decide whether the
> > output "device" of python stdout supports ANSI colored text or not?
> >
> > Thanks,
> > Pearu
>
> Good luck Pearu. Let me know if you find a _robust_ solution to this problem.
> IPython uses a lot of colors (by the way, feel free to grab the classes I've
> made for it which automate color table management, scheme switching, etc.).

I'll do that. Thanks.

There are already some interesting solutions in this thread.
Thanks to all for contribution!

> As far as I can tell, there's no sane way of determining from inside the code
> if a given terminal will put out garbage or if it will put out properly
> colored text. And when you are trying to run colored text through pagers like
> more/less, a whole new can of worms opens up!

This can of worms is kept closed by using sys.stdout.isatty(). Try:

python -c "import sys;print sys.stdout.isatty()" | less

Pearu

Fernando Pérez

unread,
May 21, 2002, 12:04:16 PM5/21/02
to
Pearu Peterson wrote:

>> colored text. And when you are trying to run colored text through pagers
>> like more/less, a whole new can of worms opens up!
>
> This can of worms is kept closed by using sys.stdout.isatty(). Try:
>
> python -c "import sys;print sys.stdout.isatty()" | less
>

Ah, but I _want_ to run colored text through a pager. And a well configured
recent version of less can do it beautifully (under linux), though 'more'
gets totally confused.

My approach has been to document it in IPython and make it an option which is
off by default. The users can test, and if it works for them they can turn it
on. When it works it's great: you get syntax highlighted source code
printouts for all your code objects from within ipython.

Cheers,

f.

David M. Cooke

unread,
May 21, 2002, 2:47:42 PM5/21/02
to
At some point, Pearu Peterson <pe...@cens.ioc.ee> wrote:

>> [Donn Cave]
>>
>> > Quoth Pearu Peterson <pe...@cens.ioc.ee>:
>>
>> > | Are there alternative (hopefully better) ways to decide whether the
>> > | output "device" of python stdout supports ANSI colored text or not?
>>

>> The normal way to check for colour terminal support is through terminal
>> info capabilities (terminfo). Check for `op', 'AF', `AB', `Sf', `Sb',
>> 'Co', `pa' and `NC' capabilities, in particular. I forgot details as of
>> now, but remember I had to fight a bit to get everything right.
>
> Thanks for the hint.
>
> I now discovered the Python curses module. It seems that
>
> sys.stdout.isatty() and curses.wrapper(lambda s:curses.has_colors())
>
> gives a reliable answer for if the terminal supports colors or not.
> However, when using it, the screen "blinks" (the terminal is blanked
> and then its contents is restored) as curses.wrapper(..) initializes and
> deinitializes the ncurses library. I have not found yet if this
> "blink" could be avoided.

I think what you want is something like:

def term_has_colours():
if not sys.stdout.isatty():
return 0
curses.start_color()
return curses.has_colors()

curses.wrapper does more than you need. I use something like the above
in my $PYTHONSTARTUP file to give me a coloured prompt.

--
|>|\/|<
/--------------------------------------------------------------------------\
|David M. Cooke
|cookedm(at)physics(dot)mcmaster(dot)ca

Pearu Peterson

unread,
May 21, 2002, 3:10:04 PM5/21/02
to

On 21 May 2002, David M. Cooke wrote:

> I think what you want is something like:
>
> def term_has_colours():
> if not sys.stdout.isatty():
> return 0
> curses.start_color()
> return curses.has_colors()
>
> curses.wrapper does more than you need. I use something like the above
> in my $PYTHONSTARTUP file to give me a coloured prompt.

The problem with the above is that it also needs

curses.initscr()

that in my python prompt messed up the terminal completely so that I have
to blindly exit python and reset the terminal. And

curses.endwin()

did not fixed the mess up either.

That's the reason why I ended up with using curses.wrapper that returns
with properly restoring the current terminal.

Thanks,
Pearu

Donn Cave

unread,
May 21, 2002, 4:39:58 PM5/21/02
to
Quoth Pearu Peterson <pe...@cens.ioc.ee>:
...

| That's the reason why I ended up with using curses.wrapper that returns
| with properly restoring the current terminal.

I should also mention that curses isn't a very well standardized
interface, so the curses module isn't as portable as the rest of
Python. A solution that doesn't require curses at all will run
on more platforms.

Donn Cave, do...@u.washington.edu

Michael Hudson

unread,
May 22, 2002, 6:06:47 AM5/22/02
to
Pearu Peterson <pe...@cens.ioc.ee> writes:

> On 21 May 2002, David M. Cooke wrote:
>
> > I think what you want is something like:
> >
> > def term_has_colours():
> > if not sys.stdout.isatty():
> > return 0
> > curses.start_color()
> > return curses.has_colors()
> >
> > curses.wrapper does more than you need. I use something like the above
> > in my $PYTHONSTARTUP file to give me a coloured prompt.
>
> The problem with the above is that it also needs
>
> curses.initscr()

Hmm, has_colors() should probably require that you have called at
least setupterm(), not the full initscr(). Would be easy enough to
change.

> that in my python prompt messed up the terminal completely so that I have
> to blindly exit python and reset the terminal. And
>
> curses.endwin()
>
> did not fixed the mess up either.
>
> That's the reason why I ended up with using curses.wrapper that returns
> with properly restoring the current terminal.

Here's a version of has_colors() that only requires you call
setupterm() (newly supported in 2.2):

def has_colors_():
return (curses.tigetnum("colors") >= 0
and curses.tigetnum("pairs") >= 0
and ((curses.tigetstr("setf") is not None
and curses.tigetstr("setb") is not None)
or (curses.tigetstr("setaf") is not None
and curses.tigetstr("setab") is not None)
or curses.tigetstr("scp") is not None))

It's just a translation of has_colors() from the ncurses source.

Cheers,
M.

--
First time I've gotten a programming job that required a drug
test. I was worried they were going to say "you don't have
enough LSD in your system to do Unix programming". -- Paul Tomblin
-- http://home.xnet.com/~raven/Sysadmin/ASR.Quotes.html

0 new messages