And I’ve answered my own question! It’s the “debug” command in pydb:
~> cat -n /tmp/test_python.py
1 #!/usr/local/bin/python
2
3 def foo():
4 print "hi"
5 print "bye"
6
7 exit(0)
8
~> pydb /tmp/test_python.py
(/tmp/test_python.py:7): <module>
7 exit(0)
(Pydb) debug foo()
ENTERING RECURSIVE DEBUGGER
------------------------Call level 11
(/tmp/test_python.py:3): foo
3 def foo():
((Pydb)) s
(/tmp/test_python.py:4): foo
4 print "hi"
((Pydb)) s
hi
(/tmp/test_python.py:5): foo
5 print "bye"
((Pydb)) s
bye
------------------------Return from level 11 (<type 'NoneType'>)
----------------------Return from level 10 (<type 'NoneType'>)
LEAVING RECURSIVE DEBUGGER
(/tmp/test_python.py:7): <module>