Date

Debugging a program with Python pdb is trivial. You just run import pdb; pdb.set_trace() (or just breakpoint() introduced in Python 3.7), and the debugger will take action.

However, when the program being debugged has a stdin redirection, this is a source of trouble. This happens because your program may be reading, for instance, input with input() (which comes from file because of the redirection) and, when entering the debugger, it continues to read what is on the file as commands to Pdb, which almost certainly is not what you want.

More specifically, Python uses sys.stdin for functions such as input(). The pdb module, which contains Pdb class, uses the cmd module, which contains Cmd. Cmd, by itself, uses input(), which is why you have the behaviour described above. Pdb class accepts a stdin kwarg, but for Cmd to accept stdin, you must set use_rawinput to False, which is only set by Pdb when you also set stdout.

The most common shells has 3 file descriptors already passed to every command run from console, which are stdin (fd 0), stdout (fd 1) and stderr (fd 2). This comes from UNIX.

A common Python program reads its input (for instance, when you run input() to read the content a user might type) from fd 0, which the shell is telling stdin by default. When you run something like this

$ python3 <file.txt

the input of your program comes not from what you type, but from what it's in the file. In effect, the command above is the same as

$ python3 0<file.txt

at least for the most common shells.

So, to the solution. The first and the most obvious way is not to use stdin redirection but to open the file normally with open(). In this case, the file is hardcoded in the file. The second way is to read the file name from the command-line interface, but involves more boilerplate than the next solution.

The third solution is to read from another fd other than the 3 default fd's already supplied by default (see above). So you can use something like this:

import sys
sys.stdin = open('/dev/fd/3')

When using the debugger, as said above, you have to specify you're going to use stdin explicly. Otherwise, Pdb, which uses Cwd, will use what you set sys.stdin to. So, instead of import pdb; pdb.set_trace() as suggested by the documentation, do:

import pdb; pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__).set_trace()

at the point you want to breakpoint. Don't forget to import sys if you didn't already done.

sys.__stdin__ is what sys.stdin is set when you run Python. Now, on the shell, to run your program, you do something like this:

$ python3 3<file.txt

and that's it. Now your program are reading the file from fd 3, and your fd 0 is freed to be used by Pdb.