Skip to main content

rety

One codebase. Multiple type checkers. One honest view.

rety runs mypy, Pyright, Pyrefly, and ty on the same Python code, normalizes their diagnostics into a shared schema, and shows you where they agree, where they disagree, and — as precisely as the data allows — why.

$ rety check src/

  src/api.py ────────────────────────────────────────────────
  3/4  * HIGH  L42  in handle_request  [Call]
      mypy      error    42:18  Argument 1 to "process" has incompatible type "str"; expected "int" [arg-type]
      pyright   error    42:18  Argument of type "str" cannot be assigned to parameter "x" of type "int" [reportArgumentType]
      pyrefly   error    42:18  Expected `int`, got `str` [bad-argument-type]

  1/4  - LOW   L87  in validate  [Call]
      ty        error    87:5   Object of type `None` is not callable [call-non-callable]

  2 cluster(s)  1 seen by multiple checkers  1 seen by only one checker

The problem rety solves

Python typing has no single ground truth. The four major type checkers implement the same specification (PEP 484 and friends) with materially different inference philosophies, conformance levels, and diagnostic vocabularies. They will disagree even on correct code, and for legitimate reasons.

rety doesn't tell you which checker is right. It turns four independent opinions about the same code into one navigable, honest picture of where they agree, where they disagree, and how confident the alignment is. The "why" — "these three diagnostics all attach to the same call expression" — is the part that's actually useful.

Concrete use cases:

  • Checker migration (e.g., mypy → Pyrefly): see exactly which mypy errors have Pyrefly counterparts before committing to the switch
  • Cross-checker validation: run two checkers as mutual cross-checks without fully replacing either
  • Empirical research: study checker disagreement patterns across a corpus without trusting any single tool's output

Install

pipx install rety
# or
uv tool install rety

rety does not install the type checkers itself. You need the checkers you want to run already installed and on $PATH (pip install mypy pyright pyrefly ty covers all four). Any selected checker that is missing is skipped with a notice on stderr that names it and shows the install command; pass --require-all to fail instead.


Usage

# Run all available checkers on a directory
rety check src/

# Run specific checkers only
rety check --checker mypy,pyright src/

# Machine-readable JSON output
rety check --format json src/ > report.json
rety check --format json --output report.json src/

# Looser line matching (useful if checkers report adjacent lines)
rety check --line-tolerance 1 src/

# Show alignment signals per cluster (why it was grouped)
rety check --verbose src/mymodule.py

# Fail if any selected checker is not installed
rety check --require-all --checker mypy,pyright src/

# Gate CI: exit 1 if any checker reported an error (or `any` diagnostic)
rety check --fail-on error src/

# Give slow checkers more (or unlimited) time; default is 600 seconds each
rety check --timeout 0 src/

Exit codes

Code Meaning
0 Run completed and the --fail-on threshold was not met
1 The --fail-on threshold was met
2 Usage error, no checker available, or --require-all not satisfied

By default (--fail-on none) rety exits 0 whenever the run itself succeeded, regardless of what the checkers found.


How it works

  1. Run — each checker is invoked as a subprocess, concurrently, with its own native config discovery intact (mypy.ini, pyrightconfig.json, pyrefly.toml, ty.toml) relative to the directory where you ran rety.
  2. Normalize — each checker's output is parsed into a shared NormalizedDiagnostic schema: mypy's JSON-lines, Pyright's and Pyrefly's JSON documents, ty's concise text. Positions are unified to 1-indexed lines and columns (Pyright and mypy report 0-indexed columns; rety converts). The parsers are tested against real captured output; the checker versions they were verified against are pinned in tests/CHECKER_VERSIONS.md.
  3. Align — diagnostics are grouped per file by line-range overlap. Two clusters on adjacent lines are merged only when a diagnostic from each sits inside the same instance of a multi-line statement or call (the classic "mypy blames the call, Pyright blames the argument two lines down" case). Two unrelated statements that merely look alike are never merged.
  4. Report — every cluster shows N/M (checkers that reported here / checkers that ran), a confidence badge, and, with --verbose, the exact signal that produced the grouping.

Confidence reflects cross-checker evidence only:

Badge Meaning
* HIGH Two different checkers report exactly the same line range
~ MED Two different checkers report overlapping line ranges
- LOW Joined only through a shared enclosing statement, --line-tolerance, or a single checker reported here

rety never collapses a cluster to a "same issue: yes/no" verdict. The output is always "N/M checkers found something here, here's what each said, here's how confident the grouping is."


Development

uv sync --all-groups          # installs rety in editable mode plus mypy, pytest, ruff
uv run pytest -q              # unit tests; no type checker needs to be installed
uv run mypy src               # strict
uv run ruff check src tests

# Run rety against all four real checkers without installing them globally
uv run --with pyright --with pyrefly --with ty rety check --require-all tests/fixtures/basic_errors.py

The adapter tests read real captured checker output from tests/fixtures/captured/. When a checker release changes its output format, recapture with the commands in tests/CHECKER_VERSIONS.md and update the pinned versions there.


License

MIT

Metadata

Release files for rety 0.1.0

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

Source distribution (sdist)

Source distribution for rety 0.1.0
File Size Uploaded
rety-0.1.0.tar.gz 34.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rety 0.1.0
File Interpreter ABI Platform
rety-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 78.0 kB

Release files / rety-0.1.0.tar.gz

Download URL rety-0.1.0.tar.gz
Size 34.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a504c6930754e462c38c4c4100599901503eb4a11ac21a4b8f69b6edd0fabd58
BLAKE2b-256 checksum
How to use checksums
b28c1bd4ec4eb6fb38ed5179bc0ec697bd8dcd32990ab0046889d5f3a5181bfe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

Release files / rety-0.1.0-py3-none-any.whl

Download URL rety-0.1.0-py3-none-any.whl
Size 43.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2224e91d3e462315e8ecceab2d1806d2cb7a80768e486aaba6f4e7e98da1da87
BLAKE2b-256 checksum
How to use checksums
be484285378f6f77b557754f47b0ebb9530016d2fc83dc93e952e5adf6b42ada
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.2

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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