简体   繁体   中英

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. For example, pressing the up arrow produces ^[[A instead of the previous command.

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?

(1) You cannot have interactivity on the tee'd output because it's a regular stream, and not a terminal. 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. You can check that sys.stdout.isatty() returns True is you run a REPL.

(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 . This works in Python 3, and in Python 2.7 if you 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. 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:

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

It will write to the file something like 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.

I suppose pdb 's interactive mode will work under this, too; at the very least, Python REPL works fine under strace.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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