I recently had a problem that I could not for the life of me figure out. It was one of those issues that you know a mistake in the code is causing, but it throws no errors. It just doesn’t do what you expect it to. I finally realized I needed to debug django using pdb. In the course of figuring out this problem, I learned how to:
- Setup Python’s pdb debugger with Django
- Navigate through code using the debugger commands
- Fork a repository and use it in my requirements.txt file
I was using django-allauth and django-rest-auth to do social authentication through my REST API. The whole flow was using OAuth2, and I got it working fine up to the point that the social platform returned data to Django in the backend. There were two pieces of the returned token the code did not save to the database: refresh_token and expires_in. Why?
There were no errors. I couldn’t find anyone else who was having this problem. Nothing on Stackoverflow. Was I crazy?
Probably. But that’s beside the point – there was something wrong with the code. So I turned to something I hadn’t really used before – the python debugger.
Setup Python’s pdb debugger with Django
Fortunately, it’s pretty straightforward to install pdb. It’s installed in your version of python already – all you have to do is import it as a module. In my case, since I was using it with Django, I imported it like so:
python -m pdb manage.py runserver
If you’re familiar with Django, you know that the ‘runserver’ command will get Django running locally. With this command you’ll have pdb up and running.
There is one step before this. If you’re like me, you are using pdb because you feel there’s something wrong in the code you’re using but you can’t figure out where. So you need to set a breakpoint at the closest place you think the problem is. For me, I set a breakpoint in my views.py file.
import pdb #you'll likely put this somewhere at the top of your file
Excellent. You’ve set up pdb by having it run when you run your Django instance and placed a breakpoint in your code. You’re ready to debug Django using pdb!
Navigate through code using the debugger commands
Once my breakpoint was set, I was ready to debug django using pdb. I triggered the breakpoint by calling the view (aka the associated endpoint). The terminal was interrupted by pdb and I was presented with a location I could insert the pdb commands.
There are a few commands that I found essential for troubleshooting my instance:
Of course, you can read more here about debugging using pdb, if you like. I’m just going to go over these commands because they were the most helpful for me.
The ‘list’ command prints out the 11 lines of code around where you currently are. In my case, it printed the code in my view.
The ‘pp’ command “pretty prints” any defined variable in the code. You can’t see the value of a variable that hasn’t been set yet.
The step command goes to the next possible place the code will execute. So if you’re on a line that calls a function, it will move into that function, line by line, and any function that’s inside that function. I used this only if I needed to follow where the code was going.
The ‘next’ command moves to the next line of code, so is a little less detailed than the ‘step’ command. This is useful if you don’t want to follow a function call deeper into the code.
Can also be shortened to ‘r’, this command will return whatever function you are currently in. Useful if you used the step command to go deeper into a function but want to just get out to the parent function.
Continues executing the program; drops you out of the pdb interface.
This exits out of pdb..
In my case, the refresh_token and expires_in keys are supposed to be passed by django-rest-auth to django-allauth. Turns out django-rest-auth was inadvertently stripping those values out of there completely, leaving the corresponding spots in the database completely blank. I opened an issue on github about it, then later found that someone had already created a pull request related to the same issue.
Fork a repository and use it in my requirements.txt file
At this point I needed to apply this fix to my codebase. I ultimately decided to fork django-rest-auth into my own set of repositories and use that in my codebase, with my patch applied.
The way to do this is by editing the requirements.txt file to look like this:
I’ve included another line to show you what the requirements.txt file usually looks like. You can also find some more info about requirements.txt here.
One of the big complicating factors was that I was using Django inside a Docker container for development instead of running it locally. I had to modify my settings.py file to get Django running locally and then I used Postman to actually make the REST endpoint calls. I felt like I really upgraded my debugging skills in Python and solved a problem that’s been bothering me for a while. Let me know how you would have tackled this problem and if you have any ways of debugging python applications that are running within Docker containers!