Recent Posts

See also posts by tag or search with DuckDuckGo:

Python: spy on function calls with unittest.mock’s wraps

Testing terminology distinguishes between different kinds of test doubles, including:

Read more...

Django: release code words up to 6.1

Did you know that each Django release has a “code word” associated with it? It’s hidden in plain sight, in the announcement blog post describing the list of features coming in the next version. I think this is a lovely little tradition.

Read more...

Django: introducing django-crawl

I recently migrated one of my client projects from the legacy django-csp package to Django 6.0’s built-in Content Security Policy (CSP) support (release note). This security header is a powerful tool for preventing unwanted content from being loaded on your site, so configuration correctness is paramount. The migration was fairly straightforward, but a few pages had complicated overrides, so I wanted to be sure that no CSP headers had been changed by my swapping of CSP implementations.

Read more...

Django: introducing django-orjson

Just as cars painted red are known to be faster, libraries implemented in Rust are also known to be faster. Today’s example is orjson, a Rusty replacement for Python’s built-in json module, boasting 10x faster serialization and 2x faster deserialization.

Read more...

Python: find all instances of a class with gc.get_objects()

Here’s a lovely hack that I’ve used when machete-mode debugging.

Read more...

Python: store extra data for objects in a WeakKeyDictionary

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.

Read more...

Django: introducing django-integrity-policy

Back in January, Firefox’s Security & Privacy Newsletter for 2025 Q4 piqued my interest with this mention:

Read more...

Django: fixing a memory “leak” from Python 3.14’s incremental garbage collection

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.

Read more...

Python: introducing profiling-explorer

I’ve made another package! Like icu4py, which I made in February, it was sponsored by my client Rippling. And like tprof, which I made in January, it’s a profiling tool!

Read more...

Python: introducing icu4py, bindings to the Unicode ICU library

I made a new package! Thank you to my client Rippling for inspiring and sponsoring its development.

Read more...

Django: profile memory usage with Memray

Memory usage can be hard to keep under control in Python projects. The language doesn’t make it explicit where memory is allocated, module imports can have significant costs, and it’s all too easy to create a global data structure that accidentally grows unbounded, leaking memory. Django projects can be particularly susceptible to memory bloat, as they may import many large dependencies like numpy, even if they’re only used in a few places.

Read more...

Zsh: select generated files with (om[1]) glob qualifiers

I’ve recently been using memray, a memory profiler for Python, to optimize the startup memory usage (and time) for a client. It’s a fantastic tool, but its flexibility hampers getting instant feedback. It takes three commands to profile a program, generate a flame graph from the profile, and open the flame graph in the browser:

Read more...

Python: introducing tprof, a targeting profiler

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).

Read more...

Django Quiz 2025

Last month, I held another quiz at the December edition of Django London. The December quiz is an annual tradition at our meetup, a way of making this final event of the year more relaxed and giving away some nice prizes. This was the seventh quiz that I’ve presented, and the eighth overall.

Read more...

Django: implement HTTP basic authentication

Previously, we covered bearer authentication within HTTP’s general authentication framework. In this post, we’ll implement basic authentication, where the client provides a username and password.

Read more...

Django: what’s new in 6.0

Django 6.0 was released today, starting another release cycle for the loved and long-lived Python web framework (now 20 years old!). It comes with a mosaic of new features, contributed to by many, some of which I am happy to have helped with. Below is my pick of highlights from the release notes.

Read more...

Django: implement HTTP bearer authentication

HTTP has a general authentication framework that defines a pattern into which various authentication schemes can fit. Clients may provide an authorization request header that contains a credential. If authorization is missing or invalid, the server may respond with a 401 (Unauthorized) status code, including a www-authenticate header advertising what authentication schemes are supported. Otherwise, the server can respond with the authenticated resource.

Read more...

GitHub: top commands in gh, the official GitHub CLI

gh (pronounced… “guh”?) is GitHub’s official command line interface (CLI) tool. It lets you interact with GitHub directly from the command line, supporting most key features across more than 25 commands and over 200 subcommands. It’s also great for bridging the terminal-browser gap, allowing you to jump to pages relevant to your current context, such as the PR for the current branch.

Read more...

Django-related Deals for Black Friday 2025

Here are some Django-related deals for this year’s Black Friday (28th November) and Cyber Monday (1st December), including my own.

Read more...

“Boost Your GitHub DX” out now

My new book, Boost Your GitHub DX is out now!

Read more...

Django: Introducing django-http-compression

HTTP supports response compression, which can significantly reduce the size of responses, thereby decreasing bandwidth usage and load times for users. It’s a cheap and valuable technique for improving website performance.

Read more...

Django: Introducing django-watchfiles, for more efficient runserver autoreloading

Django’s runserver automatically reloads when you change Python files. Without this autoreloading feature, you’d need to manually restart the server every time you made a code change.

Read more...

Git: partially cherry-pick a commit

git cherry-pick allows you to copy a commit another branch to your current one. A common use case is copying a bug fix from a long-running feature branch to another one, so that it can be merged sooner, for example:

Read more...

Git: check if a commit exists on a given branch

To check if a commit SHA exists on a given branch, you have a couple of options.

Read more...

Python: fix SyntaxWarning: 'return' in a 'finally' block

Take this code:

Read more...