cross-platform coloured text in terminal

Jonathan Hartley tartley at tartley.com
Mon Apr 19 20:12:00 EDT 2010


On Apr 17, 11:52 am, Jonathan Hartley <tart... at tartley.com> wrote:
> On Apr 16, 5:59 pm, Lie Ryan <lie.1... at gmail.com> wrote:
>
>
>
> > On 04/16/10 19:28, Jonathan Hartley wrote:
>
> > > I'm playing with ideas of what API to expose. My favourite one is to
> > > simply embed ANSI codes in the stream to be printed. Then this will
> > > work as-is on Mac and *nix. To make it work on Windows, printing could
> > > be done to a file0-like object which wraps stdout:
>
> > The problem with that is you're simply reinventing ANSI.SYS device driver.
>
> > An alternative API is you could override .__add__(), like so (completely
> > untested):
>
> > classColor(object):
> >    def __init__(self,color):
> >        self.color=  map_the_color(color)
> >        self.string = ""
> >    def __add__(self, string):
> >        self.string += string
> >        return self
> >    def __str__(self):
> >        if terminal_can_do_ansi_color:
> >            return ansicolorescape(self.string, self.color)
> >        elif windows:
> >            syscalltocolor(self.color)
> >            print self.string
> >            syscalltocolor(reset thecolor)
> >            return ""
>
> > GREEN =Color('green')
> > print GREEN + "Great" + "Good"
>
> > you can even go a bit further and allow chained calls (again, completely
> > untested, but you get the idea):
>
> > classColor(object):
> >    def __init__(self,color):
> >        self.color=  map_the_color(color)
> >        self.stack = []
> >    def __add__(self, string):
> >        if isinstance(string,Color):
> >            # not a string, chain the calls
> >            self.stack.append((string.color, []]))
> >        else:
> >            # a string,
> >            self.stack[-1][1].append(string)
> >        return self
> >    def __radd__(self, string):
> >        self.stack.append([self.default, string])
> >        return self
>
> >    def __str__(self):
> >        if ansi_capable:
> >            return colorescape(format, string)
> >        elif windows:
> >            for format, string in self.stack:
> >                syscalltocolor(color)
> >                print string
> >                return ""
>
> > GREEN =Color('green')
> > RED =Color('red')
>
> > print "Fairly" + GREEN + "Great" + RED + "Poor"
>
> > or something like that, and you will have an API that works
> > transparently on all platforms. The downside is that you cannot call
> > str(GREEN + "foo") on windows.
>
> Hey Lie,
>
> Thanks heaps for the reply!
>
> >> The problem with that is you're simply reinventing ANSI.SYS device driver.
>
> I don't see that as a problem - in fact I think it's exactly my
> goal! :-)
>
> The difference is that the ANSI driver requires installation and a
> reboot on the end-user's computer, which is a fiddly and intrusive
> thing for a Python developer to achieve. Whereas doing the same job in
> a Python module is easy to use for the Python developer - they just
> import the module, maybe call an 'init()' function, and then the ANSI
> functionality works on all platforms.
>
> Your ideas about generating and chaining the ANSI code strings are
> great. I worry though, about intermingling the code that generates
> ANSI escape sequences with the code which makes them work on Windows.
> The problem is that then, only applications which use your ANSI-
> generation library will work on Windows. Whereas if these two things
> are kept separate, then applications which use any other ANSI-
> generation techniques, such as using 'termcolor', or manaully printing
> raw ANSI sequences, these can also all work on Windows too, simply by
> adding an import and an 'init()' call to the start of the application.
>
> Am I making sense? Many thanks for your thoughts.
>
>   Jonathan


I have implemented these ideas here. It seems to work.
http://pypi.python.org/pypi/colorama



More information about the Python-list mailing list