Skip to main content

pytest-why

PyPI version Python versions License: MIT Tests

Your pytest run failed and the traceback doesn't tell you why. pytest-why adds --why: each failure gets a plain-English cause (fixture error, assertion mismatch, import error, timeout, collection error...) and the next step to try, plus a shareable Markdown/HTML report.

A pytest plugin that explains failing tests like a senior engineer.

Before, a plain pytest run on a test that uses a missing fixture:

_______________________ ERROR at setup of test_checkout ________________________
file test_checkout.py, line 3
  def test_checkout(db_session):
E       fixture 'db_session' not found
>       available fixtures: capfd, capfdbinary, caplog, capsys, ...
>       use 'pytest --fixtures [testpath]' for help on them.
=========================== short test summary info ============================
ERROR test_checkout.py::test_checkout

After, with pytest --why:

================ pytest-why: failure explanations ================
Total failures: 1
Fixture error: test_checkout.py::test_checkout (setup)
  Why: Pytest could not prepare the test because a fixture is missing, has an incompatible scope, or depends on itself.
  Hint: Check the fixture name, where it is defined, its scope, and its dependency chain.
Reports: pytest-why-report.md, pytest-why-report.html

Learn more: pytest-why: actionable failure guidance · Project page · Follow @dkkkkd on X

pytest-why turns common pytest failures into concise explanations and practical next steps. It runs locally, adds no noise to normal test runs, and creates shareable Markdown and HTML reports when you ask for them.

Install

python -m pip install pytest-why

For local development:

python -m pip install -e .[dev]

Usage

Run pytest with one extra flag:

python -m pytest --why

Without --why, the plugin does nothing and creates no report files.

Example

Given:

def test_math():
    assert 2 + 2 == 5

Run:

pytest --why

Sample output:

================ pytest-why: failure explanations ================
Total failures: 1
Assertion mismatch: test_math.py::test_math (call)
  Why: The code ran, but the observed value or state did not match what the test expected.
  Hint: Compare the expected and actual values near the final assertion, then trace where they first diverge.
Reports: pytest-why-report.md, pytest-why-report.html

Reports

Each --why run writes:

  • pytest-why-report.md for pull requests, issue trackers, and terminals
  • pytest-why-report.html for a styled, standalone browser view

Both reports include the failing test, pytest phase, classification, duration, explanation, hint, and the complete raw traceback.

Supported classifications

  • Assertion mismatch: expected and actual values differ
  • Import error: a module or symbol could not be imported
  • Fixture error: missing fixtures, scope mismatches, or recursive dependencies
  • Timeout: a test or operation exceeded its time limit
  • Syntax/collection error: parsing or collection failed before a test could run
  • Type error: an operation received an incompatible object or argument type
  • Connection error: a dependency connection was refused, reset, or otherwise failed
  • Unknown failure: deterministic fallback with traceback-first guidance

Selenium and Playwright tracebacks also receive a focused browser automation hint covering selectors, waits, page timing, and element visibility.

When to use pytest-why (vs alternatives)

Tool What it does How pytest-why differs
pytest -vv / --tb=long Shows more of the traceback and the full assertion diff pytest-why keeps the normal output and adds a short, classified cause and a next step per failure, plus a report you can share
pytest-clarity, pytest-icdiff Make assertion diffs easier to read Those are diff viewers for assertion failures. pytest-why also covers fixture, import, collection, timeout, type and connection failures, and it works alongside them
Pasting the traceback into an LLM chat Free-form explanation pytest-why runs locally and offline, sends nothing anywhere, and gives the same answer every time (rule-based classification)

Use it when you want a quick triage of "what kind of failure is this and where do I start", in your terminal or in CI. It is not a replacement for reading the traceback: the classification is pattern-based, and failures that match no pattern are reported as Unknown failure, with the raw traceback kept in the report.

FAQ

Does it send my code or tracebacks anywhere? No. Classification is deterministic string matching inside the pytest process. There are no network calls, and the reports are written only to your working directory.

Does it slow down my test runs? Without --why, the plugin does nothing. With --why, it only does work for failed tests (a few substring checks per failure), plus writing the two report files at the end of the session.

Does it work with pytest-xdist? Yes. Failure reports from workers are collected by the main process, so pytest -n auto --why prints one combined summary and writes one pair of reports.

Where are the reports written, and should I commit them? pytest-why-report.md and pytest-why-report.html are written to the current working directory on every --why run. Add them to .gitignore, or upload them as CI artifacts.

My failure shows up as "Unknown failure". That's the deterministic fallback for tracebacks that don't match a known pattern. The report still contains the full raw traceback. Issues with example tracebacks are welcome: https://github.com/godhiraj-code/pytest-why/issues

License

MIT. See LICENSE.

Stop doomscrolling tracebacks. Run pytest --why.

Metadata

Release files for pytest-why 0.1.2

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

Source distribution (sdist)

Source distribution for pytest-why 0.1.2
File Size Uploaded Provenance
pytest_why-0.1.2.tar.gz 14.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pytest-why 0.1.2
File Interpreter ABI Platform
pytest_why-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 24.3 kB

Release files / pytest_why-0.1.2.tar.gz

Download URL pytest_why-0.1.2.tar.gz
Size 14.0 kB
Tags Source
SHA-256 checksum
How to use checksums
039c1c41c5883b2708c91417b556c6638622b0b96ba60288914542e9f1e2a5c5
BLAKE2b-256 checksum
How to use checksums
3f3f2f89e99ad795ce8e618670f53bd2ae5a3902af4b8cd8815a212749535995
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Release files / pytest_why-0.1.2-py3-none-any.whl

Download URL pytest_why-0.1.2-py3-none-any.whl
Size 10.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aee4facf1d9bace87c8c5401559f380d3d48e6255203d57df0bbcacd4bd05593
BLAKE2b-256 checksum
How to use checksums
424f7e568ff33989682e8d7631e861e6a56c2eb04dd65d3261f66ada29572dc3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.7

Security for pytest-why 0.1.2

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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