Git Hook for Code Formatting with Black and flake8

by Tykling


23. oct 2019 23:15 UTC


I use the code code-formatter Black to format code in some of my repositories, for example Certgrinder and SocialRating. I also use flake8 as a linter/code quality checker. This post is about automating running Black and flake8 in a git pre-commit hook, so I don't forget to run it and accidently commit some code that will need reformatting later.

Pre-commit

I use the package pre-commit to do the heavy lifting here:

(venv) user@privat-old:~/devel/certgrinder$ pip install pre-commit black flake8
Collecting pre-commit
  Using cached https://files.pythonhosted.org/packages/5b/e2/70050edecec542122bd32789b2c4563d578e0152c0f338f7870b7627afeb/pre_commit-1.18.3-py2.py3-none-any.whl
Collecting black
  Using cached https://files.pythonhosted.org/packages/30/62/cf549544a5fe990bbaeca21e9c419501b2de7a701ab0afb377bc81676600/black-19.3b0-py36-none-any.whl
Collecting flake8
  Downloading https://files.pythonhosted.org/packages/26/de/3f815a99d86eb10464ea7bd6059c0172c7ca97d4bdcfca41051b388a653b/flake8-3.7.8-py2.py3-none-any.whl (70kB)
     || 71kB 3.1MB/s 
Requirement already satisfied: pyyaml in ./venv/lib/python3.7/site-packages (from pre-commit) (5.1.2)
Requirement already satisfied: virtualenv>=15.2 in ./venv/lib/python3.7/site-packages (from pre-commit) (16.7.7)
Requirement already satisfied: six in ./venv/lib/python3.7/site-packages (from pre-commit) (1.12.0)
Requirement already satisfied: identify>=1.0.0 in ./venv/lib/python3.7/site-packages (from pre-commit) (1.4.7)
Requirement already satisfied: importlib-metadata in ./venv/lib/python3.7/site-packages (from pre-commit) (0.23)
Requirement already satisfied: nodeenv>=0.11.1 in ./venv/lib/python3.7/site-packages (from pre-commit) (1.3.3)
Requirement already satisfied: toml in ./venv/lib/python3.7/site-packages (from pre-commit) (0.10.0)
Requirement already satisfied: aspy.yaml in ./venv/lib/python3.7/site-packages (from pre-commit) (1.3.0)
Requirement already satisfied: cfgv>=2.0.0 in ./venv/lib/python3.7/site-packages (from pre-commit) (2.0.1)
Requirement already satisfied: appdirs in ./venv/lib/python3.7/site-packages (from black) (1.4.3)
Requirement already satisfied: attrs>=18.1.0 in ./venv/lib/python3.7/site-packages (from black) (19.3.0)
Requirement already satisfied: click>=6.5 in ./venv/lib/python3.7/site-packages (from black) (7.0)
Collecting pyflakes<2.2.0,>=2.1.0
  Using cached https://files.pythonhosted.org/packages/84/f2/ed0ffb887f8138a8fe5a621b8c0bb9598bfb3989e029f6c6a85ee66628ee/pyflakes-2.1.1-py2.py3-none-any.whl
Collecting pycodestyle<2.6.0,>=2.5.0
  Downloading https://files.pythonhosted.org/packages/0e/0c/04a353e104d2f324f8ee5f4b32012618c1c86dd79e52a433b64fceed511b/pycodestyle-2.5.0-py2.py3-none-any.whl (51kB)
     || 51kB 3.5MB/s 
Collecting entrypoints<0.4.0,>=0.3.0
  Downloading https://files.pythonhosted.org/packages/ac/c6/44694103f8c221443ee6b0041f69e2740d89a25641e62fb4f2ee568f2f9c/entrypoints-0.3-py2.py3-none-any.whl
Collecting mccabe<0.7.0,>=0.6.0
  Downloading https://files.pythonhosted.org/packages/87/89/479dc97e18549e21354893e4ee4ef36db1d237534982482c3681ee6e7b57/mccabe-0.6.1-py2.py3-none-any.whl
Requirement already satisfied: zipp>=0.5 in ./venv/lib/python3.7/site-packages (from importlib-metadata->pre-commit) (0.6.0)
Requirement already satisfied: more-itertools in ./venv/lib/python3.7/site-packages (from zipp>=0.5->importlib-metadata->pre-commit) (7.2.0)
Installing collected packages: pre-commit, black, pyflakes, pycodestyle, entrypoints, mccabe, flake8
Successfully installed black-19.3b0 entrypoints-0.3 flake8-3.7.8 mccabe-0.6.1 pre-commit-1.18.3 pycodestyle-2.5.0 pyflakes-2.1.1
(venv) user@privat-old:~/devel/certgrinder$ 

I also added pre-commit and Black and flake8 to requirements-dev.txt as I will only be needing these packages for development.

Pre-Commit Config

A pretty simple config to tell pre-commit to run Black and flake8 before each commit:

(venv) user@privat-old:~/devel/certgrinder$ cat .pre-commit-config.yaml 
repos:
  - repo: "https://github.com/ambv/black"
    rev: "stable"
    hooks:
    - id: "black"
      language_version: "python3.7"
  - repo: "https://github.com/pre-commit/pre-commit-hooks"
    rev: "v2.3.0"
    hooks:
    - id: "flake8"

flake8 Config

To make Black and flake8 play nice I need a short config to tell flake8 to ignore a few errors:

(venv) user@privat-old:~/devel/certgrinder$ cat .flake8 
[flake8]
max-line-length = 88
ignore = E501 W503
(venv) user@privat-old:~/devel/certgrinder$ 

Install Hooks

Actually installing the hooks is easy:

(venv3) user@privat-old:~/devel/certgrinder$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
(venv3) user@privat-old:~/devel/certgrinder$ 

Trying It Out

The only thing left to do is to see if it runs my hook when I commit:

(venv) user@privat-old:~/devel/certgrinder$ git commit -m "add flake8"
[INFO] Stashing unstaged files to /home/user/.cache/pre-commit/patch1571922885.
black....................................................................Passed
Flake8...................................................................Failed
hookid: flake8

certgrinder.py:791:5: F841 local variable 'E' is assigned to but never used

[INFO] Restored changes from /home/user/.cache/pre-commit/patch1571922885.

Clearly flake8 is not happy. Fortunately it tells me on which line the problem is so I can fix it quickly. After fixing the issue I stage the new change and try the commit again:

(venv) user@privat-old:~/devel/certgrinder$ git add certgrinder.py 
(venv) user@privat-old:~/devel/certgrinder$ git commit -m "add flake8"
black....................................................................Passed
Flake8...................................................................Passed
[master 3d2074f] add flake8
 4 files changed, 35 insertions(+), 15 deletions(-)
 create mode 100644 .flake8
(venv) user@privat-old:~/devel/certgrinder$ 

Yay!

Search this blog

Tags for this blogpost