Skip to main content

preen

PyPI version CI Documentation License: MIT

Preen is the conformance-and-adoption CLI for the py-canon fleet standard. py-canon defines the standard — a copier template, reusable GitHub workflows, and shared Sphinx configuration. Preen is how repos enter the fleet and stay in it: it scaffolds new packages, retrofits existing ones, pulls template updates, checks conformance, and cuts tag-driven releases.

preen itself requires Python >=3.12, stricter than the >=3.11 floor of the fleet standard it enforces on other repos — the tool can hold itself to a higher bar than the standard it applies.

Install

uv tool install preen   # or: pipx install preen

Use with Claude Code

/plugin marketplace add gojiplus/preen
/plugin install preen@gojiplus

The bundled skill teaches Claude Code to reach for the preen CLI — scaffolding, adoption, checks, and releases — instead of reimplementing its logic.

Commands

Command What it does
preen new NAME Scaffold a new package from the py-canon copier template
preen adopt [PATH] Retrofit an existing repo: mine answers from the repo, copy in the managed files, rewrite [tool.*] in pyproject.toml
preen update [PATH] Pull the latest template changes into an adopted repo (copier update)
preen check [PATH] Run conformance checks (detection only); --strict for CI
preen fix [CHECK] Apply fixes for issues the checks found
preen release [X.Y.Z] Guided release: run checks, confirm, git tag vX.Y.Z, push — the tag triggers the release workflow

Adopting an existing repo

cd my-package
preen adopt
# review the ADOPTION REPORT, then:
uv lock && uv sync --all-groups
preen check

preen adopt mines the copier answers from the repo itself (name, description, and authors from pyproject.toml; org from the git remote), renders the template into a temp directory, and copies in only the managed files: the CI/docs/release workflow shims, .pre-commit-config.yaml and dependabot config (if absent), docs/conf.py (old one backed up), .copier-answers.yml, py.typed, plus LICENSE and CITATION.cff if missing. It rewrites the [tool.ruff] (preserving any repo-specific lint ignores already present, and setting target-version from the repo's own requires-python floor, falling back to py311), [tool.pyright], and [tool.pydoclint] sections to the standard with tomlkit (comments elsewhere survive) and deletes legacy [tool.black], [tool.isort], [tool.flake8], and [tool.mypy] sections.

Pass --release-migration to also convert the build backend to hatchling + uv-dynamic-versioning, so the git tag becomes the version.

Checks

preen check runs: template (copier adoption + drift against the latest py-canon tag), ruff, tests, citation, changelog (Keep a Changelog structure), deps (deptry), deptree (circular imports), depgroups (PEP 735 dependency-groups usage), audit (pip-audit over the locked dependencies), ci-matrix (canon shim, or a matrix covering the requires-python floor), structure, version (hardcoded version strings), license (PEP 639 license metadata), links, metadata (requires-python upper bound, PEP 561 py.typed), pydoclint, pyright, and codespell.

Issues carry an impact level: critical blocks release, important can be overridden with informed consent, info is advisory. preen release walks that ladder interactively before tagging. Most checks are detection-only; preen fix license migrates the deprecated { text = ... } license table form to an SPDX string where the mapping is unambiguous, drops redundant License :: classifiers, and adds a missing license-files entry.

Releasing

The fleet standard derives versions from git tags (uv-dynamic-versioning) — no bump commits. preen release runs the checks, then refuses to proceed unless the version is PEP 440-valid, the tag doesn't already exist, and CHANGELOG.md has an entry for it (offering to rename [Unreleased] to the new version and commit that rename if the Unreleased section has content). It then asks for confirmation, tags vX.Y.Z, and pushes the tag; the repo's release workflow does the rest (build, PEP 740 attestations, PyPI trusted publishing, GitHub Release). Use --dry-run to see the plan without acting.

Configuration

Preen reads an optional [tool.preen] section in pyproject.toml:

[tool.preen]
src_layout = true       # expect src/ layout (default: true)
tests_at_root = true    # expect tests/ at the repo root (default: true)
skip_checks = ["links"] # checks to skip by default

Notes

  • pydoclint covers docstring-signature consistency for now; ruff ships equivalent DOC rules ([tool.ruff.lint] external = ["DOC"] reserves the codes), but they're still preview-only, so pydoclint stays until ruff stabilizes them.
  • codespell stays: ruff has no spelling-check rules.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

preen-0.2.0.tar.gz (133.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

preen-0.2.0-py3-none-any.whl (66.2 kB view details)

Uploaded Python 3

File details

Details for the file preen-0.2.0.tar.gz.

File metadata

  • Download URL: preen-0.2.0.tar.gz
  • Upload date:
  • Size: 133.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for preen-0.2.0.tar.gz
Algorithm Hash digest
SHA256 62f0caffb70be1be07003038e848752e8ff4d041e48a20b311dea5352678413d
MD5 b8da2abc8faca05726121f744b588427
BLAKE2b-256 bdbc8dfe58937b42a8a7f565326a419d9baace65a189dfb0e79bf679f9a0521a

See more details on using hashes here.

Provenance

The following attestation bundles were made for preen-0.2.0.tar.gz:

Publisher: release.yml on gojiplus/preen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file preen-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: preen-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 66.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for preen-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5913ae2b32e68b4d41cdc64fd1aa7298f3797f9538977b18c6a45c93647affb3
MD5 5f0858a1fac3c54eb248f543d73b8288
BLAKE2b-256 27f66c5e2f042063a07836f7db03d23428dbb8f1524950157effe66aaff98e0b

See more details on using hashes here.

Provenance

The following attestation bundles were made for preen-0.2.0-py3-none-any.whl:

Publisher: release.yml on gojiplus/preen

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page