pypfmt
An opinionated formatter and sorter for pyproject.toml files. Produces
deterministic, consistently-ordered output so you can diff configuration
across many Python projects and copy settings between them without noise.
Features
- Sort tables and keys with opinionated defaults —
[project],[build-system], and[dependency-groups]always come first; common tool sections follow a predictable order - Format whitespace and style via taplo for consistent indentation, trailing commas, and column alignment
- Preserve all data — no keys, values, or comments are lost or reordered when order matters (e.g.
pytest.ini_options.addopts) - Idempotent — running the tool twice produces identical output
- Pre-commit hook — drop-in integration with pre-commit
- Configurable — override defaults per-project via
[tool.pypfmt]
Installation
pip install pypfmt
Or using uv (recommended):
uv add pypfmt
Usage
Format files in-place
pypfmt pyproject.toml
Multiple files (useful for monorepos):
pypfmt services/*/pyproject.toml
Check mode (CI)
Exit non-zero if any file needs formatting, without modifying files:
pypfmt --check pyproject.toml
Diff mode
Print a unified diff of proposed changes without modifying files:
pypfmt --diff pyproject.toml
Combined check + diff
Print the diff and exit non-zero if changes are needed:
pypfmt --check --diff pyproject.toml
Stdin / stdout
Pipe input through pypfmt and receive formatted output on stdout:
cat pyproject.toml | pypfmt
Pre-commit hook
Add to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/bitflight-devops/pyproject-fmt
rev: v1.0.0 # replace with the latest tag
hooks:
- id: pypfmt
language: python is used so pre-commit installs taplo and all other
dependencies automatically.
Configuration
Add a [tool.pypfmt] section to your pyproject.toml to override defaults.
Sort order
[tool.pypfmt]
# Replace the root-level table ordering entirely
sort-first = ["project", "build-system", "dependency-groups"]
# Or append extra tables to the default ordering
extend-sort-first = ["my-custom-tool"]
# Disable alphabetical key sorting within tables
sort-table-keys = false
Per-table overrides
[tool.pypfmt]
# Extend the built-in per-table overrides
[tool.pypfmt.extend-overrides]
"tool.mypy" = { first = ["strict", "plugins"] }
"project.optional-dependencies.*" = { inline_arrays = true }
taplo formatting options
[tool.pypfmt]
# Replace all taplo options
taplo-options = ["column_width=100", "indent_string= "]
# Or append extra options to the defaults
extend-taplo-options = ["column_width=100"]
Comment handling
[tool.pypfmt]
comments-header = true # preserve file-level header comments (default: true)
comments-footer = true # preserve file-level footer comments (default: true)
comments-inline = true # preserve inline comments (default: true)
comments-block = true # preserve block comments (default: true)
Default opinionated behaviour
| Behaviour | Default |
|---|---|
| Root table order | project, build-system, dependency-groups, then alphabetical |
| Tool section order | hatch, git-cliff, uv, pytest, coverage, ty, ruff, mypy, … |
Key order within [project] |
name, version, description, readme, dynamic, authors, maintainers, license, classifiers, keywords, requires-python, dependencies, then alphabetical |
| Classifiers | Sorted alphabetically |
| Dependencies | Sorted alphabetically |
pytest.ini_options.addopts |
Preserved as-is (positional arguments) |
keywords |
Preserved as-is (positional) |
| Inline comments | Aligned |
| Indentation | 4 spaces |
| Trailing commas in arrays | Always added |
Development
Prerequisites
- Python 3.11+
- uv for package management
Setup
git clone https://github.com/bitflight-devops/pyproject-fmt.git
cd pyproject-fmt
uv sync --all-groups
Running Tests
uv run poe test
# With coverage
uv run poe test-cov
# Across all Python versions
uv run poe test-matrix
Code Quality
# Run all checks (lint, format, type-check)
uv run poe verify
# Auto-fix lint and format issues
uv run poe fix
Pre-commit hooks (prek)
prek install
prek run --all-files
Documentation
uv run poe docs-serve
License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for pypfmt 1.1.14
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pypfmt-1.1.14.tar.gz | 14.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pypfmt-1.1.14-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.2 kB
Release files / pypfmt-1.1.14.tar.gz
| Download URL | pypfmt-1.1.14.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fad0ac1aa7d87114cd6ef944c666009e6fd7092a589a9030ae0d4c3513ddbc89
|
|
BLAKE2b-256 checksum How to use checksums |
6ac76d9086fe9f301efd401b0f501ba743e64bc87894b76a3b2ae52773586dd4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / pypfmt-1.1.14-py3-none-any.whl
| Download URL | pypfmt-1.1.14-py3-none-any.whl |
|---|---|
| Size | 15.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9d3b98d6d6a167ecac552c4eba526755c49b5a19ed9c182bde0d9cc615712b51
|
|
BLAKE2b-256 checksum How to use checksums |
bafa33d90b07198b75d4d7208d25272be9ae6e05bef01e5ae1e96a0251be6788
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.7 {"installer":{"name":"uv","version":"0.12.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|