ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: RedirectedIO context manager and redirect_io decorator
Submitter: Eduardo Padoan (other recipes)
Last Updated: 2007/11/20
Version no: 1.4
Category: Shortcuts

 

4 stars 1 vote(s)


Description:

Use the "with" keyword or a decorator to simplify a bit redirecting IO to a file.

Source: Text Source

#!/usr/bin/python
from __future__ import with_statement

import sys
from StringIO import StringIO

__all__ = ['RedirectedIO', 'redirect_io']


class RedirectedIO(object):
    def __init__(self, target=None, mode='a+',
                 close_target=True):
        try:
            target = open(target, mode)
        except TypeError:
            if target is None:
                target = StringIO()
        self.target = target
        self.close_target = close_target

    def __enter__(self):
        """ Redirect IO to self.target.
        """
        self.original_stdout = sys.stdout
        sys.stdout = self.target
        return self.target

    def __exit__(self, *args, **kwargs):
        """ Restore stdio and close the file.
        """
        sys.stdout = self.original_stdout
        if self.close_target:
            self.target.close()


def redirect_io(target=None, mode='a+', keep_target=True):
    """ Returns a decorator that wrapps a
    function and redirects its IO to a target
    file (a StringIO by default). The target is
    available as .iotarget on the decorated function.
    """
    def dec(func):

        def wrapper(*args, **kwargs):
            with RedirectedIO(target, mode, not keep_target) as iotarget:
                result = func(*args, **kwargs)
                if keep_target:
                    wrapper.iotarget = iotarget
            return result

        wrapper.iotarget = None
        wrapper.__doc__ = func.__doc__
        wrapper.__name__ = func.__name__
        return wrapper

    return dec

Discussion:

If no file or StringIO (or any file-like) is given, it will redirect the output to a StringIO(). The default opening mode (a+) is not arbitrary: you will probably want to append each printed line to the file and still be able to read it. After the "with" block, the file is closed (by default).



Add comment

Number of comments: 3

You should restore the old stdout, Paul Moore, 2007/11/16
Rather than setting sys.stdout to sys.__stdout__ in __exit__, you should save the old sys.stdout in an instance variable in __enter__, and restore it in __exit__. That way, if the user nests this construct, or redirects sys.stdout some other way, you won't clobber his change.
Add comment

Eduardo Padoan, 2007/11/16
Nice point, thanks!
Add comment

Paul Moore, 2007/11/19
Typo in the __exit__ code: sys.stdout = sys.original_stdout. That should be self.original_stdout.
Add comment



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. IPy Notify

4. Changing return value ...

5. Quantum Superposition

6. Pickle objects under ...

7. Generalized delegates ...

8. Reorder a sequence (uses ...

9. Setting Win32 System ...

10. ObjectMerger




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.