Improve your Django experience with IPython

IPython is an improved Python shell for interactive use. It has many great features such as syntax highlighting, autocomplete, and powerful “magic commands”. I love it, use it on every project, and use the IPython prompt for examples on my blog.
IPython has too much goodness to cover here. Check out its tutorial for an introduction.
To use IPython with Django, simply install it:
$ python -m pip install ipython
(Or add to your project’s requirements file.)
Now Django’s shell
will automatically use IPython:
$ ./manage.py shell
Python 3.9.1 (default, Jan 21 2021, 09:04:53)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.20.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from db_buddy.core.models import Server|
Server
ServerKind
ServerManager
In this example, I typed Server
then pressed “Tab” and IPython opened a drop-down of possible names to import.
IPython’s debugger
IPython also comes with an improved version of Python’s pdb
debugger, with colorization and other features. Inside the IPython shell, if you code raises an exception, you can open the IPython debugger with the %debug
magic command:
In [1]: def divide(x, y):
...: return x/y
...:
In [2]: divide(1,0)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-3-4fffc6193274> in <module>
----> 1 divide(1,0)
<ipython-input-2-97054f827698> in divide(x, y)
1 def divide(x, y):
----> 2 return x/y
3
ZeroDivisionError: division by zero
In [3]: %debug
> <ipython-input-2-97054f827698>(2)divide()
1 def divide(x, y):
----> 2 return x/y
3
ipdb> x
1
ipdb> y
0
In this session, I first added the divide()
function and then ran it, and it crashed. At In [3]
I typed %debug
, which started the IPython debugger at the line of code that raised the ZeroDivisionError
exception. This is the post_mortem()
pdb method.
The debugger showed the function with an arrow pointing at the line of code that raised the exception. I then checked the values of the x
and y
variables.
Using pdb, and by extension ipdb, is a skill in itself. For more information, check out:
Using IPython’s debugger outside of IPython
You can use IPython’s debugger outside of its shell by installing the wrapper package ipdb
:
$ python -m pip install ipdb
Now you can start the debugger similar to pdb
:
import ipdb
ipdb.set_trace()
But, since Python 3.7, the new breakpoint()
built-in is the best way to start a debugger. This allows you to use an alternative debugger with the same syntax, maybe even with per-project customization.
By default breakpoint()
uses pdb
, but we can make it use ipdb
by setting the PYTHONBREAKPOINT
environment variable. You can do this at the top of your manage.py
:
#!/usr/bin/env python
import os
import sys
from pathlib import Path
os.environ["PYTHONBREAKPOINT"] = "ipdb.set_trace"
def main():
...
Now if you need to start the debugger at some point in your code, you can add a call to breakpoint()
. For example in a view:
def index(request):
breakpoint()
return render(request, "index.html")
Nice.
Using IPython’s debugger in tests
Django’s test framework has a --pdb
flag to open a debugger on test failure. It will automatically use ipdb
once you’ve installed it.
pytest has a similar --pdb
flag. You can configure --pdb
to use the IPython debugger by setting the --pdbcls
flag. This is most conveniently done in the addopts
setting in your pytest.ini
(or other configuration file):
[pytest]
addopts = --pdbcls=IPython.terminal.debugger:TerminalPdb
Great!
Learn how to make your tests run quickly in my book Speed Up Your Django Tests.
One summary email a week, no spam, I pinky promise.
Related posts:
Tags: django