How can I debug manually typed expression and statements in pdb?
Asked Answered
D

2

11

In pdb (or ipdb) we can execute statements and evaluate expressions with the ! or p commands:

p expression
     Evaluate the expression in the current context and print its value.

[!]statement

     Execute the (one-line) statement in the context of the current stack frame. The exclamation point can be omitted unless the first word of the statement resembles a debugger command. To set a global variable, you can prefix the assignment command with a global command on the same line

So, for example, I can type p reddit.get_subreddits() while debugging in ipdb and the code will be executed in the current context and I will see the return value.

Is there a way I can debug the execution of such "manually typed" expressions?

Basically I would like to do is s reddit.get_subreddits(), but that just executes the step command and ignores the expression.

EDIT: A trivial example

Take this simple function:

import random

def get_value_for_weekday(weekday_index=None):
    values = [10, 20, 20, 10, 30, 30, 30]
    if not weekday_index:
        # If no weekday provided, return the average of all weekdays
        return sum(values) / 7
    return averages[weekday_index]

if __name__ == '__main__':
    while True:
        import ipdb; ipdb.set_trace()  # enter ipbd for debug
        get_value_for_weekday(random.randint(0, 7))

Which is bugged because of the if not weekday_index (it should check weekday_index is not None.)

Let's assume I notice I get 10 half the number of times I was expecting. So I added a import ipdb; ipdb.set_trace() before the call to the function to try and debug the code.

So I'm in the ipdb console and I suddenly get the idea that maybe the problem is when I pass 0 as weekday_index. I can test my hypothesis directly in ipdb:

ipdb> p get_value_for_weekday(0)
22

Ok, so I realize there's something wrong when weekday_index=0.
What I would like to do now is debug step by step the call to get_value_for_weekday(0), so that I could see that I erranously enter the if block.

Obviously I could exit ipdb, stop the script, change the code to always pass 0, relaunch the script and when I enter ipdb, debug the call with the ipdb step (s) command.
But wouldn't it be easier if I could just do s get_value_for_weekday(0) much the same way I was able to do p get_value_for_weekday(0)?

Is there a way do something like this?

Deckard answered 13/1, 2016 at 14:47 Comment(2)
Could you give a more tangible examble which I could reproduce? I'm having a bit of a hard time understanding what exactly you're looking for.Atomic
Added an example, I hope it makes thing clearer.Deckard
A
15

I think you're looking for the (d)ebug command which, for some reason, is not specified in the Debugger Commands. Just for future reference, pdb has a nice set of commands specified (which you can see by typing help in the interactive prompt). On to the debug command:

(Pdb) help debug
debug code
        Enter a recursive debugger that steps through the code
        argument (which is an arbitrary expression or statement to be
        executed in the current environment).

Which seems to do what you're after. Using your sample script from the terminal:

python -m pdb pdbscript.py

After issuing two n commands in order for the function to get parsed (I believe this is how pdb works). You can issue a debug get_value_for_weekday(0) command to recursively step in the function:

(Pdb) debug get_value_for_weekday(0)
ENTERING RECURSIVE DEBUGGER
> <string>(1)<module>()
((Pdb)) s
--Call--
> /home/jim/Desktop/pdbscript.py(3)get_value_for_weekday()
-> def get_value_for_weekday(weekday_index=None):
((Pdb)) n
> /home/jim/Desktop/pdbscript.py(4)get_value_for_weekday()
-> values = [10, 20, 20, 10, 30, 30, 30]
((Pdb)) n 
> /home/jim/Desktop/pdbscript.py(5)get_value_for_weekday()
-> if not weekday_index:
((Pdb)) p weekday_index
0
((Pdb)) n
> /home/jim/Desktop/pdbscript.py(7)get_value_for_weekday()
-> return sum(values) / 7

Do note, I feel really sketchy about this form of meta-debugging but it seems to be what you're after.

Atomic answered 18/1, 2016 at 21:16 Comment(4)
This seems to be exactly what I was looking for!Deckard
@Deckard I'm glad! Like I noted though, I really feel weird about embedded debuggers; thinking about them makes my head hurt a bit.Atomic
Good answer. Out of curiosity, what is it about embedded debuggers that makes you feel uncomfortable? :)Prudenceprudent
From (Pdb) help I could not figure out how to save a variable value in a new one. With this answer I was able to do it with debug newvar = oldvar and because you linked the docs I found the much cleaner ! newvar = oldvar. Thank you!Colan
C
1

With regards to your example, you don't need to exit pdb and change the code. You can step into the function (with 's') and set weekday_index=0 inside.

One solution to your original problem is to use the debugger's jump command as follows:

  1. jump before the function call using 'j #line-number'
  2. step in the function with 's'
  3. set the input params, and continue debugging.

This worked when I tried it, but the debugger complained when I tried to do step 3 before step 2 for some reason.

Confection answered 16/1, 2016 at 22:1 Comment(4)
I don't necessarily want to debug a function call I will step into it later, maybe another function call (one I will not step into but could have side effects or help me understand the code in some way). I guess my example was not that good.Deckard
I see. I'm not sure if this is possible with ipdb.Confection
A different solution to your problem is to use the debugger's jump command as follows: (1) jump before the function call using 'j #line-number' (2) step in the function with 's' (3) set the input params and continue debugging.Confection
Can you add that to the answer?Deckard

© 2022 - 2024 — McMap. All rights reserved.