Pre-commit hooks in Python

Pre-commit hooks can help reduce code style discrepancies amongst a code base by performing checks on each contributors git repo before they commit code and push to the remote server.

What can be done on the client before commiting and pushing?
This client side check can performan many things:
- format code (check line length and style)
- check imports
- check white space consistency
- check newline and end of file
Most of these checks are mundane when done consistently, but annoying if not infuriating when done inconsistently. Infuriating may be an exxageration, but repeated inconsistencies take mental effort to notice and deal with. It can break the flow of contribution and isn't something to spend time worry about.
It doesn't have to be tedious.
Git hooks and Pre-commit
https://pre-commit.com/ is the documentation for a wonderful package. Let's let them explain it!
Introduction
Git hook scripts are useful for identifying simple issues before submission to code review. We run our hooks on every commit to automatically point out issues in code such as missing semicolons, trailing whitespace, and debug statements. By pointing these issues out before code review, this allows a code reviewer to focus on the architecture of a change while not wasting time with trivial style nitpicks.
As we created more libraries and projects we recognized that sharing our pre-commit hooks across projects is painful. We copied and pasted unwieldy bash scripts from project to project and had to manually change the hooks to work for different project structures.
We believe that you should always use the best industry standard linters. Some of the best linters are written in languages that you do not use in your project or have installed on your machine. For example scss-lint is a linter for SCSS written in Ruby. If you’re writing a project in node you should be able to use scss-lint as a pre-commit hook without adding a Gemfile to your project or understanding how to get scss-lint installed.
We built pre-commit to solve our hook issues. It is a multi-language package manager for pre-commit hooks. You specify a list of hooks you want and pre-commit manages the installation and execution of any hook written in any language before every commit. pre-commit is specifically designed to not require root access. If one of your developers doesn’t have node installed but modifies a JavaScript file, pre-commit automatically handles downloading and building node to run eslint without root.
Quick start
1. Install pre-commit
Follow the install instructions above pre-commit --version should show you what version you're using
pre-commit --version
pre-commit 2.13.0
2. Add a pre-commit configuration
Create a file named .pre-commit-config.yaml You can generate a very basic configuration using pre-commit sample-config Yhe full set of options for the configuration are listed below This example uses a formatter for python code, however pre-commit works for any programming language Other supported hooks are available
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-toml
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:
- id: black
3. Install the git hook scripts
Run pre-commit install to set up the git hook scripts
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
Now pre-commit will run automatically on git commit!
4. (optional) Run against all the files
It's usually a good idea to run the hooks against all of the files when adding new hooks (usually pre-commit will only run on the changed files during git hooks)
$ pre-commit run --all-files
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/psf/black.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/psf/black.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
Check Yaml...............................................................Passed
Fix End of Files.........................................................Passed
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- exit code: 1
Files were modified by this hook. Additional output:
Fixing sample.py
black....................................................................Passed
Oops! looks like I had some trailing whitespace Consider running that in CI too
Conclusion
Pre-commits are an excellent tool to automate the mundane sources of inconsistencies amongst our individual and team projects. The above just scratches the surface.