# encoding: utf-8 """ Trap stdout/stderr, including at the OS level. Calls a callback with the output each time Python tries to write to the stdout or stderr. """ __docformat__ = "restructuredtext en" #------------------------------------------------------------------------------- # Copyright (C) 2008 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # Imports #------------------------------------------------------------------------------- from fd_redirector import FDRedirector, STDOUT, STDERR from IPython.kernel.core.file_like import FileLike from IPython.kernel.core.output_trap import OutputTrap class RedirectorOutputTrap(OutputTrap): """ Object which can trap text sent to stdout and stderr. """ #------------------------------------------------------------------------ # OutputTrap interface. #------------------------------------------------------------------------ def __init__(self, out_callback, err_callback): """ out_callback : callable called when there is output in the stdout err_callback : callable called when there is output in the stderr """ # Callback invoked on write to stdout and stderr self.out_callback = out_callback self.err_callback = err_callback # File descriptor redirectors, to capture non-Python # output. self.out_redirector = FDRedirector(STDOUT) self.err_redirector = FDRedirector(STDERR) # Call the base class with file like objects that will trigger # our callbacks OutputTrap.__init__(self, out=FileLike(self.on_out_write), err=FileLike(self.on_err_write), ) def set(self): """ Set the hooks: set the redirectors and call the base class. """ self.out_redirector.start() self.err_redirector.start() OutputTrap.set(self) def unset(self): """ Remove the hooks: call the base class and stop the redirectors. """ OutputTrap.unset(self) # Flush the redirectors before stopping them self.on_err_write('') self.err_redirector.stop() self.on_out_write('') self.out_redirector.stop() #------------------------------------------------------------------------ # Callbacks for synchronous output #------------------------------------------------------------------------ def on_out_write(self, string): """ Callback called when there is some Python output on stdout. """ try: self.out_callback(self.out_redirector.getvalue() + string) except: # If tracebacks are happening and we can't see them, it is # quasy impossible to debug self.unset() raise def on_err_write(self, string): """ Callback called when there is some Python output on stderr. """ try: self.err_callback(self.err_redirector.getvalue() + string) except: # If tracebacks are happening and we can't see them, it is # quasy impossible to debug self.unset() raise