With pdb
you can use nice combination of break function
and until lineno
:
Without argument, continue execution until the line with a number
greater than the current one is reached.
With a line number, continue execution until a line with a number
greater or equal to that is reached. In both cases, also stop when the
current frame returns.
Changed in version 3.2: Allow giving an explicit line number.
You can achieve what you needed.
I modified your example a bit (so you would see that instruction gets executed although pdb reports it as "next instruction"):
01: class A(object):
02:
03: def __init__(self):
04: self.X = []
05:
06: def f(self):
07: print('pre exec')
08: for i in range(10):
09: self.X.append(i)
10: print('post exec')
11:
12: a = A()
13: a.f()
14: print('Game is over')
15:
And result from running with python -m pdb test.py
goes like this:
Start debugging and run it just after class declaration (so you can add named breakpoint):
> d:\tmp\stack\test.py(1)<module>()
-> class A(object):
(Pdb) until 11
> d:\tmp\stack\test.py(12)<module>()
-> a = A()
Now, break at the beginning of function:
(Pdb) break A.f
Breakpoint 1 at d:\tmp\stack\test.py:6
Just continue with execution until it hits breakpoint:
(Pdb) continue
> d:\tmp\stack\test.py(7)f()
-> print('pre exec')
Take advantage of "also stop when the current frame returns":
(Pdb) until 14
pre exec
post exec
--Return--
As you can see, both pre exec and post exec were printed, but when executing where
you are still in f()
:
(Pdb) w
c:\python32\lib\bdb.py(405)run()
-> exec(cmd, globals, locals)
<string>(1)<module>()
d:\tmp\stack\test.py(13)<module>()
-> a.f()
> d:\tmp\stack\test.py(10)f()->None
-> print('post exec')
> d:\tmp\stack\test.py(10)f()->None
-> print('post exec')
And all context variables are intact:
(Pdb) p self.X
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Now with your real life example:
01: class A(object):
02: def __init__(self):
03: self.X = []
04:
05: def f(self):
06: for i in range(10):
07: self.X.append(i)
08:
09: a = A()
10: a.f()
11: print('Game is over')
Start the similar fashion as before:
> d:\tmp\stack\test.py(1)<module>()
-> class A(object):
(Pdb) until 8
> d:\tmp\stack\test.py(9)<module>()
-> a = A()
(Pdb) break A.f
Breakpoint 1 at d:\tmp\stack\test.py:5
(Pdb) cont
> d:\tmp\stack\test.py(6)f()
-> for i in range(10):
Now... Breakpoint in f.A
actually means breakpoint at first statement of f.A
which is unfortunately for i in...
so it would break on it every time.
If you don't actually start your real code with loop, you can skip this part.
(Pdb) disable 1
Disabled breakpoint 1 at d:\tmp\stack\test.py:5
Again, use the until <end of file>
:
(Pdb) until 10
--Return--
> d:\tmp\stack\test.py(6)f()->None
-> for i in range(10):
And again, all frame variables are available:
(Pdb) p i
9
(Pdb) w
c:\python32\lib\bdb.py(405)run()
-> exec(cmd, globals, locals)
<string>(1)<module>()
d:\tmp\stack\test.py(10)<module>()
-> a.f()
> d:\tmp\stack\test.py(6)f()->None
-> for i in range(10):
(Pdb)
The sad thing here is, that I wanted to try this piece of automation:
(Pdb) break A.f
Breakpoint 1 at d:\tmp\stack\test.py:5
(Pdb) commands 1
(com) disable 1
(com) until 11
(com) end
Which would do everything you need automatically (again, disable 1
not needed when you have at least one pre-loop statement), but according to documentation on commands
:
Specifying any command resuming execution (currently continue, step, next, return, jump, quit and their abbreviations) terminates the command list (as if that command was immediately followed by end). This is because any time you resume execution (even with a simple next or step), you may encounter another breakpoint–which could have its own command list, leading to ambiguities about which list to execute.
So until
just doesn't seem to work (at least for Python 3.2.5 under windows) and you have to do this by hand.