Skip to content

Design

Build system

This template uses Hatch as the build backend and project manager.

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

✅ Why choose Hatch?

Hatch is a modern, PEP 517-compliant build backend. Main features:

Tool consolidation

Hatch can also manage virtual environments, test runners, and formatters (e.g. hatch fmt), reducing reliance on multiple tools.

PEP 621 support

Clean, declarative configuration in pyproject.toml. Keeping the number of configuration files minimal.

Integrated versioning

Instead of hardcoding the version number in pyproject.toml, we delegate it to a separate file (__about__.py) inside the source tree. This pattern has a few advantages:

  • Single source of truth: The version lives inside your package, making it accessible at runtime via import.
  • Tool-friendly: Hatch can automatically read and update this file using [tool.hatch.version], supporting both static and dynamic versioning.
  • Clean packaging: Keeps pyproject.toml minimal, and avoids cluttering the __init__.py with metadata.

Documentation

The user can select which documentation engine they prefer. Some information on the two options is already provided below, this will be fleshed out more as both frameworks are tested more rigorously.

MyST Markdown

MyST Markdown is a Markdown-based documentation tool that avoids Sphinx' reStructuredText format while preserving most of its power. The main reason to use this over MkDocs to test the Jupyter notebook integration, especially the "executable content". MyST is also easy to integrate with Sphinx, which has a lot of powerful tools, especially for scientific software.

MkDocs

MkDocs is another Markdown-based documentation tool that focusses even more on simplicity. Some features:

  1. Very simple to build and write, not too much faff.
  2. Builds/serves very fast (faster than MyST in my experience).
  3. Static pages, easy to host.
  4. Sleek look, using Material for MkDocs.

DevOps

This template includes development automation tools that ensure code quality, consistency, and developer efficiency.

Pre-commit hooks

We use pre-commit to run automated checks before each commit. The configuration is stored in .pre-commit-config.yaml and runs hooks at two stages. A single pre-commit install wires both up, thanks to default_install_hook_types: [pre-commit, commit-msg]:

  • pre-commit stagehatch fmt in two separate steps: hatch fmt -f to format the code, then hatch fmt -l to lint it for issues.
  • commit-msg stagedev/check_commit_msg.py, which rejects commit subjects that do not start with one of the recognized type emojis (see the commit message conventions).

The same check_commit_msg.py script is also invoked by a commit-msgs CI job over every commit in a pull request, so contributors who skip the local hook still get caught before merge.