<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=338168267432629&amp;ev=PageView&amp;noscript=1">
Programming

Debugging Python With PDB

Debugging code isn’t always fun but it doesn’t have to be difficult.


“Where is this error coming from??  Everything looks like it should work but it just isn’t!!”  We’ve all been in this situation at one point or another.  Debugging code isn’t always fun but it doesn’t have to be difficult.

 

The first tool that I reach for when I find myself confused by an error while working with Python is the built-in package ‘pdb’ or The Python Debugger.  With this handy tool we are able to slowly step through our code, examining each variable and line of code, to find out where the code fails and why.  

 

Let’s use the following Django view to examine how this tool can help speed things up while debugging.

 

def future_age(current_age):
    age_in_five = current_age + 5
    return age_in_five

class test_view(DetailView):
    def post(self, request):
        current_age = request.POST.get('age')
        aged = future_age(current_age)
        return render(request, 'test_template.html', {'age_in_five': aged}

In this view, the user may enter their current age and when they submit this information should be presented with how old they will be in 5 years.  It’s a straightforward block of code but for some reason, we are presented with an error every time we attempt to enter our age on the template form.  We have, of course, tested the ‘future_age’ function and it works as would be expected, however in the context of everything that is happening it keeps failing!  Frustrating!

 

Let’s introduce ‘pdb’ now and figure out what is going on.

 

import pdb

def future_age(current_age):
    age_in_five = current_age + 5
    return age_in_five

class test_view(DetailView):
    def post(self, request):

    pdb.set_trace()
    current_age = request.POST.get('age')
    aged = future_age(current_age)
    return render(request, 'test_template.html', {'age_in_five': aged}

 

The next time that we enter an age (i.e. 33) into the form on our template we will notice that the code stalls and we can observe the following in the terminal:

-> current_age = request.POST.get(‘age’)

Now we can start to figure out what is causing the error.  The basic ‘pdb’ commands are as follows:

  • p <expression>
    • Prints the value of the expression in its current context
  • n
    • Executes the current line and moves on to the next line of code in the current function
  • s
    • Executes the current line and stops at the next opportunity whether that is the next line in the current function or the first line in a function that is called.
  • c
    • Continues execution of the code until it either hits another breakpoint or returns
  • q
    • Quits the debugger and the code being executed is aborted



Where we currently stand within the code we may want to check just to make sure that the correct age is being grabbed from the request.  So we enter our pdb print statement to check the value of the ‘current_age’ variable like so:

 

p current_age

 

And run into another error!

 

*** NameError: name 'current_age' is not defined

This is because ‘pdb’ stops executing the code at the beginning of the line following the ‘pdb.set_trace()’ statement so ‘current_age’ has not been set yet.  In order to ensure that the ‘current_age’ variable is being set correctly we can use the ‘n’ command in the terminal and ‘pdb’ will execute the current line of code and move on to the next line of code within the current function.  We will then be presented with the following in the terminal:

-> aged = future_age(current_age)

We are now able to use the previous pdb print statement to check the value of the ‘current_age’ variable.

p current_age
‘33’

 

If we look closely we can see that the value of current_age is a string of ‘33’.  Here we may already see why we are getting an error.  If it is not obvious here, however, we have another option.  By using the ‘s’ command we are able to step into the ‘future_age’ function that is called on the next line.

s
-> def future_age(current_age):
s
-> age_in_five = current_age + 5
P
Current_age
'33'

By stepping into the function that is called it may become more obvious what is going on. Thanks to ‘pdb’ we can see that the function ‘future_age’ is, in its current context, attempting to add the integer 5 to the string ‘33’ which causes a TypeError and is the reason that this specific view is failing to work the way that it was intended. With this knowledge in hand, we can make the necessary changes to ensure that our code will run correctly the next time. To exit out of The Python Debugger mode we can use either the ‘c’ command which will run until the code returns or it hits any other pdb.set_trace() statements or can simply quit code execution with the ‘q’ command.

The Python Debugger is a powerful tool when used correctly. It can help us quickly diagnose variables that have unexpected values or even just see where our code is failing to execute to the next line so that we can hone in on a specific area of the code. The ‘pdb’ package has other useful commands and functions beyond the ones listed here so make sure to give the official documentation a read if attempting to debug your code in other useful ways.

 

Official PDB Documentation


Similar posts

Get notified about the latest in Tech

Be the first to know about new tech from the experts at Bixly!