Recent Posts (Page 2)

Python: capture stdout and stderr in unittest

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.

Read more...

Git: count files in a repository

When you want to count the number of files within a Git repository, it's generally best to use Git itself for the task because it will skip over any generated or downloaded files. Here is a command chain to use to count all committed files within the current directory:

Read more...

Django: write a custom URL path converter to match given strings

Here’s a little tip based on some recent work. The project has a URL pattern where the first part of the URL matches the current role the user is viewing the site as. Let’s say the roles are “chef”, “gourmand”, and “foodie”—example URLs might look like this:

Read more...

Python: check a package version with importlib.metadata.version()

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.

Read more...

Django: split ModelAdmin.get_queryset() by view

Within Django’s popular admin site, you can override ModelAdmin.get_queryset() to customize the queryset used by the admin views. It’s often used for performance optimizations, such as adding a select_related() call to batch-fetch related objects:

Read more...

Django: iterate through all registered URL patterns

I’ve found it useful, on occasion, to iterate through all registered URL patterns in a Django project. Sometimes this has been for checking URL layouts or auditing which views are registered.

Read more...

Git: find the largest commits

Recently, I was working in a new repository and found the git blame output often pointed back to a large repository-wide formatting commit (applying Black to all Python files). To ignore this commit in git blame, I added its SHA to a .git-blame-ignore-revs file, per this documentation:

Read more...

Python: fix BrokenPipeError when piping output to other commands

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:

Read more...

Git: share a full repository as a file with git fast-export

Typically, we share repositories through a Git host, like GitHub, allowing others to clone the repository to get a copy. But sometimes that’s not an option, for example when trying to get someone started on your project when corporate onboarding processes take days to grant GitHub access.

Read more...

Django: hide the development server warning

From Django 5.2 (April 2025), the runserver management command outputs a warning:

Read more...

Django: Introducing inline-snapshot-django

I recently released a new package called inline-snapshot-django. It’s a tool for snapshot testing SQL queries in Django projects, described shortly.

Read more...

Python: sharing common tests in unittest

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.

Read more...

Python: a quick cProfile recipe with pstats

Python comes with two built-in profilers for measuring the performance of your code: cProfile and profile. They have the same API, but cProfile is a C extension, while profile is implemented in Python. You nearly always want to use cProfile, as it’s faster and doesn’t skew measurements as much.

Read more...

Git: list checked-in symlinks

Git supports storing symbolic links (symlinks) in your repository, which are filesystem links that point to another file or directory. These are great for when you want to have the same file at multiple locations in your repository, such as some configuration file that is used for multiple sub-projects. But how can you list all the symlinks in your repository?

Read more...

GitHub Actions: avoid double runs from on: [push, pull_request]

I’ve often seen a GitHub Actions workflow defined with a trigger like:

Read more...

Docker: disable “What’s next” adverts

On a client project today, I noticed that running docker exec -it tacks this advert on the end of the output:

Read more...

pre-commit: install with uv

pre-commit is my favourite Git-integrated “run things on commit” tool. It acts as a kind of package manager, installing tools as necessary from their Git repositories. This makes it fairly easy to set up: all you need to install is pre-commit itself, and it takes things from there.

Read more...

Git: fix a filename case collision

You may encounter this warning when cloning a Git repository:

Read more...

Docker: remove obsolete version keys from Compose files

If you use Docker Compose, you may see this message:

Read more...

Django: model field choices that can change without a database migration

Adam Hill posted a question on Mastodon: he wants a model field that uses choices that doesn’t generate a database migration when the choices change. This post presents my answer. First, we’ll recap Django’s default behaviour with choice fields, a solution with callable choices, and the drawbacks.

Read more...

Python type hints: mixin classes

In Python, a mixin class is a class that is not intended to be used directly, but instead “mixed in” to other classes through multiple inheritance. Mixins are not really a language feature but more of a conventional pattern allowed by Python’s multiple inheritance rules. Unfortunately, adding type hints to mixin classes can be tricky because they implicitly require subclasses to fit a certain shape.

Read more...

GitHub: render GitHub-Flavored Markdown with the API

GitHub-Flavored Markdown (GFM) is GitHub’s variant of Markdown, with extra features like task lists and alert boxes. It’s used in issues, pull requests, comments, and many other places on GitHub.

Read more...

Django: what’s new in 5.2

Django 5.2 was released last Wednesday, another exciting step forward for our favourite web framework. It comes with a composite 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...

Zsh: clear the “You have mail“ message

Do you see this message when you open a new terminal session?

Read more...

Boost Your Git DX now has a free sample

Last week, I released the second update to my book Boost Your Git DX. Today I’m happy to announce that I have released a free sample of the book.

Read more...