When contributing to Django, you’ll want to run its test suite to check your changes. The official contributing docs cover setup in Running the unit tests, using a virtual environment and pip. Here’s an alternative guide using uv.
I previously announced my Python optimization workshop in Lisbon, on 10th October (which still has a few places). I am now pleased to add a Python/Django meetup on the Thursday before.
Back in January, I introduced tprof, a targeting profiler for Python 3.12+ that measures the time spent in specific functions, rather than your whole program. As a reminder, here’s the basic usage, specifying a target function with -t and a script to run:
time-machine is my library for mocking the current date and time in Python tests. Its headline advantage over freezegun, the library that inspired it, is speed.
time-machine is my library for mocking the current date and time in Python tests. I’ve just released version 3.3.0 with a decent number of changes, so here’s a lovely summary for you.
When you use a unittest.mock mock, you often make assertions on the calls it received, such as through the mock_calls list. But sometimes you want to assert on the order of calls across multiple mocked functions, for example to check that steps in a process happen in the right sequence.
In several programs, I’ve wanted to solve the problem of associating extra data with an object. For example, in django-upgrade, the individual “fixer” functions often want to store extra data per visited ast.Module object.
Back in February, I encountered an out-of-memory error while migrating a client project to Python 3.14. The issue occurred when running Django’s database migration command (migrate) on a limited-resource server, and seemed to be caused by the new incremental garbage collection algorithm in Python 3.14.
Profilers measure the performance of a whole program to identify where most of the time is spent. But once you’ve found a target function, re-profiling the whole program to see if your changes helped can be slow and cumbersome. The profiler introduces overhead to execution and you have to pick out the stats for the one function you care about from the report. I have often gone through this loop while optimizing client or open source projects, such as when I optimized Django’s system checks framework (previous post).
When testing code that outputs to the terminal through either standard out (stdout) or standard error (stderr), you might want to capture that output and make assertions on it. To do so, use contextlib.redirect_stdout() and contextlib.redirect_stderr() to redirect the respective output streams to in-memory buffers that you can then inspect and assert on.
Sometimes, it’s useful to branch the behaviour of your code based on the version of a package that you have installed. This may be to support an upgrade in your project, or for your own package to support different versions of a dependency.
If you’ve written a Python script that outputs a lot of data, then piped that output into another command that only reads part of it, you might have encountered a BrokenPipeError. For example, take this script:
A neat testing pattern is writing common tests in a base class and then applying them to multiple objects through subclassing. Doing so can help you test smarter and cover more code with less boilerplate.