Projects

I have created or maintain a number of open source projects, this is a list of the most noteworthy.

"" Actively Maintained ""

apig-wsgi

PyPI

Wrap a WSGI application in an AWS Lambda handler function for running on API Gateway or an ALB.

I wrote this while working at Time Out to help build an AWS Lambda based Django application. Existing solutions for the problem, such as Zappa, required complete control over the application deployment, while we already had a defined deployment pipeline using Ansible (roughly like this blog post). Therefore I created this open source layer to translate the AWS API Gateway requests back and forth to WSGI, allowing any standard Python web application to be deployed on Lambda.

blacken-docs

PyPI

Run Black on Python code blocks in documentation files.

Anthony Sottile wrote this project in 2018. I took over its maintainence end of 2022. It’s a neat tool that I use to format code examples in my blog and books. It has the nice side effect of ensuring the examples have valid syntax.

Djade

PyPI

A Django template formatter.

See the introductory blog post.

django-browser-reload

PyPI

Automatically reload your browser in development.

See the introductory blog post.

django-cors-headers

PyPI

A Django App that adds Cross-Origin Resource Sharing (CORS) headers to responses.

I took over maintenance of this from the creator Otto Yiu in 2016 and have shepherded it through many releases since. It adds CORS headers and is by far the most used package I maintain.

django-harlequin

PyPI

Launch Harlequin, the SQL IDE for your Terminal, with your Django database configuration.

Harlequin is a Terminal-based SQL IDE. This package provides a Django management command to launch Harlequin for your Django-defined databases.

django-htmx

PyPI

Extensions for using Django with htmx.

htmx extends HTML to allow you to build complex features without any JavaScript. I co-authored this package with Niccolò Cantù to provide useful extensions to Django for working with htmx.

django-linear-migrations

PyPI

Ensure your migration history is linear.

An extension to Django’s migrations framework to make migrations easier to handle. See my introductory blog post.

django-minify-html

PyPI

Use `minify-html &LThttps://github.com/wilsonzlin/minify-html>`__, the extremely fast HTML + JS + CSS minifier, with Django.

A middleware to minify your HTML. See my introductory tweet thread.

Django-MySQL

PyPI

Django-MySQL is a non-inventively named package that helps you use some MySQL/MariaDB-specific features in the world of Django.

This is my biggest self-made project, and what gained me the most attention from the Django community for my invitation as a core contributor.

django-perf-rec

PyPI

Keep detailed records of the performance of your Django code.

This was based off some code I helped develop at YPlan. I was given permission to open source it, which I did at the PyCon UK 2017 sprints, although with some heavy re-factoring.

django-permissions-policy

PyPI

Set the draft security HTTP header Permissions-Policy on your Django app.

I created this at Genus AI while working to get the web platform to an A+ score on securityheaders.com. It adds control over the header Permissions-Policy, which at time of writing is still experimental.

django-read-only

PyPI

Disable Django database writes.

This is based on a technique we had at YPlan, but rewritten to use Django’s database instrumentation. It can be useful to activate it for interactive sessions, so you don't accidentally modfiy your database.

django-rich

PyPI

Extensions for using Rich with Django.

Rich provides tools for nice terminal output. This package helps you use Rich within Django.

django-upgrade

PyPI

Automatically upgrade your Django projects.

Automated source code rewriter for upgrading Django projects.

django-version-checks

PyPI

System checks for your project’s environment.

django-version-checks adds several system checks that can help ensure that the current environment has the right versions of Python, databases, etc. This is useful when coordinating upgrades across all your infrastructure. See my introductory blog post.

ec2-metadata

PyPI

An easy interface to query the EC2 metadata API, with caching.

I wrote this while at Time Out to fill in a gap where AWS' library boto provided an interface to the EC2 Metadata Service while the new version boto3 doesn't.

flake8-comprehensions

PyPI

A flake8 plugin that helps you write better list/set/dict comprehensions.

I was given permission to write this as a plugin at YPlan through our "Friday Afternoon Time" initiative to find and fix some common performance-impacting comprehension issues we found across the YPlan codebase.

flake8-logging

PyPI

A Flake8 plugin that checks for issues using the standard library logging module.

I wrote this package after fixing a “silent failure” issue with logging on a client project. I added more rules based on the guidance in the logging module’s documentation and my experience.

flake8-no-pep420

PyPI

A flake8 plugin to ban PEP-420 implicit namespace packages. *

Implicit namespace packages are folders containing Python files but without an __init__.py file. They’re valid in Python since PEP-420, but many code quality tools don’t discover them - at least coverage.py, Django’s test runner, and Mypy without --namespace-packages. After hitting such problems several times I wrote this plugin to prevent implicit namespace packages on projects that don’t need them.

flake8-tidy-imports

PyPI

A flake8 plugin that helps you write tidier imports.

Similar to the above, this was also created at YPlan to improve code quality, and later to ban some imports when migrating to Python 3.

heroicons

PyPI

Use heroicons in your Django and Jinja templates.

A Python package for using this great icon set. See my blog post introducing it.

patchy

PyPI

Patch the inner source of python functions at runtime.

This is a real hack, but we used it at YPlan to modify just a few of Django's innards without having to fork it. I gave a lightning talk on it at PyCon UK 2015. Since publishing, my ex-colleague Tom Grainger has fixed a lot of its edge cases.

pygments-git

PyPI

Pygments lexers for Git output and files.

I created this to nicely highlight examples in my writings about Git.

pytest-flake8-path

PyPI

A pytest fixture for testing flake8 plugins.

Used for testing my flake8 plugins such as flake8-comprehensions. The successor to pytest-flake8dir, using pathlib.Path instead of the old py lib py.path class, following pytest’s example.

pytest-randomly

PyPI

pytest plugin to randomly order tests and control random.seed.

I wrote this plugin at YPlan to improve the test suite and was given permission to open source it. I've written a blog post covering its history.

pytest-restrict

PyPI

pytest plugin to restrict the test types allowed.

A pretty niche pytest plugin, we used this to defend the YPlan test suite against non-internal TestCase classes being inadvertently used in tests, which could break assumptions from our other testing tools.

pytest-reverse

PyPI

pytest plugin to reverse test order.

A small plugin to reverse test order. Inspired by a user issue on pytest-randomly that pointed to a paper suggesting reversal is almost as effective as random ordering for discovering non-isolated tests.

time-machine

PyPI

Travel through time in your tests.

A library for mocking the current date and time in tests. See my blog post introducing it.

treepoem

PyPI

Barcode rendering for Python.

My colleagues Christian Muirhead and Julius Seporaitis created this package when we worked together at YPlan. I have maintained it since because I think it’s pretty useful. It wraps a neat tool called BWIPP (Barcode Writer in Pure Postscript).

unittest-parametrize

PyPI

Parametrize tests within unittest TestCases.

I created this to provide an API like pytest’s parametrization decorator for unittest test cases.


💀 No Longer Maintained 💀

django-capture-on-commit-callbacks

PyPI

Capture and make assertions on transaction.on_commit() callbacks.

Read more in my blog post The Fast Way to Test Django transaction.on_commit() Callbacks.

django-settings-file

PyPI

Let Django use settings from an arbitrary Python file instead of an importable module.

I wrote this as an investigation based on an idea posted by Jamesie Pic on the django-developers mailing list. It was useful as a maintenance "canary," for example when testing new Django versions, but it was never popular.

flake8-no-types

PyPI

A flake8 plugin to ban type hints.

I wrote this while working on a codebase with type hints but no MyPy setup, which meant many of the hints had bitrotted to be fairly wrong. I figured it would be better to have no hints rather than wrong hints. This isn’t really true though, as many python libraries, like dataclasses, require type hints to function. It’s better to run Mypy.

kwargs-only

PyPI

A decorator to make a function accept keyword arguments only, on both Python 2 and 3.

This was useful for making functions more robust for callers by not accepting positional arguments. For example, it's used in the timezonefinder library to avoid users mixing the 'longitude' and 'latitude' arguments, which have varying conventions on order. I no longer maintain it because it's only needed on Python 2, because Python 3 has native syntax (def func(*, foo=1)).

mariadb-dyncol

PyPI

Pack/unpack Python dicts into/out of MariaDB’s Dynamic Columns format.

I wrote this during PyCon UK 2016 as a way of supporting this JSON-like data type in Django-MySQL and got great support from David R. MacIver in the sprints testing it with Hypothesis. It was a fun exercise implementing a serializer/deserializer of a binary format in pure Python, optimizing it to run quickly, and discovering many bugs with Hypothesis' property-based testing.

I stopped maintaing it though since it was never popular. The Dynamic Columns data type is a niche MariaDB feature, no longer really developed. JSON is a better cross-DB alternative.

multilint

PyPI

Run multiple python linters easily.

I made this to make my open source projects more consistent, by applying the same linters to the same sets of paths easily. I've stopped maintaining it since I use the much more powerful pre-commit to lint my projects now.

nose-randomly

PyPI

Nose plugin to randomly order tests and control random.seed.

I wrote this plugin at YPlan to improve the test suite and was given permission to open source it. I've written a blog post covering its history and that of its successor pytest-randomly. I stopped maintaining it because Nose itself is no longer maintained. I recommend pytest as an alternative.

pytest-flake8dir

PyPI

A pytest fixture for testing flake8 plugins.

Used for testing my flake8 plugins such as flake8-comprehensions. Succeeded by pytest-flake8-path.

pytest-is-running

PyPI

pytest plugin providing a function to check if pytest is running.

Useful for doing stuff only if pytest is/is not running. Retired because it doesn’t provide much value over checking if pytest has been imported.

pytest-super-check

PyPI

pytest plugin to check your TestCase classes call super in setUp, tearDown, etc.

Another plugin open sourced from YPlan. Django's TestCase does some magic to mean you don't need to call super() in your setUp(), but this can mean forgetting to call it when it's needed inheriting from subclasses of TestCase. This plugin runs a simple check that all setUp() (and related) methods call super(), regardless of whether it's needed. I now think this would be better implemented as a lint rule.

Sound Resynthesis with a Genetic Algorithm

GitHub

This is the source code for my final year thesis at Imperial College. I haven't tried to run it since 2011 but I put it on GitHub as some readers emailed me asking for it, and the thesis is in the repository too.

tox-py

PyPI

Adds the --py flag to tox to run environments matching a given Python interpreter.

A little tox plugin, this made it easy to set up my preferred CI setup. With the release of tox 4 in December 2022, it became redundant, as tox gained an option to do basically the same thing.