Python’s not the strictest language, so to have any confidence in your code you need to hit it with a barrage of checks to ensure it at least meets some level of quality.

The tools I use are:

A fourth is Pytest, but this can take some time to run so I run it manually, and not automated – the exception being in deployment scripts (we can’t allow deployments if tests are failing).

When taking on a new or existing project, setting up these automated checks should be the first action to take.

Pre-commit hooks

This runs the checks locally on your development machine when you try to commit.

Install pre-commit.

Add the following .pre-commit-config.yaml file to the root of your repository.

fail_fast: true

  - repo:
    rev: 21.6b0
      - id: black
        args: [--diff, --check]

  - repo:
    rev: v3.0.0a3
      - id: pylint
        args: [--disable=all, --enable=unused-import]

  - repo:
    rev: v0.902
      - id: mypy
        exclude: ^tests/
        args: [--strict]

Install them as git hooks:

pre-commit install

Github Actions

This will run the checks when a pull request is created, allowing a reviewer to see any potential issues straight up before beginning their review.

Add the following to your repository in .github/workflows/checks.yml.

name: Checks
on: [pull_request]

    runs-on: ubuntu-latest
    name: Checks
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v2
        python-version: 3.x
    - run: |
        pip install --upgrade pip
        pip install black==21.6b0 pylint==v3.0.0a3 mypy==v0.902
        black --diff --check mypackage
        pylint --disable=all --enable=unused-import mypackage
        mypy --strict mypackage

Even though we’re running the same checks as in pre-commit, this can actually pick up errors that weren’t found in pre-commit, e.g. if you’ve created a file but forgotten to add it to the repository.


This will run final checks before deploying. These are the most important checks because this is your last line of defense. These checks should not be skippable.

Put the commands in your build script, before deploying.

set -e  # Stop on any error (you can also set this in the shebang)
black --diff --check /path/to/code
pylint --disable=all --enable=unused-import /path/to/code
mypy --strict /path/to/code
pytest /path/to/tests

Each of the commands will exit with a non-zero status if they find a problem, which will abort the script and should fail your build.


See also