Skip to main content

pyrift

Detect silent Python behaviour differences across CPython versions and CPython vs PyPy.

PyPI version Python 3.10+ Tests License: MIT PyPI Downloads


What is pyrift?

Python upgrades and cross-runtime compatibility (CPython vs PyPy) introduce silent behaviour differences — code that runs without errors but produces wrong results, leaks resources, or crashes only in certain environments.

These are not syntax errors. Linters won't catch them. They are not CVEs. Security scanners won't catch them. They only appear at runtime, often in production.

pyrift statically detects these patterns before they become bugs.


Install

pip install pyrift

Zero external dependencies. Pure Python. Works on Python 3.10+.


Quick start — CLI

# Scan current directory
pyrift scan .

# Scan a specific path
pyrift scan ./src

# JSON output (for CI integration)
pyrift scan . --format json

# Markdown report saved to file
pyrift scan . --format markdown --output report.md

# Check version
pyrift --version

Example output

[ERROR] src/server.py:42 CPY002: Exception.add_note() requires Python 3.11+
→ Guard with: if sys.version_info >= (3, 11): e.add_note(...)

[ERROR] src/compat.py:17 CPY007: Module removed in Python 3.13
→ Find a third-party replacement for 'cgi' on PyPI

[WARNING] src/resource.py:88 PPY001: Relying on del for resource cleanup breaks on PyPy
→ Use context managers (with statement) or try/finally blocks

Scanned 23 file(s). Found 2 error(s), 1 warning(s). Score: 77/100

Quick start — Python API

import pyrift

# Scan a directory
result = pyrift.scan("./src")

print(result)
# ScanResult(files=23, errors=2, warnings=1, score=77)

# Iterate findings
for finding in result.findings:
    print(finding)

# Filter by severity
for error in result.errors:
    print(f"{error.file}:{error.line}{error.title}")

# Export formats
json_output     = pyrift.to_json(result)
markdown_output = pyrift.to_markdown(result)
text_output     = pyrift.to_text(result)

# Scan a single file
findings = pyrift.scan_file("./src/utils.py")

Rules

CPython rules — version compatibility

ID Title Severity Affects
CPY001 Dict ordering assumption Warning CPython < 3.7
CPY002 Exception.add_note() requires Python 3.11+ Error CPython ≤ 3.10
CPY003 X | Y union type syntax requires Python 3.10+ Error CPython ≤ 3.9
CPY004 tomllib requires Python 3.11+ Error CPython ≤ 3.10
CPY005 match/case requires Python 3.10+ Error CPython ≤ 3.9
CPY006 asyncio.timeout() / TaskGroup requires Python 3.11+ Error CPython ≤ 3.10
CPY007 Module removed in Python 3.13 (21 modules) Error CPython ≥ 3.13
CPY008 __slots__ may not prevent __dict__ with base classes Info All versions
CPY009 ExceptionGroup requires Python 3.11+ Error CPython ≤ 3.10
CPY010 @dataclass(slots=True) requires Python 3.10+ Error CPython ≤ 3.9

PyPy rules — runtime differences

ID Title Severity Affects
PPY001 Relying on __del__ for resource cleanup Error PyPy all versions
PPY002 ctypes usage may silently fail Warning PyPy all versions
PPY003 sys.getrefcount() is meaningless on PyPy Error PyPy all versions
PPY004 weakref.proxy() raises ReferenceError unpredictably Warning PyPy all versions
PPY005 File write without explicit flush may lose data Warning PyPy all versions
PPY006 Monkey-patching built-in types behaves differently Warning PyPy all versions
PPY007 sys.intern() identity guarantees differ on PyPy Warning PyPy all versions

Full rule documentation: docs/rules.md


Use in CI

Add pyrift to your GitHub Actions workflow:

- name: Run pyrift
  run: |
    pip install pyrift
    pyrift scan . --format json --output pyrift-report.json
    pyrift scan .

Exit code is 1 when errors are found — fails the CI build automatically. Use --exit-zero to report without failing.


Use with pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/BHUVANSH855/pyrift
    rev: v0.3.1
    hooks:
      - id: pyrift

Why pyrift?

Tool What it catches What it misses
pylint / ruff Style, common bugs Runtime behaviour differences
mypy / pyright Type errors Runtime behaviour differences
pip-audit Known CVEs Behaviour differences
bandit Security patterns Behaviour differences
pyrift Silent runtime behaviour differences (that's the whole point)

pyrift does not replace any of these tools. It catches what they all miss.


Roadmap

Planned for upcoming versions — contributions welcome:

  • CPY011typing.Self requires Python 3.11+
  • CPY012typing.LiteralString requires Python 3.11+
  • CPY013@override decorator requires Python 3.12+
  • PPY008array.array behaviour differences on PyPy
  • PPY009decimal module precision differences on PyPy
  • Pre-commit hook native support
  • VS Code extension
  • GitHub Action marketplace listing

See CONTRIBUTING.md to add a rule yourself — rule IDs CPY011+ and PPY008+ are open for community contributions.


Contributing

Contributions are very welcome — especially new rules for behaviour differences you have personally encountered.

See CONTRIBUTING.md for the full guide.


Project status

  • Version: 0.3.1
  • Rules: 17 (10 CPython + 7 PyPy)
  • Tests: 70 passing
  • Dependencies: zero
  • Python: 3.10+

Author

Built by Bhuvansh Kataria — CPython contributor and PyPy toolkit author.


License

MIT — see LICENSE

Download files

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

Source Distribution

pyrift-0.3.1.tar.gz (26.3 kB view details)

Uploaded Source

Built Distribution

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

pyrift-0.3.1-py3-none-any.whl (30.2 kB view details)

Uploaded Python 3

File details

Details for the file pyrift-0.3.1.tar.gz.

File metadata

  • Download URL: pyrift-0.3.1.tar.gz
  • Upload date:
  • Size: 26.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.6

File hashes

Hashes for pyrift-0.3.1.tar.gz
Algorithm Hash digest
SHA256 7cbf00830ad0358902806ebd1fcef036cd1fcb4a71bbf37f9b2268e110d12084
MD5 0ff72050ca897b04be47a2636390c8ab
BLAKE2b-256 f20eb98a61c427c4ba0ed9adb69599e4052315ae0570da81199a87079218f137

See more details on using hashes here.

File details

Details for the file pyrift-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: pyrift-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 30.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.6

File hashes

Hashes for pyrift-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2f176a4e6436c3050d11490cbe8c83d98627ffd1dc316c82f6b1e5f90c140fcb
MD5 ba723bce7a50bc9e3ee7947e6346ddd1
BLAKE2b-256 473d078712487c7c78e022c5160355b7e0534750b011de46514ad1b171c2cc1f

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.0

2 files

0.4.0

2 files

This release

0.3.1 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

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