I’m a big fan of pre-commit and have written about it before (see posts on pre-commit, pre-commit CI and pre-commit updating). This post discusses some of the hooks that I use and how to configure them.
Python Linting
Ruff
ruff is a Python linter written in Rust which means its considerably faster than many native linters. It aims for parity with Flake8 and covers a lot of the linting that PyLint undertakes too. Its configured via pyproject.toml
which makes incorporating it into your Python Package simple.
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.191
hooks:
- id: ruff
Configuration is, as noted, via pyproject.toml
and you may find the post on Python Packaging worth reading to understand more on this.
[tool.ruff]
exclude = []
# per-file-ignores = []
line-length = 120
target-version = "py310"
# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["A", "B", "C", "D", "E", "F", "R", "S", "W", "U"]
unfixable = []
Black
Black is an opinionated formatter for Python that is PEP8 compliant. By using black
to format your code you end up with a consistent style across the code base and commit changes end up being minimal. This helps speed up code-review of pull-requests.
repos:
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
types: [python]
Configuration is, as noted, via pyproject.toml
and you may find the post on Python Packaging worth reading to understand more on this.
[tool.black]
line-length = 120
target-version = ["py38", "py39", "py310"]
include = "\\.pyi?$"
pydocstyle
You can check your docstrings are correctly written using the pydocstyle hook.
Its pretty straight-forward to use and accepts arguments so you can pass all the command line options you might want to use into the hook when it runs. It supports three different doc string styles, pep257
, numpy
and google
.
- repo https://github.com/pycqa/pydocstyle
rev: 6.3.0 # pick a git hash / tag to point to
hooks:
- id: pydocstyle
args:
- --convention=numpy
# Optionally ignore rules
- --ignore=D101,D2
Alternatively you can add configuration options to your projects pyproject.toml
under a [tool.pydocstyle]
section.
[tool.pydocstyle]
convention = "numpy"
ignore = [
"D101",
"D2"
]
Markdown Linting
markdownlint-cli2 is a useful and highly configurable hook for linting Markdown and CommonMark. I wanted to use it on this blog though which is written using Quarto and therefore uses PandocMarkdown with files that have extension .qmd
. I therefore enable the hook in .pre-commit-config.yaml
with a configuration file specified
repos:
- repo: https://github.com/DavidAnson/markdownlint-cli2
rev: v0.6.0
hooks:
- id: markdownlint-cli2
args: [.markdownlin-cli2.yaml]
..and add a sample configuration file (e.g. .mardownlint-cli2.yaml
although other formats such as JSON can be used) is shown below and markdownlint-cli2
picks this up automatically.
# Configuration
config:
# MD013 - line-length
line_length:
line_length: 120
code_blocks: false
tables: false
html:
allowed_elements:
- div
# Globs
globs:
- "**/*.qmd"
- "*.qmd"
# Fix any fixable errors
fix: false
Emacs Lisp
As I use Emacs I have recourse to write some Emacs Lisp and so its useful to applying formatting to my .el
files before committing them. lisp-format does the job nicely.
repos:
- repo: https://github.com/eschulte/lisp-format
rev: 088c8f78ca41204b44f2636275517ac09a2de6a9
hooks:
- id: lisp-format
name: formatter of lisp code
description: Run lisp-format against lisp files
language: script
files: \.(lisp|cl|asd|scm|el)$
entry: lisp-format -i
Conclusion
There are a lot of hooks out there to be used with pre-commit and incorporated into your Continuous Integration pipeline with pre-commit.ci. Which you find useful will depend to a large extent on the languages that you are using for any given project. Here I’ve focused mainly on common tools for Python Packages, Markdown and Lisp but you can find hooks for Docker, Ansible, Rust, Go, JavaScript, C++ and many more, there is even gitlint which lints your commit messages! Checkout the long list of available hooks and try some out.
Links
Pre-commit hooks
Reuse
Citation
@online{shephard2023,
author = {Shephard, Neil},
title = {Pre-Commit : {Useful} {Hooks}},
date = {2023-05-07},
url = {https://blog.nshephard.dev/posts/pre-commit-hooks/},
langid = {en}
}