Suppress output to stdout/stderr in InteractiveInterpreter

Dave W. evadeflow at gmail.com
Wed Apr 14 21:03:15 EDT 2010


I've subclassed InteractiveInterpreter in an attempt to make it
friendlier for use in a remote console for a C++ app.  What I really
wanted to do was wrap/adapt the base class's runsource() method to
return a 2-tuple (more, result) where 'more' is a bool indicating
whether a complete command was recognized, and 'result' is a string
representing the results of evaluating the last chunk (which may be
empty, or may contain an error message).

The only fool-proof way I found to do this was to redirect stdout/
stderr
during calls to the base class's runsource() method.  If I only
provide
custom sys.displayhook and sys.excepthook replacements, then any print
statements the user enters go to the host app's stdout:

  >>> print xvis.get_object(17).pos

instead of being captured and echoed back to the remote console.
If I omit the print, it does what I expect:

  >>> xvis.get_object(17).pos
  >>> (11.7, 1005.0, 0.0)

But I'd really like to:

1) Get rid of this slight difference to the normal python REPL
2) Not have to redirect stdout/stderr (I'm afraid other [C++]
   threads may compete with python for these streams.)

I thought I could get away with import print_function from __future__
(see example code below), but my re-pointed print function never gets
called.

I think I'm just naive about how exec() works. Is it hard-wired to
stdout or something?  *Should* this even work?

Any insight much appreciated!

- Dave Wolfe

----------

from __future__ import print_function
...
class HookContext(object):

    def __init__(self, printhook, displayhook, excepthook):
        self.printhook = printhook
        self.displayhook = displayhook
        self.excepthook = excepthook

    def __enter__(self):
        print = self.printhook
        sys.displayhook = self.displayhook
        sys.excepthook = self.excepthook

    def __exit__(self, exc_type, exc_value, traceback):
        print = __builtins__.print
        sys.displayhook = sys.__displayhook__
        sys.excepthook =  sys.__excepthook__


class Interpreter(InteractiveInterpreter):

    [ ... lots of stuff omitted ...]

    def do_runsource(self, source):
        self.output.reset()
        self.output.truncate()

        with HookContext(self.printhook
                         self.displayhook, self.excepthook):
            try:
                more = InteractiveInterpreter.runsource(self, source)
                result = self.output.getvalue()
            except (EOFError, OverflowError, SyntaxError):
                pass

            return more, result



More information about the Python-list mailing list