— 2 min read


Some time back in April 2013 I was bored and looking for a new project to keep my attention, if only for a short period of time.

My colleague @codeinthehole had an idea but no time to implement it, this idea was to have shields like those of travis-ci (shown below) but displaying package download counts.

Status of blackhole on Travis CI

Tech stack

From the very start I decided to use Tornado framework, although this may change in the future.

The original plan was to generate the images using Pillow (PIL) and then simply cache them to disk. I decided it would make far more sense to do this using Varnish and not have to worry about it working as expected.

Manually generating the images

The images were originally generated from a base template using Pillow, but sadly Python’s image manipulation is not very good, especially it’s text manipulation and the shields could have really used a bit of work.

I reached out to the shields project but sadly got no response so the images remained as they were.

crate.io shuts down

Sadly crate.io stopped being a custom PyPI mirror in mid December which meant I had to rewrite the codebase to use the official PyPI JSON API. In doing so I lost the ability to get download counts for all versions or a specific version and instead, could only get a count by day, week or month.

It was while changing this functionality that I stumbled upon a ticket from the shields project mentioning my shields and their poor artistic styling. The ticked mentioned an public API for generating these images.

After switching to this API I quickly found from PyPI Pin users on Twitter that there was an issue in their API, specifically with version number formats. Version numbers with a format of X.X.X worked fine but X.XX did not. I can only assume that many other formats didn’t work either.


While trying to find the source code for shields.io on GitHub I found what they consider a newer, better version.

I promptly switched to PyPI Pins to use this and queried the authors on GitHub to make sure the API was meant to be public and usable, thankfully it was.

Eggs, wheels and licenses

With this new found image API and the wealth of data in the PyPI JSON API I quickly decided to leverage it as much as I could and thus the egg, wheel and license shields were created.

The tech stack remains the same, I still cache all successful image requests using Varnish to limit the impact on my Tornado servers and on the shields.io service. I look forward to adding more shields and functionality in the future.

You can access this set of services on PyPI Pins.


Anarchist. Pessimist. Bipolar. Hacker. Hyperpolyglot. Musician. Ex-(semi-)pro gamer. They/Them.

View Source