0

Here is a sample python script.

import sys
print("Hello, world!")
for i, line in enumerate(sys.stdin):
    print(line)
    print(f"Before breakpoint: {i}")
    breakpoint()
    print(f"After breakpoint: {i}")

Running seq 1 10 | python tmp.py launches debugger at the specified breakpoint, however, it automatically reads all the stdin.

seq 1 10 | python tmp.py 
Hello, world!
1

Before breakpoint: 0
> .../tmp.py(9)<module>()
-> print(f"After breakpoint: {i}")
(Pdb) 2
(Pdb) 3
(Pdb) 4
(Pdb) 5
(Pdb) 6
(Pdb) 7
(Pdb) 8
(Pdb) 9
(Pdb) 10
(Pdb) 
Traceback (most recent call last):
  File ".../tmp.py", line 9, in <module>
    print(f"After breakpoint: {i}")
  File ".../tmp.py", line 9, in <module>
    print(f"After breakpoint: {i}")
  File ".../python3.10/bdb.py", line 90, in trace_dispatch
    return self.dispatch_line(frame)
  File ".../python3.10/bdb.py", line 115, in dispatch_line
    if self.quitting: raise BdbQuit
bdb.BdbQuit

How to stop breakpoint() from reading STDIN? i.e., I still want breakpoint() but just don't want it to automatically consume and execute STDIN. I looked into the docs[1] and it doesn't mention about this STDIN behavior, nor an option to disable it.


[1] https://docs.python.org/3.10/library/functions.html?highlight=breakpoint#breakpoint. I am using Python 3.10.9 on Ubuntu 20.04.6 LTS (WSL)

Thamme Gowda
  • 11,249
  • 5
  • 50
  • 57
  • 1
    PDB has to read from stdin otherwise you wouldn't be able to send commands to it. Some work arounds here https://stackoverflow.com/q/17074177/1032785 – jordanm Jun 06 '23 at 17:24

1 Answers1

0

Answering my own question. Thanks to the comments, and credits to this answer [1], here is a solution that works.

The trick is to attach TTY as STDIN/OUT/ERR for the PDB while leaving STDIN/OUT/ERR intact.

import sys

print("Hello, world!")

def tty_pdb():
    from contextlib import (_RedirectStream,
                            redirect_stdout, redirect_stderr)
    class redirect_stdin(_RedirectStream):
        _stream = 'stdin'
    with open('/dev/tty', 'r') as new_stdin, \
         open('/dev/tty', 'w') as new_stdout, \
         open('/dev/tty', 'w') as new_stderr, \
         redirect_stdin(new_stdin), \
         redirect_stdout(new_stdout), redirect_stderr(new_stderr):
        __import__('pdb').set_trace()

for i, line in enumerate(sys.stdin):
    print(line)
    print(f"Before breakpoint: {i}")
    tty_pdb()
    print(f"After breakpoint: {i}")

It's elegant -- no need to tweak the scripts that invoke python program! Credits to the author of [1] (I've already upvoted their answer).

[1] - https://stackoverflow.com/a/48430325/1506477

Thamme Gowda
  • 11,249
  • 5
  • 50
  • 57
  • On a second thought, I found VS Code debugger to be more helpful for debugging in this scenario. Easy to jump across frames/call stack. – Thamme Gowda Jun 11 '23 at 09:33