Introducing multilint

Clean crystals

I maintain a few Python projects on Github + PyPI. I try to keep them as consistent and error-free as possible and thus running code quality tools (known as ‘linters’) such as flake8 and isort to ensure this happens. I also discovered the lesser known python setup.py check which has found a number of problems I otherwise wouldn’t have found until release time - highly recommended!

One problem with these tools is invoking them all - they all have different command line flags and behaviour. One tool that I use to ensure code is compatible between Python 2 & 3, python-modernize, isn’t even a proper linter, and thus doesn’t output a failure code when it finds something to change (in its ‘diff mode’).

To run them all together I hacked together a script in each project. Many started out with just flake8 and isort, then I’d later add another, e.g. python setup.py check, updating the wrapper script in one project with code copied from another project. Of course this copy/paste lead to duplication and edits that made it hard to track what was going on and ironically to keep all the projects consistent.

Whenever you’re copy/pasting in programming, it’s best to question why! I ended up packaging this script into a new utility that runs flake8, isort, and all the other linters I run on the same set of files. It’s called multilint!

Once installed (pip install multilint), you just need to configure the paths it lints with a [tool:multilint] section in your setup.cfg, for example:

[tool:multilint]
paths = mylib
        setup.py
        tests

Then, when you run multilint, it will invoke all the linters it knows about (that are installed) on those files.

I use it on all of my Python projects now and will continue to maintain it for any new linters or options that come along. Right now it just passes some default options to the linters, which can be otherwise configured with files e.g. a [flake8] section in your setup.cfg.

Check it out on Github.


Tags: python