I'd like to have real-time access to both interpreter input and error and standard output. Preferably this information would be written to a file, so that I can poll the file for changes after every interpreter command has been entered. For example, given an interpreter session:
>>> 5 * 7
35
>>> print("Hello, world!")
Hello, world!
>>> "Hello, world!"
'Hello, world!'
I'd like to see the following in a log file:
> 5 * 7
35
> print("Hello, world!")
Hello, world!
> "Hello, world!"
'Hello, world!'
The formatting is not important; what is important is that I can search the file for key words to trigger interactive events during the session.
What I have learned so far trying to accomplish this:
Python's code
module allows me to create an InteractiveConsole
object, the raw_input
method of which I can redefine to log to a file, like so:
import code
class LoggedConsole(code.InteractiveConsole):
def __init__(self, locals):
super(LoggedConsole, self).__init__(locals)
self.file = open('consolelog.dat', 'a')
def __del__(self):
self.file.close()
def raw_input(self, prompt=""):
data = input(prompt)
self.file.write(data+'\n')
return data
Furthermore, InteractiveConsole
uses a built-in write
method to log errors, which I can redefine to:
def write(self, data):
sys.stderr.write(data)
self.file.write(data+'\n')
I've also learned that the following snippet will log all stdout:
class Tee(object):
def __init__(self):
self.file = open('consolelog.dat', 'a')
self.stdout = sys.stdout
def __del__(self):
sys.stdout = self.stdout
self.file.close()
def write(self, data):
self.file.write(data)
self.stdout.write(data)
sys.stdout = Tee()
My (broken) attempt to bring this all together was to then create a LoggedConsole
object, and pass it Tee
in locals.
console = LoggedConsole(locals={sys.stdout:LoggedExec()})
console.interact()
(I've not passed locals before, so perhaps I'm doing it incorrectly here, but I don't receive an error.)
Anyways, this will open a new Interactive Console, and will log (after closing) all input and errors, but not output. I've been banging my head against this for a while, and I feel like I'm close, but maybe not even.
Also, is there a way for all of this to occur during the session? Currently all logging takes place once the session is closed.
Thanks for your time, sorry for the wall of text.
edit: I'd like to be able to accomplish this in the standard Python interpreter for portability purposes.
edit2: Jaime's snippet works very well for logging everything I need. Any way, though, that I can have it do so in real time, instead of waiting for the session to close?
edit3: Figured it out :). The final, working snippet:
import code
import sys
class Tee(object):
def __init__(self, log_fname, mode='a'):
self.log = open(log_fname, mode)
def __del__(self):
# Restore sin, so, se
sys.stdout = sys.__stdout__
sys.stdir = sys.__stdin__
sys.stderr = sys.__stderr__
self.log.close()
def write(self, data):
self.log.write(data)
self.log.flush()
sys.__stdout__.write(data)
sys.__stdout__.flush()
def readline(self):
s = sys.__stdin__.readline()
sys.__stdin__.flush()
self.log.write(s)
self.log.flush()
return s
def flush(foo):
return
sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')
console = code.InteractiveConsole()
console.interact()
I've only tested this in python2.7. I don't have 3 handy.
import code
import sys
class Tee(object):
def __init__(self, log_fname, mode='a'):
self.log = open(log_fname, mode)
def __del__(self):
# Restore sin, so, se
sys.stdout = sys.__stdout__
sys.stdir = sys.__stdin__
sys.stderr = sys.__stderr__
self.log.close()
def write(self, data):
self.log.write(data)
sys.__stdout__.write(data)
def readline(self):
s = sys.__stdin__.readline()
self.log.write(s)
return s
# Tie the ins and outs to Tee.
sys.stdout = sys.stderr = sys.stdin = Tee('consolelog.dat', 'w')
console = code.InteractiveConsole()
console.interact()
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