Skip to content

leonkozlowski/puff

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

puff

A blazing-fast pyproject.toml formatter written in Rust.

Built with Rust License: MIT

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",
]

Features

  • 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

Installation

git clone https://github.com/leonkozlowski/puff.git
cd puff
cargo install --path .

Usage

# 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 --stdout

Options

Usage: 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

Formatting Rules

Section Order

Sections are ordered according to their purpose:

  1. [build-system] — Build configuration (PEP 517/518)
  2. [project] — Project metadata (PEP 621)
  3. [project.*] — Project subtables (urls, scripts, optional-dependencies)
  4. [tool.*] — Tool configuration (sorted alphabetically)

Key Order

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

Dependency Sorting

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:

  1. Explicit --internal-packages flag
  2. Explicit --internal-prefixes flag
  3. Auto-detection from project name (e.g., myapp project treats myapp-* as internal)

Disable auto-detection with --no-auto-detect.

String Quotes

All strings are normalized to double quotes:

# Before
name = 'mypackage'
version = '1.0.0'

# After
name = "mypackage"
version = "1.0.0"

Array Formatting

Arrays with multiple items are formatted one-per-line with trailing commas:

# Before
dependencies = ["requests", "aiohttp", "numpy"]

# After
dependencies = [
    "aiohttp",
    "numpy",
    "requests",
]

Configuration

Configure puff in your pyproject.toml:

[tool.puff]
internal-packages = ["mycompany-core", "mycompany-utils"]
internal-prefixes = ["mycompany-", "internal-"]
auto-detect-internal = true
indent = 4

CI Integration

GitHub Actions

- name: Check pyproject.toml formatting
  run: |
    cargo install puff
    puff --check

Pre-commit

repos:
  - repo: local
    hooks:
      - id: puff
        name: puff
        entry: puff --check
        language: system
        files: pyproject\.toml$

Exit Codes

Code Meaning
0 Success (formatted or already formatted)
1 Would reformat (--check mode)
2 Error (parse error, file not found, etc.)

Performance

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.

Comparison

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

Related Projects

  • ruff — Fast Python linter and formatter
  • taplo — TOML toolkit
  • pyprojectsort — Python-based pyproject.toml sorter

License

MIT

About

An extremely fast pyproject.toml formatter, written in Rust.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages