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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With