Source code for scitools.redirect_io

#!/usr/bin/env python
r"""

Example usage:
--------------

Redirect stderr using the 'with'-statement:

>>> from __future__ import with_statement
>>> from redirect_io import *
>>> with hidden_stderr():
...     print >> sys.stderr, 'Divide By Cucumber Error'
>>>

Redirect stderr to stout:

>>> with hidden_stderr(sys.stdout):
...     print >> sys.stderr, 'Where am I ?'
Where am I ?
>>>

Optinal usage without 'with'-statement:

>>> _redirect_err()
>>> try:
...     print >> sys.stderr, " +++ Divide by Cucumber Error, "\
...                          "Please ReInstall Universe And Reboot +++"
... finally:
...     _return_err()
>>>

Fetch previous error messages:

>>> print _tmp_err.getvalue() 
Divide By Cucumber Error
 +++ Divide by Cucumber Error, Please ReInstall Universe And Reboot +++
<BLANKLINE>
>>> 
"""
from __future__ import with_statement # Comment to run _test_with_statement
__author__ = 'Rolv Erlend Bredesen <rolv@simula.no>'
__all__ = ['sys', '_tmp_err', 'hidden_stderr', '_redirect_err', '_return_err']

import __future__
import StringIO 
import sys
from contextlib import contextmanager  

if float(sys.version[:3]) < 2.5:
    raise ImportError("This module requires version >= 2.5 of python")

_std_err = sys.stderr
_tmp_err =  StringIO.StringIO() # stream for hidden stderr
_tmp_err.__exit__ = _tmp_err.flush # Add __exit__ method

@contextmanager # 'with' requires __enter__ and __exit__
[docs]def hidden_stderr(stream=_tmp_err): sys.stderr = stream try: yield None finally: sys.stderr = _std_err # For error stream with python version < 2.5
def _redirect_err(): sys.stderr = _tmp_err def _return_err(): sys.stderr = _std_err def _test_with_statement(): """ If the word 'with', which is a reserved keyword from python version 2.6, is used in python2.5 code then a warning will be printed to sys.stderr when the code is bytecompiled. In this example we look at capturing the warning messages """ assert 'with_statement' not in globals() assert sys.version[:3] == '2.5' # Force Error statement = 'with=3' try: c = compile(statement, '/dev/null', 'exec', __future__.with_statement.compiler_flag) except SyntaxError: print "Success: '%s' did not compile" %statement else: raise Exception("Statement: '%s' should not have been compiled" \ % statement) # Setup error redirection std_err = sys.stderr tmp_err = StringIO.StringIO() if float(sys.version[:3]) < 2.5: raise ImportError, "This module requires version 2.5 of python" # Compile with error redirection statement1 = 'with=3' statement2 = 'print "with>>", with' print '>>>', statement1 print '>>>', statement2 # Test compilation of code using the reserved keyword with # Redirection standard error under compilation to prevent warning _redirect_err() try: c = compile(statement1, '/dev/null', 'single') finally: _return_err() # No warning here exec c in {}, locals() _redirect_err() try: # This one will give a warning exec statement2 finally: _return_err() print "Here is the redirected error stream:\n", tmp_err.getvalue() # 'with'-example print "Testing the use of the 'with'-statement" c = compile( r"""'''In this example we test the use of the 'with'-statement''' #from __future__ import with_statement # using proper compile flag instead from contextlib import contextmanager # 'with' requires __enter__ and __exit__ err_ = StringIO.StringIO() @contextmanager def stderr_redirected(stream): err = sys.stderr sys.stderr = stream try: yield None finally: sys.stderr = err statement = 'with_=3' # we have imported the with_statement with stderr_redirected(err_): print >> sys.stderr, "Can you see me?" c_ = compile(statement, '/dev/null', 'single', 0, 0) """, '/dev/null', 'exec', __future__.with_statement.compiler_flag) exec c print "\nIt appears the with_statement worked." print "Here is the redirected error stream:\n", err_.getvalue() if __name__ == '__main__': if 'with_statement' in globals(): import doctest import unittest suite = unittest.TestSuite() suite.addTest(doctest.DocTestSuite()) runner = unittest.TextTestRunner(sys.stdout, verbosity=1) runner.run(suite) else: # To run you must comment # 'from __future__ import with_statement ' at start of file _test_with_statement()