45

I have a python script that reads stdin via a pipe, and I cannot seem to use it with pdb.set_trace().

my_script.py:

#!/usr/bin/env python
import sys
import pdb

def main():
    for line in sys.stdin:
        print "Printing a line: " +line

if __name__=='__main__':
    status = main()

Suppose tempfile.csv is some file with two lines,

$ cat tempfile.csv 
line1
line2

then I can run my script with: $ cat tempfile.csv | ./my_script.py, and everything is fine:

$ cat tempfile.csv | ./my_script.py 
Printing a line:  line1

Printing a line:  line2

On the other hand, if I put pdb.set_trace() anywhere then I get an error. For example, putting pdb.set_trace() below def main(), then I get

$ cat tempfile.csv | ./my_script.py 
> /home/ilangmore/mobiuss/TM/branches/hadooprotype/my_script.py(7)main()
-> for line in sys.stdin:
(Pdb) *** NameError: name 'line1' is not defined
(Pdb) *** NameError: name 'line2' is not defined
(Pdb) 
Traceback (most recent call last):
  File "./my_script.py", line 11, in <module>
    status = main()
  File "./my_script.py", line 7, in main
    for line in sys.stdin:
  File "./my_script.py", line 7, in main
    for line in sys.stdin:
  File "/usr/lib/python2.7/bdb.py", line 48, in trace_dispatch
    return self.dispatch_line(frame)
  File "/usr/lib/python2.7/bdb.py", line 67, in dispatch_line
    if self.quitting: raise BdbQuit
bdb.BdbQuit

Note that my question is probably related to this question (i.e. pdb by default reads from stdin), but I need more help.

Community
  • 1
  • 1
Ian Langmore
  • 2,819
  • 5
  • 21
  • 20

6 Answers6

28

Here's an example of what worked for me:

import sys
import pdb

lines = sys.stdin.readlines()
sys.stdin = open("/dev/tty")
pdb.set_trace()

Edit: since 3.7 you no longer need to import pdb for set_trace, it is available as breakpoint, so the above only requires a sys import.

import sys

lines = sys.stdin.readlines()
sys.stdin = open("/dev/tty")
breakpoint()

You may wish to replace sys.stdin.readlines() above with the iterable fileinput.input() (which defaults to sys.stdin if the list of files in sys.argv[1:] is empty) like so:

import fileinput
import sys

lines = fileinput.input()
sys.stdin = open("/dev/tty")
breakpoint()
Louis Maddox
  • 5,226
  • 5
  • 36
  • 66
Carl Smith
  • 710
  • 1
  • 8
  • 11
  • I had same issue and this worked great. Anyone know why? – unclejamil Mar 06 '16 at 02:35
  • 4
    Pdb reads from stdin to be interactive; so to use pdb you must first read all stdin, then set stdin to be the teletype interface or in otherwords hook it up back to your terminal and keyboard instead of the shell pipe. At that point you can start pdb like normal (and use it) – ThorSummoner May 24 '16 at 20:39
  • 3
    I used: `import sys; sys.stdin = open('/dev/tty'); import pdb; pdb.set_trace()` – Louis M Oct 11 '17 at 15:14
  • doesn't work for me, I get `site-packages/prompt_toolkit/application/application.py", line 654, in _run_async2 assert not self._is_running AssertionError` and then after it crashes out my terminal is unusable – Anentropic May 20 '19 at 20:28
  • I tell a lie - that happens with `ipdb` but it works fine with `pdb` – Anentropic May 20 '19 at 20:33
  • As Anentropic found it, this does not seem to work with `ipdb`, can anyone explain why? – David S. Mar 29 '20 at 21:36
5

Using the ripdb module (pip install ripdb) solved this issue for me.

C. Reed
  • 2,382
  • 7
  • 30
  • 35
5

The thing is: cat will not stop sending data because your script is currently debugging. And when you going to trace, then stdin is still filled by cat + your keyboard. You need to choose one of them.

You can read the whole stdin, and then, set_trace() will be not filled by stdin:

sys.stdin.read()
pdb.set_trace()
tito
  • 12,990
  • 1
  • 55
  • 75
  • 3
    This seems to help but not completely. I put sys.stdin.read() in a few places, and pdb.set_trace() below, and I no longer get the NameError. However, pdb doesn't open...it just exits (same message as above, without the NameError) – Ian Langmore Feb 07 '12 at 16:14
3

For completeness, I made a snippet with the following code, based on the accepted answer.

import sys; sys.stdin = open('/dev/tty'); import pdb; pdb.set_trace();
Andrei Cioara
  • 3,404
  • 5
  • 34
  • 62
2

You may want to look at how the Celery RDB (Remote Debugger) contrib module works:

https://github.com/celery/celery/blob/master/celery/contrib/rdb.py

It seems to involve a lot of stream processing, but I have tested it, and it works by allowing you to telnet into a new local network port. It's not the much better ipdb, but simply pdb.

Nate Ferrero
  • 1,408
  • 14
  • 15
1

I ran into this exact problem today. I found that Winpdb works perfectly.

thyme
  • 480
  • 7
  • 16