Skip to main content

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
CPY011 typing.Self requires Python 3.11+ Error CPython ≤ 3.10
CPY012 typing.LiteralString requires Python 3.11+ Error CPython ≤ 3.10
CPY013 typing.override requires Python 3.12+ Error CPython ≤ 3.11
CPY014 typing.TypeAlias requires Python 3.10+ Error CPython ≤ 3.9
CPY015 typing.Never requires Python 3.11+ Error CPython ≤ 3.10
CPY016 typing.TypeVarTuple requires Python 3.11+ Error CPython ≤ 3.10
CPY017 typing.Unpack requires Python 3.11+ Error CPython ≤ 3.10
CPY018 typing.Required / NotRequired requires Python 3.11+ Error CPython ≤ 3.10
CPY019 distutils removed in Python 3.12+ Error CPython ≥ 3.12
CPY020 datetime.UTC requires Python 3.11+ Error CPython ≤ 3.10
CPY021 asyncio.iscoroutinefunction() deprecated since 3.12 Warning CPython ≥ 3.12
CPY022 Bitwise inversion on bool deprecated in 3.12 Warning CPython ≥ 3.12
CPY023 multiprocessing default start method changing in 3.14 Warning CPython ≥ 3.14
CPY024 typing.TypeGuard requires Python 3.10+ Error CPython ≤ 3.9
CPY025 typing.ParamSpec requires Python 3.10+ Error CPython ≤ 3.9
CPY026 typing.io and typing.re removed in Python 3.13 Error CPython ≥ 3.13
CPY027 locale.resetlocale() removed in Python 3.13 Error CPython ≥ 3.13
CPY028 lib2to3 removed in Python 3.13 Error CPython ≥ 3.13
CPY029 locals() semantics changed in Python 3.13 Warning CPython ≥ 3.13
CPY030 sys.path no longer accepts bytes in Python 3.11+ Error CPython ≥ 3.11
CPY031 typing.assert_never requires Python 3.11+ Error CPython ≤ 3.10
CPY032 typing.reveal_type requires Python 3.11+ Error CPython ≤ 3.10
CPY033 pathlib.Path.is_relative_to() requires Python 3.9+ Error CPython ≤ 3.8
CPY034 int.bit_count() requires Python 3.10+ Error CPython ≤ 3.9
CPY035 str.removeprefix/removesuffix requires Python 3.9+ Error CPython ≤ 3.8
CPY036 datetime.utcnow() deprecated since Python 3.12 Warning CPython ≥ 3.12
CPY037 datetime.utcfromtimestamp() deprecated since Python 3.12 Warning CPython ≥ 3.12
CPY038 asyncio.get_event_loop() raises RuntimeError in 3.12+ Error CPython ≥ 3.12
CPY039 zoneinfo module requires Python 3.9+ Error CPython ≤ 3.8
CPY040 graphlib module requires Python 3.9+ Error CPython ≤ 3.8
CPY041 dict | merge operator requires Python 3.9+ Error CPython ≤ 3.8
CPY042 aiter() and anext() builtins require Python 3.10+ Error CPython ≤ 3.9
CPY043 math.lcm() requires Python 3.9+ Error CPython ≤ 3.8
CPY044 math.gcd() multi-arg form requires Python 3.9+ Error CPython ≤ 3.8
CPY045 NaN hash behaviour changed in Python 3.10 Warning CPython ≥ 3.10

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
PPY008 threading.local() cleanup timing differs on PyPy Warning PyPy all versions
PPY009 id() values not stable across GC cycles on PyPy Warning PyPy all versions
PPY010 gc.collect() behaviour differs on PyPy Warning PyPy all versions
PPY011 array.array('u') type code removed in Python 3.13 Error CPython ≥ 3.13
PPY012 Overriding built-in methods behaves differently on PyPy Warning PyPy all versions
PPY013 sys.getsizeof() raises TypeError on PyPy Error PyPy all versions
PPY014 String concatenation in loops is O(n²) on PyPy Warning PyPy all versions
PPY015 Generator cleanup timing differs on PyPy Warning PyPy all versions
PPY016 Instance __dict__ ordering not guaranteed on PyPy Warning PyPy all versions
PPY017 Adding __del__ to existing class not called on PyPy Error PyPy all versions
PPY018 sys.setrecursionlimit() behaviour differs on PyPy Warning PyPy all versions
PPY019 float('nan') identity differs between CPython and PyPy Warning PyPy all versions
PPY020 dict(**kwargs) requires string keys on PyPy Error PyPy all versions
PPY021 Socket not closed promptly on PyPy Warning PyPy all versions
PPY022 PYTHONHASHSEED=0 has no effect on PyPy Warning PyPy all versions
PPY023 inspect.ismethod() returns different results on PyPy Warning PyPy all versions
PPY024 timeit reports average not minimum on PyPy Info PyPy all versions
PPY025 Set iteration order differs between CPython and PyPy Warning PyPy all versions
PPY026 __builtins__ is always a module on PyPy Warning PyPy all versions
PPY027 Deleting module/class attributes is slower on PyPy Warning PyPy all versions
PPY028 readline.parse_and_bind() silently ignored on PyPy Warning PyPy all versions
PPY029 Assigning to __builtins__ has no effect on PyPy Warning PyPy all versions
PPY030 sys.flags values may differ between CPython and PyPy Warning PyPy all versions
PPY031 Integer is identity semantics differ on PyPy Info PyPy all versions
PPY032 Mutating dict keys raises RuntimeError on PyPy Warning PyPy all versions
PPY033 Exceptions in __del__ appear at unpredictable times Warning PyPy all versions
PPY034 hash() values may differ between CPython and PyPy Info PyPy all versions
PPY035 C extension packages may not work correctly on PyPy Warning PyPy all versions
PPY036 open() line buffering behaves differently on PyPy Warning PyPy all versions
PPY037 os.urandom() source may differ on PyPy Info PyPy all versions
PPY038 decimal module uses different backend on PyPy Info PyPy all versions
PPY039 os.fork() may not work correctly on all PyPy platforms Warning PyPy all versions
PPY040 subprocess.PIPE buffering may cause deadlocks on PyPy Warning PyPy all versions
PPY041 dict | operator requires PyPy 7.3.7+ Info PyPy < 7.3.7
PPY042 print(flush=True) may not flush immediately on PyPy Info PyPy all versions
PPY043 __slots__ memory savings differ on PyPy Info PyPy all versions
PPY044 Exception variable cleanup timing differs on PyPy Info PyPy all versions
PPY045 sys.settrace() disables JIT 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.5.0
    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:

  • CPY046typing.TypeIs requires Python 3.13+
  • CPY047typing.ReadOnly requires Python 3.13+
  • Pre-commit hook native support
  • VS Code extension
  • GitHub Action marketplace listing

See CONTRIBUTING.md to add a rule yourself — rule IDs CPY046+ and PPY046+ 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.5.0
  • Rules: 90 (45 CPython + 45 PyPy)
  • Tests: 316 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.5.0.tar.gz (64.0 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.5.0-py3-none-any.whl (110.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for pyrift-0.5.0.tar.gz
Algorithm Hash digest
SHA256 233aaee7d2dc71fa2106ac0b9346557314ee1faae55e5f8701fc17767cfd5f62
MD5 60b167016c0f2d4f6fad854e830fcad4
BLAKE2b-256 ce940de56194586957224f53ac60163d3d3f0ea220971d28f4aec8ec29b0303e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pyrift-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 110.0 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.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d51ff96ee6049552e81ef7ec49d05738ef6fb40a4af4d443db898c793367b40a
MD5 7e61fc2847a5ae8df1fe8fbc3813d659
BLAKE2b-256 249ad7cbae1990c087875eb5074933f437feae779a6157cafb700398a77f613e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 files

0.4.0

2 files

0.3.1

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