简体   繁体   English

重定向sys.stdout时,Python PDB交互模式中断

[英]Python PDB interactive mode breaks when redirecting sys.stdout

After replacing sys.stdout with a Tee logger (to redirect output to a file), PDB no longer works properly. Tee记录器替换sys.stdout (以将输出重定向到文件)后,PDB不再正常工作。 For example, pressing the up arrow produces ^[[A instead of the previous command. 例如,按向上箭头会产生^[[A而不是前一个命令。

The problem can be reproduced using this snippet: 可以使用以下代码段重现该问题:

import sys
import pdb

class Tee(object):
    def __init__(self, name, mode):
        self.file = open(name, mode)
        self.stdout = sys.stdout
        sys.stdout = self
    def __del__(self):
        sys.stdout = self.stdout
        self.file.close()
    def write(self, data):
        self.file.write(data)
        self.stdout.write(data)
    def flush(self):
        self.file.flush()

sys.stdout = Tee('test.txt', 'w')
pdb.set_trace()

Is there any way to replace sys.stdout without breaking PDB? 有什么办法可以在不破坏PDB的情况下替换sys.stdout

(1) You cannot have interactivity on the tee'd output because it's a regular stream, and not a terminal. (1)您不能在发球区域的输出上具有交互性,因为它是常规流,而不是终端。 A terminal allows to do a ton of things: position the cursor, erase contents, read keys, echo keypresses to the screen, etc. A regular file on a disk can't do all these things, this is why pdb fails to do these things in interactive mode. 终端可以做很多事情:定位光标,擦除内容,读取键,在屏幕上回显按键等等。磁盘上的常规文件不能完成所有这些事情,这就是为什么pdb无法做到这些交互模式下的事物。 You can check that sys.stdout.isatty() returns True is you run a REPL. 您可以检查sys.stdout.isatty()是否在运行REPL时返回True

(2) You can of course change every print function invocation in your code to write to stdout and to whatever file you want, because you can redefine print . (2)当然,您可以更改代码中的每个print 函数调用 ,以写入stdout 和所需的任何文件,因为您可以重新定义print This works in Python 3, and in Python 2.7 if you from __future__ import print . 如果您from __future__ import print ,这在Python 3和Python 2.7中都from __future__ import print Then you can do things like this: 然后,您可以执行以下操作:

system_print = print  # preserve the original.

def print_also_to(other_file):
  def tee_print(*args, **kwargs):
    system_print(*args, **kwargs)  # Normally prints to stdout.  
    system_print(*args, **kwargs, file=other_file)  # Write a copy.
  return tee_print

print = print_also_to(open('/tmp/copy-of-stdout'))  # A crude example.

print("Hello world!")  # Unmodified code.

With print statements , your situation is worse. 使用print 语句 ,您的情况会更糟。 Use strace on Linux or DTrace on macOS to capture the writing to stdout (and elsewhere) and redirect it to a file when starting your process: 在Linux上使用strace或在macOS 使用DTrace来捕获对stdout(以及其他地方)的写入,并在启动进程时将其重定向到文件:

strace -e trace=write -o writes.txt python your-script.py

It will write to the file something like write(1, 'Hello world!') . 它将类似write(1, 'Hello world!')文件。 You would need to parse it and reconstruct output to stdout (1) specifically to produce a real copy of the output. 您将需要对其进行解析并将输出重构为stdout(1),以专门生成输出的真实副本。

I suppose pdb 's interactive mode will work under this, too; 我想pdb的交互模式也可以在这种情况下工作。 at the very least, Python REPL works fine under strace. 至少,Python REPL在strace下可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM