One of the easiest ways to make code more readable is to follow consistent style and formatting conventions.

Most Important Aspects

  • Consistency: follow the same standard.
  • Automation: formatting should be effortless after the initial configuration.

Tools

Black

  • A code formatter that (mostly) adheres to PEP8 convention.
  • Documentation

Configuration:

# pyproject.toml
 
[tool.black]
line-length = 120
include = '\.pyi?$'
exclude = '''
/(
      .eggs         # exclude a few common directories in the
    | .git          # root of the project
    | .hg
    | .mypy_cache
    | .tox
    | venv
    | _build
    | buck-out
    | build
    | dist
  )/
'''

iSort

  • Sorts and formats import statements inside Python scripts.
  • Documentation

Configuration:

# pyproject.toml
 
[tool.isort]
profile = "black"
line_length = 79
multi_line_output = 3
include_trailing_comma = true
virtual_env = "venv"

Flake8

  • A code linter with stylistic conventions that adhere to PEP8 convention.
  • Documentation

Configuration:

# pyproject.toml
 
[tool.flake8]
exclude = "venv"
ignore = ["E501", "W503", "E226"]
# E501: Line too long
# W503: Line break occurred before binary operator
# E226: Missing white space around arithmetic operator

Using NOQA: <error-code> on a line, we’re specifying flake8 to do NO Quality Assurance for that particular error on this line.

Usage

black .
flake8
isort .

Makefile

Automatically run these three lines using the Makefile. This can be used to define a set of commands that can be executed with a single command.

# Makefile
SHELL = /bin/bash
 
# Styling
.PHONY: style
style:
    black .
    flake8
    python3 -m isort .
    pyupgrade
 
# Cleaning
.PHONY: clean
clean: style
    find . -type f -name "*.DS_Store" -ls -delete
    find . | grep -E "(__pycache__|\.pyc|\.pyo)" | xargs rm -rf
    find . | grep -E ".pytest_cache" | xargs rm -rf
    find . | grep -E ".ipynb_checkpoints" | xargs rm -rf
    rm -rf .coverage*

Pre-Commit Framework

Using the pre-commit git hooks to ensure that certain rules are followed or specific actions are executed successfully and if any of them fail, the commit will be aborted.

Install

pip install pre-commit
pre-commit install

Configuration

# simple config
 
pre-commit sample-config > .pre-commit-config.yaml
cat .pre-commit-config.yaml
  • Built-in Hooks
# .pre-commit-config.yaml
 
...
-   id: check-added-large-files
    args: ['--maxkb=1000']
    exclude: "notebooks"
...
  • Exclude Key
# .pre-commit-config.yaml
 
...
-   id: check-yaml
    exclude: "mkdocs.yml"
...
  • Custom Hooks
# .pre-commit-config.yaml
 
...
-   repo: https://github.com/psf/black
    rev: 20.8b1
    hooks:
    -   id: black
        args: []
        files: .
...
  • Local Hooks
# .pre-commit-config.yaml
 
...
-   repo: local
    hooks:
    -   id: clean
        name: clean
        entry: make
        args: ["clean"]
        language: system
        pass_filenames: false

Running

# Run
pre-commit run --all-files  # run all hooks on all files
pre-commit run <HOOK_ID> --all-files # run one hook on all files
pre-commit run --files <PATH_TO_FILE>  # run all hooks on a file
pre-commit run <HOOK_ID> --files <PATH_TO_FILE> # run one hook on a file

Skip Hooks

# Commit without hooks
git commit -m <MESSAGE> --no-verify

Update

# Autoupdate
pre-commit autoupdate