Pylint is a great linter, but it can be horrendously slow to run on anything but the most trivial of code bases.
While there are a multitude of configuration options that can be tweaked, the simplest approach is to only lint files that you have edited.
To this end, we can feed pylint
the list of files that have been modified. If you're doing this locally on your workstation you can lint the dirty files in the current working tree:
pylint `git diff --name-only --diff-filter=d | grep -E '\.py$' | tr '\n' ' '`
We use git diff
to get the list of dirty files in the current tree, and massage the output into something that pylint
can accept using pipes to grep
and tr
.
The regex-based filtering in the above expression – the grep
on the .py
file extension – can be omitted. Pylint won't try to lint non-Python source files, but you might as well not pass files at the source if you're able to.
The --name-only
argument specifies that we only want the file path, and the contents of the diff itself can be omitted from the output.
The --diff-filter
argument allows us to exclude deleted files with the lowercase d
value. there's no point in linting a file that is going to be removed, so we might as well avoid passing the path to pylint
. You could also omit renamed (r
) and copied files (c
), but I like to have those checked just in case they had preexisting lint warnings or errors that may have slipped through the cracks. If you run a full lint on the entire codebase regularly this is likely not necessary.
We can, of course, use the --staged
option to only lint those files that have been staged for commit:
pylint `git diff --name-only --diff-filter=d --staged | grep -E '\.py$' | tr '\n' ' '`
If we're in a remote CI setup we can extract out the list of modified files from the last commit using HEAD^
to refer to first parent of the tip of the branch in question, and lint that set of files:
pylint `git diff --name-only --diff-filter=d HEAD^ | grep -E '\.py$' | tr '\n' ' '`