Skip to main content

pycoati

Audits Python test suites for mock smells and suspicious tests. Walks a project with tree-sitter, optionally runs pytest for collection, durations, and coverage, and emits a structured inventory: per-file and per-test counts, mock-API smells, and a per-test suspicion score.

Install

# From source (Rust)
cargo install --path .

# Or as a Python package (via maturin)
maturin develop

Usage

pycoati --help

pycoati <PATH>

Audit a project directory or a single .py file. Writes the inventory to stdout as JSON unless --output is given.

# Structured inventory to a file
pycoati . --output inventory.json

# Aligned-column terminal view
pycoati . --format pretty

# Static analysis only, no pytest subprocesses
pycoati . --static-only

Key flags: --format <json|pretty>, --output <PATH>, --tests-dir <PATH>, --static-only, --no-coverage, --top-suspicious <N>, --project-package <NAME>, --python <CMD>, --pytest-args <STR>, --member-cwd <root|member>, --accept-file <PATH>, --no-accept, --include-accepted. See pycoati --help for the full list.

Weights behind suspicion_score are documented in WEIGHTS.md.

Accepted findings

An audit that runs on a schedule keeps re-surfacing the same legitimate tests. Record the review decision once, with a reason, in .pycoati-accept.toml at the project root (a single-file scan walks up from the file to find it):

schema_version = "1"

[[accept]]
test = "tests/test_packaging.py::test_wheel_installs"
signals = ["zero_asserts", "high_setup_ratio"]
reason = "assertions run in a child interpreter; the parent propagates failure via subprocess.run(check=True)"
reviewed = "2026-09-12"
fingerprint = "3f0a1c7d9b2e4a56"   # optional: lapses the entry if the test is edited

reason is required — an entry without one is a parse error. Acceptance is scoped to one test and one named signal (mock_only_assertions, mock_overuse, zero_asserts, high_setup_ratio); there is no wildcard, so a new finding on an accepted test still surfaces.

The accepted test keeps running and keeps counting: pytest arguments are untouched, so suite.test_count, runtime and coverage are unchanged, and every count, smell hit and score stays in the inventory as measured. The only effect is that a test whose every active signal is accepted is held back from top_suspicious.test_functions. The decisions and their reasons are reported under accepted.findings, entries that no longer apply under accepted.stale, and --include-accepted puts everything back on the shortlist for a full report.

Run pycoati guide setup for the full reference.

pycoati guide [PAGE]

Prints the workflow instructions that ship inside the binary, aimed at a coding agent working through an audit. Because the pages are embedded at compile time, they always describe the inventory schema this exact build emits.

# Pick the page from the state of the current directory
pycoati guide

# Or ask for one by name
pycoati guide setup
pycoati guide analyze
pycoati guide remediate
Page Contents
setup Configuration surface, how to run the scan, where inventory.json lands.
analyze Field reference for every key in the inventory, plus the anti-pattern taxonomy and its detection heuristics.
remediate The remedy ladder, the human-approval gate, and the "do not" list.

With no argument, the page is chosen from the current directory: analyze when an inventory.json is present there, otherwise setup. remediate is never auto-selected — reach it via the analyze page's breadcrumb or by name.

The subcommand shadows a directory of the same name: if you have a ./guide directory to audit, write pycoati ./guide.

Each page ends with a single next: line, so an agent is always one command away from the right instructions. A --format pretty scan that finds candidates ends with the same breadcrumb; JSON output never carries it.

The page sources are plain markdown under docs/guide/, embedded via include_str!. tests/guide_schema_drift.rs asserts that every field name serde emits is documented on the analyze page, so a schema change cannot land without the guide being updated alongside it.

Development

# Pre-commit checks
cargo fmt --check && cargo clippy --all-targets --all-features -- -D warnings && cargo test --all-features

# Full review (fmt, clippy, tests, audit, deny)
make review

License

MIT

Metadata

Release files for pycoati 0.2.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pycoati 0.2.9
File Size Uploaded Provenance
pycoati-0.2.9.tar.gz 195.5 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for pycoati 0.2.9
File Interpreter ABI Platform
pycoati-0.2.9-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
pycoati-0.2.9-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
pycoati-0.2.9-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 4.8 MB

Release files / pycoati-0.2.9.tar.gz

Download URL pycoati-0.2.9.tar.gz
Size 195.5 kB
Tags Source
SHA-256 checksum
How to use checksums
60a264c128d9d2ad24d56aea626f260a5dfa2e55f21513e82337f75499af8b26
BLAKE2b-256 checksum
How to use checksums
7c9332fd410e64d83ee056c7c3fc366a2cf20a405ce6cbf3247cf2929cdf93a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / pycoati-0.2.9-py3-none-win_amd64.whl

Download URL pycoati-0.2.9-py3-none-win_amd64.whl
Size 1.5 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
f92a7abf3c9340382ae8234c055255aaa1ac9f8a260fe3524e7a81e8d308851a
BLAKE2b-256 checksum
How to use checksums
cc6e3fa92cbb39070e6c754f630a4c0d9d38c5f61087bea6db05a05cf5c9b5c6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / pycoati-0.2.9-py3-none-manylinux_2_28_x86_64.whl

Download URL pycoati-0.2.9-py3-none-manylinux_2_28_x86_64.whl
Size 1.7 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
660281ced42b42c304dd88d208ac361c89d5a783560d69d6560a88f0be300e0a
BLAKE2b-256 checksum
How to use checksums
1277b267cb4210bf452d5c3b095d1614a2d038aa7da3d5a9afe83d3e2d88a34c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / pycoati-0.2.9-py3-none-macosx_11_0_arm64.whl

Download URL pycoati-0.2.9-py3-none-macosx_11_0_arm64.whl
Size 1.4 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
8abd3c21280d4087e2a401f563b1eaf18946ae09eff78823e8b6ce36da88f346
BLAKE2b-256 checksum
How to use checksums
e43cca527e44b8b282f9bed71923bc44ddd5d975a2a29f42a8a81f4e8a79decc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Security for pycoati 0.2.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 4 files in this release have been uploaded with provenance metadata.

Select from 4 files

Attestation for pycoati-0.2.9.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page