Setting up flake8 for Cython

Jul 03, 2018 | Cython , Python

I like enabling flake8 on my Python projects. It helps prevent a lot of "does this code look pretty" arguments with contributors. These arguments feel like bike-shedding because they are very subjective and almost everyone has a different idea of what "pretty" means.

Disagreeing on such matters often feels petty. At the end of the day, you want your codebase to look consistent. Multiple definitions of "pretty" in one codebase does not help with that.

Standardizing on a set of rules and letting a script enforce them is nice. If you hook it up to your CI server, it's easy to end such discussions with a "hey it's not me, it's the robots that are complaining".

This morning I enabled flake8 on streaming-form-data. Now, most of the code in this repository is written in Cython, which is not strictly Python, but a strange mix of C and Python. And since it's a mix with some Python in there, I would still like to have flake8 do its thing so that the codebase looks consistent.

Making files visible

Cython files have the .pyx extension, which flake8 seems to ignore by default. This can be easily fixed by adding a tox.ini file in your project directory with the following contents.

[flake8]
filename = *.py, *.pyx

This instructs flake8 to include .pyx files in addition to the default .py ones in the list of files it's going to check.

Avoiding false positives

Since Cython has a slightly different syntax than Python, it gets confused about reporting violations on perfectly normal Cython code.

As an example, let's look at error E225. PEP8 defines this error code to be raised on "missing whitespace around operator".

So something like a = b * c would fail this check, since PEP8 would like to see some spaces between * and c (or b and *).

But the situation is slightly different in Cython, because now a * could refer to pointers. A statement like cdef const char *ptr is declaring a pointer variable. And no, it does not mean we're multiplying char and ptr 🤦‍♂️ . But flake8 does not know that.

What I'd like to do here is to tell flake8 to ignore certain warnings for specific files. Unfortunately, flake8 does not have native support for this (yet). But what it does have is support for plugins. And luckily, someone wrote a plugin for exactly this situation.

flake8-per-file-ignores lets you associate filenames with error codes you'd like to ignore in those files. This can be done by adding a per-file-ignores setting to your tox.ini, so it looks something like the following.

[flake8]
filename = *.py, *.pyx
per-file-ignores =
    streaming_form_data/_parser.pyx: E225, E226

This instructs flake8 to not report errors E225 and E226 in streaming_form_data/_parser.pyx. For all other files, flake8 defaults to the standard rules.