A blazing-fast pyproject.toml formatter written in Rust.
Inspired by Astral's Ruff — Built with Claude Code
Disclaimer: This is a personal project and the code was 100% generated by Claude Code.
Before:
[project]
dependencies = ['zlib', "requests", 'myapp-utils', "aiohttp"]
name = 'myapp'
[build-system]
requires = ["setuptools>=45"]After:
[build-system]
requires = ["setuptools>=45"]
[project]
name = "myapp"
dependencies = [
"aiohttp",
"requests",
"zlib",
"myapp-utils",
]- Section ordering —
[build-system]→[project]→[tool.*] - Key ordering — Canonical order within sections per PEP 621
- Dependency sorting — Alphabetical with internal packages last
- Quote normalization — Consistent double quotes throughout
- Array formatting — Multi-line with trailing commas
- Fast — Written in Rust with parallel file processing
git clone https://github.com/leonkozlowski/puff.git
cd puff
cargo install --path .# Format pyproject.toml in place
puff
# Format specific file(s)
puff pyproject.toml
puff **/pyproject.toml
# Check without modifying (useful for CI)
puff --check
# Show diff of changes
puff --diff
# Read from stdin, write to stdout
cat pyproject.toml | puff --stdin --stdoutUsage: puff [OPTIONS] [FILES]...
Arguments:
[FILES]... Files or glob patterns to format [default: pyproject.toml]
Options:
-c, --check Check formatting without modifying
-d, --diff Show unified diff of changes
-q, --quiet Suppress non-error output
--stdin Read from stdin
--stdout Write to stdout
--internal-packages <PACKAGES> Packages to treat as internal
--internal-prefixes <PREFIXES> Prefixes for internal packages
--no-auto-detect Disable internal package auto-detection
-h, --help Print help
-V, --version Print version
Sections are ordered according to their purpose:
[build-system]— Build configuration (PEP 517/518)[project]— Project metadata (PEP 621)[project.*]— Project subtables (urls, scripts, optional-dependencies)[tool.*]— Tool configuration (sorted alphabetically)
Keys within [project] follow PEP 621 canonical order:
name
version
description
readme
requires-python
license
authors
maintainers
keywords
classifiers
dependencies
optional-dependencies
urls
scripts
gui-scripts
entry-points
dynamic
Keys within [build-system] follow PEP 517/518 order:
requires
build-backend
backend-path
Dependencies are sorted alphabetically, with internal packages last:
dependencies = [
"aiohttp", # External (alphabetical)
"requests>=2.0",
"zlib",
"myapp-core", # Internal (alphabetical, sorted last)
"myapp-utils",
]Internal packages are detected by:
- Explicit
--internal-packagesflag - Explicit
--internal-prefixesflag - Auto-detection from project name (e.g.,
myappproject treatsmyapp-*as internal)
Disable auto-detection with --no-auto-detect.
All strings are normalized to double quotes:
# Before
name = 'mypackage'
version = '1.0.0'
# After
name = "mypackage"
version = "1.0.0"Arrays with multiple items are formatted one-per-line with trailing commas:
# Before
dependencies = ["requests", "aiohttp", "numpy"]
# After
dependencies = [
"aiohttp",
"numpy",
"requests",
]Configure puff in your pyproject.toml:
[tool.puff]
internal-packages = ["mycompany-core", "mycompany-utils"]
internal-prefixes = ["mycompany-", "internal-"]
auto-detect-internal = true
indent = 4- name: Check pyproject.toml formatting
run: |
cargo install puff
puff --checkrepos:
- repo: local
hooks:
- id: puff
name: puff
entry: puff --check
language: system
files: pyproject\.toml$| Code | Meaning |
|---|---|
| 0 | Success (formatted or already formatted) |
| 1 | Would reformat (--check mode) |
| 2 | Error (parse error, file not found, etc.) |
puff is designed for speed:
- Written in Rust with zero-copy parsing where possible
- Parallel file processing with rayon
- Optimized release builds with LTO
Typical execution time is under 10ms for a single file.
| Feature | puff | taplo | pyprojectsort |
|---|---|---|---|
| Language | Rust | Rust | Python |
| Dependency sorting | Yes | No | Yes |
| Internal packages last | Yes | No | No |
| Section ordering | Yes | No | Yes |
| Key ordering (PEP 621) | Yes | No | Yes |
| Quote normalization | Yes | Yes | Yes |
- ruff — Fast Python linter and formatter
- taplo — TOML toolkit
- pyprojectsort — Python-based pyproject.toml sorter
MIT