如何记录在Python交互式Shell会话中发生的所有事件?


问题内容

我想实时访问解释器输入以及错误和标准输出。最好将此信息写入文件,以便在输入每个解释器命令后,我可以轮询文件以查找更改。例如,给定一个解释器会话:

>>> 5 * 7
35
>>> print("Hello, world!")
Hello, world!
>>> "Hello, world!"
'Hello, world!'

我想在日志文件中看到以下内容:

> 5 * 7
35
> print("Hello, world!")
Hello, world!
> "Hello, world!"
'Hello, world!'

格式并不重要;重要的是,我可以在文件中搜索关键字以触发会话期间的交互式事件。

到目前为止,我已学到了以下知识:

Python的code模块允许我创建一个InteractiveConsole对象,raw_input可以重新定义其方法以登录到文件,如下所示:

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

此外,InteractiveConsole使用内置write方法记录错误,我可以将其重新定义为:

def write(self, data):
  sys.stderr.write(data)
  self.file.write(data+'\n')

我还了解到以下代码片段将记录所有标准输出:

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()

我(试图)将所有这些组合在一起的尝试是创建一个LoggedConsole对象,然后将其传递给Tee本地人。

console = LoggedConsole(locals={sys.stdout:LoggedExec()})
console.interact()

(我以前没有通过本地人,所以也许我在这里做错了,但是没有收到错误。)

无论如何,这将打开一个新的Interactive
Console,并记录(关闭后)所有输入和错误,但不会记录输出。我已经为此撞了一段时间了,我觉得自己已经接近了,但也许还没有。

另外,有没有一种方法可以 会话 期间 进行所有这些操作?当前,所有日志记录都在会话关闭后进行。

感谢您的时间,对不起您的留言。

编辑:出于可移植的目的,我希望能够在标准的Python解释器中完成此操作。

edit2:Jaime的代码片段非常适合记录我需要的一切。但是,有什么办法可以让我实时进行操作,而不是等待会话关闭?

edit3: 想通了:)。 最后的工作片段:

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()

问题答案:

我仅在python2.7中对此进行了测试。我没有3方便。

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()