Problem with Pdb

Hi there

I’m sometimes frustrated when debugging iterators because pdb terminates with StopIteration.
When you run the following sample code, typing [n]ext on the last iteration line (a), causes pdb to stop unintentionally and the process continues to run. To continue pdb there, you need to type [s]tep instead of [n]ext.
A similar situation occurs for GeneratorExit

I’m not sure if this is designed or not, but I’d like to report this to the issue tracker as a future enhancement. Is there any possibility of improvement?

# foo.py
def test():
    for x in range(1):  # (a)
        yield x         # (b)

breakpoint()
u = list(test())  # pdb terminates with StopIteration at (a)?
v = next(test())  # pdb terminates with GeneratorExit at (b).
print(u, v)

Tests:

C:\temp>py -3.11 foo.py
> c:\temp\foo.py(6)<module>()
-> u = list(test())  # pdb terminates with StopIteration?
(Pdb) s
--Call--
> c:\temp\foo.py(1)test()
-> def test():
(Pdb) n
> c:\temp\foo.py(2)test()
-> for x in range(1):  # (a)
(Pdb) n
> c:\temp\foo.py(3)test()
-> yield x         # (b)
(Pdb) n
> c:\temp\foo.py(2)test()
-> for x in range(1):  # (a)
(Pdb) n
[0] 0

Can you post a stdout trace of your steps (and what you expected at each separate step) since it’s not clear to me from your description which actions you actually performed or what you expected? I tried a few things and found nothing unexpected when running your script in pdb.

Thank you for your reply @hansgeunsmeyer,

The inputs are:

s
n
n
n
n

and the whole output is the one I posted above. With the last [n] pdb stops to run, which results in the final output line: [0] 0.

If the inputs are

s
n
n
n
s

the last [s] makes pdb return from the function and stop at the next point to break. The outcome is what I expected for [n]ext:

(Pdb) s
--Return--
> c:\temp\foo.py(2)test()->None
-> for x in range(1):  # (a)

Ok, but what do you find strange about this? This is exactly what I would expect.

Fair enough. The design for generator functions may be something like that.
What I feel strange is that when I type [s]tep it actually runs as [n]ext, and when I type [n]ext it quits.

If you do ‘s’, you step into whatever call is going to be made. Pdb explicitly indicates when it’s making a ‘Call’ and ‘Return’, as in this case, so the pdb output for that last ‘s’ step makes sense to me (at that point your still inside the first function call).
If you are stepping through a regular (non-generator) function, pdb will also stop at the ‘Return’ point and indicate what the return value of the function is, before actually going to the next line. So, there is nothing happening that is fundamentally different – at least not that I can see:

def test(x):
      return x
breakpoint()
x = test(1)
print(x)

Gives:

> /tmp/t.py(6)<module>()
-> v = test(1)
(Pdb) s
--Call--
> /tmp/t.py(2)test()
-> def test(x):
(Pdb) s
> /tmp/t.py(3)test()
-> return x
(Pdb) s
--Return--
> /tmp/t.py(3)test()->1
-> return x
(Pdb) s
> /tmp/t.py(7)<module>()
-> print(v)
(Pdb)