An opinionated, agentic CLI for Python package hygiene and release
"Get your feathers in order before you fly"
preen is a comprehensive tool for Python package maintenance that treats pyproject.toml as the single source of truth. It automatically generates and synchronizes derived files, runs comprehensive pre-release checks, and provides an opinionated workflow for package development and release.
- π 12 comprehensive checks - linting, tests, dependencies, CI matrix, project structure, version consistency, citation validation, link validation, documentation quality, static type checking, and spell checking
- π§ Interactive fixes - preview diffs and apply fixes automatically or selectively
- π¦ Package initialization - scaffold new packages with opinionated best practices
- π File synchronization - generate CI workflows, documentation config, and CITATION.cff from pyproject.toml
- π Version management - semantic versioning with automatic derived file updates
- π― Modern tooling - uv-native workflows, GitHub Actions, and trusted publishing
pip install preenRequires Python 3.9+
preen init mypackage
cd mypackage
pip install -e .[dev]preen check # Interactive check with fix prompts
preen check --fix # Apply all fixes automatically
preen check --strict # Exit 1 if any issues (perfect for CI)preen sync # Update all derived files
preen sync --only citation # Update only CITATION.cff
preen sync --check # Check if files need updating (CI mode)preen bump patch # 1.0.0 β 1.0.1
preen bump minor # 1.0.1 β 1.1.0
preen bump major # 1.1.0 β 2.0.0Initialize new Python packages with opinionated structure:
- Modern
pyproject.tomlwith setuptools backend src/layout for better import isolation- Comprehensive
tests/directory at project root - GitHub Actions workflows for CI, docs, and release
- Pre-configured development dependencies (pytest, ruff)
- CITATION.cff for academic software
preen init mypackage # Interactive mode
preen init mypackage --dir ./custom # Specify directoryRun comprehensive pre-release checks:
| Check | Description |
|---|---|
| ruff | Code linting and formatting |
| tests | Run pytest suite |
| deps | Find unused/missing dependencies (requires deptry) |
| ci-matrix | Verify CI tests all declared Python versions |
| structure | Enforce project structure best practices |
| version | Detect hardcoded version strings |
| citation | Ensure CITATION.cff matches pyproject.toml |
| links | Check for broken or dead links in project files |
| pydoclint | Check docstring quality and completeness |
| pyright | Static type checking for type safety |
| codespell | Check spelling in documentation and comments |
preen check # Interactive mode
preen check --fix # Auto-apply all fixes
preen check --only ruff,tests # Run specific checks
preen check --skip deps,links,pydoclint,pyright,codespell # Skip optional checks
preen check --strict # CI mode (exit 1 on issues)Synchronize derived files from pyproject.toml:
.github/workflows/ci.yml- CI matrix from Python classifiers.github/workflows/docs.yml- Documentation deployment.github/workflows/release.yml- PyPI publishing with trusted publisherdocs/conf.py- Sphinx configurationCITATION.cff- Citation metadata for academic software
preen sync # Update all derived files
preen sync --only ci,citation # Update specific targets
preen sync --check # Verify files are up to dateSemantic version management:
- Updates version in
pyproject.toml - Regenerates all derived files with new version
- Commits changes to git with conventional commit message
preen bump patch # Bug fixes: 1.0.0 β 1.0.1
preen bump minor # New features: 1.0.1 β 1.1.0
preen bump major # Breaking changes: 1.1.0 β 2.0.0
preen bump patch --dry-run # Preview changes
preen bump minor --no-commit # Skip git commitCustomize behavior in pyproject.toml:
[tool.preen]
# CI configuration
ci_os = ["ubuntu-latest", "macos-latest"]
ci_runner = "uv" # or "pip"
# Documentation
sphinx_theme = "furo"
use_myst = true
# Structure preferences
src_layout = true
tests_at_root = true
# Skip specific checks
skip_checks = ["deps", "structure"]Typical workflow for package maintenance:
# 1. Initialize new package
preen init myawesome-package
cd myawesome-package
# 2. Develop your package
# ... write code, tests ...
# 3. Pre-release checks
preen check --fix
# 4. Version bump and release prep
preen bump minor
git push origin main
# 5. Manual steps (for now)
# - Create GitHub release
# - CI will build and publish to PyPI via trusted publisherpyproject.toml as Single Source of Truth
- All metadata lives in one place
- Derived files are generated, never edited manually
- Eliminates version mismatches and configuration drift
Opinionated Best Practices
src/layout for better import isolationtests/at project root, not inside package- Modern Python packaging (setuptools, trusted publishing)
- Comprehensive CI matrix matching declared Python support
DRY Across Configuration
- CI matrix generated from Python classifiers
- Documentation config reflects project metadata
- CITATION.cff stays in sync with authors and version
When you run preen sync, these files are generated/updated:
.github/workflows/
βββ ci.yml # Test matrix + linting
βββ docs.yml # Documentation deployment
βββ release.yml # PyPI publishing
docs/
βββ conf.py # Sphinx configuration
CITATION.cff # Citation metadata
All generated files include a header indicating they're managed by preen:
# Generated by preen β do not edit manually
# Regenerate with: preen syncGitHub Actions
# .github/workflows/quality.yml
- name: Package hygiene
run: |
pip install preen
preen check --strict
preen sync --checkPre-commit Hook
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: preen-check
name: preen check
entry: preen check --strict
language: system
pass_filenames: falseThis project is licensed under the MIT License - see the LICENSE file for details.
- Fork the repository
- Create a feature branch
- Make your changes
- Run
preen checkto ensure code quality - Submit a pull request
For development setup:
git clone https://github.com/gojiplus/preen.git
cd preen
pip install -e .[dev]
preen check