How to setup your project with pre-commit, black, and flake8
Tags: python, tutorial
Published: 2019-11-18 16:20:34

## Why pre-commit Git hooks?

Several OpenStax Python projects use Git hooks via [pre-commit][pre-commit] in order to run formatting and linting checks before the commit process. This approach has some really nice advantages:

* IDE agnostic
* Runs automatically on only the code that is changing.
* Feedback on linting or formatting issues happens before you commit.
* Enforces style consistency in the codebase.
* Helps create smaller diffs.

## Why Black?

[Black][black] is a highly opinionated code formatter. Black focuses on reformatting your code files in place for you. When you're comfortable with black taking over the minutiae of hand formatting you will see that you can focus more on the content of your code than formatting it properly.

## Why Flake8?

[Flake8][flake8] is a wrapper around various Python linting tools used to check for conformance against the PEP8 style guidelines for Python. This helps make sure that your code is using a consistent style across the entire project.

## How to install pre-commit and the proper config files

### Install pre-commit

We first need to install pre-commit onto the system. You can refer to the [pre-commit][pre-commit] website for more in-depth information. We'll focus on the necessary commands to get things installed.

If you are using OSX you can install pre-commit using brew:

    `brew install pre-commit`

You can also install pre-commit into your python virtualenv:

    `pip install pre-commit`

### Configure Black

Create a `pyproject.toml` file in the root of the project directory, if it doesn't exist, and copy the following into the file:

```
    [tool.black]
    py36 = true
    include = '\.pyi?$'
    exclude = '''
    /(
        \.git
      | \.hg
      | \.mypy_cache
      | \.tox
      | \.venv
      | _build
      | buck-out
      | build
      | dist
    
      # The following are specific to Black, you probably don't want those.
      | blib2to3
      | tests/data
    )/
```

### Configure Flake8

Create a `.flake8` in the root of the project directory, if it doesn't exist, and add the following to the file:

```
    [flake8]
    ignore = E203, E266, E501, W503, F403, F401
    max-line-length = 89
    max-complexity = 18
    select = B,C,E,F,W,T4,B9
```

### Configure pre-commit

Now that we have the proper files in place we can start using pre-commit to run black and flake8 git hooks.

Create a `.pre-commit-config.yaml` file in the root of the project directory, if it doesn't exist, and add the following to the file:
```
    # See https://pre-commit.com for more information
    # See https://pre-commit.com/hooks.html for more hooks
    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.0.0
          hooks:
          - id: flake8
```

### Install the hooks

Install the git hooks defined in the pre-commit file by running the following in the terminal:

    `pre-commit install`

### Run the hooks

If this is an already existing project you may want to go ahead and format all the files. You can do this by running the following in the terminal:

    `pre-commit run --all-files`

This will run all the git hooks you've installed against all files. At this point you can review the messages and make corrections as necessary. You can re-run the command until there are no longer any warnings.

Finally, commit all the new changes! From now on when you stage files to be committed only those will be formatted and linted by black and flake8. Say goodbye to forgetting to run those linting commands and having Travis CI blow up.

[pre-commit]: https://pre-commit.com/#intro
[black]: https://github.com/python/black
[flake8]: http://flake8.pycqa.org/en/latest/