Question

I'm trying to subclass the built-in file class in Python to add some extra features to stdin and stdout. Here's the code I have so far:

class TeeWithTimestamp(file):
    """
    Class used to tee the output of a stream (such as stdout or stderr) into
    another stream, and to add a timestamp to each message printed.
    """

    def __init__(self, file1, file2):
        """Initializes the TeeWithTimestamp"""
        self.file1 = file1
        self.file2 = file2
        self.at_start_of_line = True

    def write(self, text):
        """Writes text to both files, prefixed with a timestamp"""

        if len(text):
            # Add timestamp if at the start of a line; also add [STDERR]
            # for stderr
            if self.at_start_of_line:
                now = datetime.datetime.now()
                prefix = now.strftime('[%H:%M:%S] ')
                if self.file1 == sys.__stderr__:
                    prefix += '[STDERR] '
                text = prefix + text

            self.file1.write(text)
            self.file2.write(text)

            self.at_start_of_line = (text[-1] == '\n')

The purpose is to add a timestamp to the beginning of each message, and to log everything to a log file. However, the problem I run into is that if I do this:

# log_file has already been opened
sys.stdout = TeeWithTimestamp(sys.stdout, log_file)

Then when I try to do print 'foo', I get a ValueError: I/O operation on closed file. I can't meaningfully call file.__init__() in my __init__(), since I don't want to open a new file, and I can't assign self.closed = False either, since it's a read-only attribute.

How can I modify this so that I can do print 'foo', and so that it supports all of the standard file attributes and methods?

Was it helpful?

Solution

Calling file.__init__ is quite feasible (e.g., on '/dev/null') but no real use because your attempted override of write doesn't "take" for the purposes of print statements -- the latter internally calls the real file.write when it sees that sys.stdout is an actual instance of file (and by inheriting you've made it so).

print doesn't really need any other method except write, so making your class inherit from object instead of file will work.

If you need other file methods (i.e., print is not all you're doing), you're best advised to implement them yourself.

OTHER TIPS

You can as well avoid using super :

class SuperFile(file):

    def __init__(self, *args, **kwargs):
        file.__init__(self, *args, **kwargs)

You'll be able to write with it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top