Skip to content

Releases: BHUVANSH855/PyRift

pyrift v0.8.0 — 104 rules, 519 tests, version-guard awareness, dynamic imports

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 26 Aug 16:36

Major release — production grade

New rules (15 new)

  • CPY046–CPY057, CPY062–CPY063 — Python 3.14/3.15 coverage
  • PPY046–PPY047 — PyPy additions

Architecture

  • pyrift.analysis — shared AST utilities (imports, calls, scope)
  • Version-guard awareness — if sys.version_info >= (3,11): from typing import Self no longer flagged
  • Dynamic import detection — importlib.import_module('cgi') now caught
  • by_statement() dedup — multi-name from imports produce one finding

Quality

  • 519 tests (was 392)
  • 81/81 golden benchmark cases
  • Self-scan: 120 files, 0 findings, 0 parse errors
  • Corpus: 7 real packages (requests, flask, asyncio, email, httpx, logging, http)
  • Runtime harness: 5 rules verified across CPython 3.10–3.15
  • CI: CPython 3.10–3.14 + PyPy3.11 all run full benchmark suite

Fixed

  • CPY057: protocol=None now flagged (same as no protocol); pickle.Pickler() detected
  • PPY009: no longer flags id() used as dict key
  • 15 BOM-corrupted files stripped — pyrift now correctly scans BOM files
  • Duplicate findings from multi-name from imports fixed
  • ASCII-safe output — no Windows console crashes
  • cpy050 filename typo fixed

Install / upgrade

pip install --upgrade pyrift

pyrift v0.7.0 — baseline transparency

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 25 Aug 00:33

What's new

Baseline suppressed count now visible in all output formats

When a baseline is active, pyrift now shows exactly how many
findings were suppressed — so you always know the baseline is working.

Text output:
✅ No issues found — 23 file(s) scanned.
Baseline suppressed: 17 finding(s)

JSON output:
{
"summary": {
"files_scanned": 23,
"total_findings": 0,
"baseline_suppressed": 17,
"score": 100
}
}

Markdown output:
| Baseline suppressed | 17 |

Baseline workflow

# Create baseline from current findings
pyrift baseline create .

# Scan — old findings suppressed, new findings reported
pyrift scan .

Stats

  • 90 rules (45 CPython + 45 PyPy)
  • 392 tests passing
  • Zero dependencies

Install / upgrade

pip install --upgrade pyrift

pyrift v0.6.0 — target-aware scanning, baseline engine, 392 tests

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 25 Aug 00:33
feat: v0.6.0 — target-aware scanning, baseline engine, fingerprinting…

pyrift v0.5.0 — 90 rules, 316 tests

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 24 Aug 19:50

The biggest release yet

90 rules — 45 CPython + 45 PyPy

316 tests — all passing on Python 3.10, 3.11, 3.12, 3.13

Zero dependencies — pure Python

What's new in v0.5.0

CPython rules added (CPY019–CPY045)

  • distutils removed in Python 3.12+
  • datetime.utcnow() and utcfromtimestamp() deprecated in 3.12
  • asyncio.get_event_loop() raises RuntimeError in 3.12+
  • asyncio.iscoroutinefunction() deprecated in 3.12
  • Bitwise inversion on bool deprecated in 3.12
  • typing.TypeGuard, ParamSpec, TypeAlias, Never, TypeVarTuple, Unpack, Required, assert_never, reveal_type
  • locale.resetlocale(), lib2to3, typing.io, typing.re removed in 3.13
  • zoneinfo, graphlib require Python 3.9+
  • str.removeprefix/removesuffix, pathlib.is_relative_to require Python 3.9+
  • int.bit_count(), aiter(), anext(), math.lcm() require Python 3.10+
  • dict | merge operator requires Python 3.9+
  • NaN hash behaviour changed in 3.10

PyPy rules added (PPY008–PPY045)

  • threading.local(), gc.collect(), sys.getsizeof(), sys.settrace()
  • os.fork(), os.urandom(), subprocess.PIPE, open() buffering
  • Generator GC timing, string concatenation O(n²), float('nan') identity
  • builtins always module, readline.parse_and_bind() ignored
  • sys.setrecursionlimit(), sys.flags, inspect.ismethod() differences
  • C extension packages, decimal backend, decimal module differences
  • Exception variable

pyrift v0.4.0 — 20 rules, 79 tests

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 24 Aug 11:50

What's new

Added

  • CPY011 — typing.Self requires Python 3.11+ (PEP 673)
  • CPY012 — typing.LiteralString requires Python 3.11+ (PEP 675)
  • CPY013 — typing.override requires Python 3.12+ (PEP 698)
  • 9 new tests covering all 3 rules

Stats

  • 20 rules (13 CPython + 7 PyPy)
  • 79 tests passing on Python 3.10, 3.11, 3.12, 3.13
  • Zero dependencies

Install

pip install pyrift
pip install --upgrade pyrift

pyrift v0.3.1 — CPY001 false positive fix

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 24 Aug 11:23

What changed

Fixed

  • CPY001 false positive — dict view comparisons against set and
    frozenset are now correctly skipped. Only comparisons against
    list and tuple are flagged.
  • Rule description updated to clarify the actual risk pattern.

Tests

  • 3 new tests added covering the false positive cases
  • Total: 70 tests passing

Install

pip install pyrift==0.3.1

Upgrade

pip install --upgrade pyrift


Bug reported by @fix error on Python Discord within 22 minutes
of the v0.3.0 launch. Thanks for the sharp feedback.

pyrift v0.3.0 — 17 rules, 67 tests, zero dependencies

Choose a tag to compare

@BHUVANSH855 BHUVANSH855 released this 24 Aug 10:03
6439a18

First public release of pyrift.

Install

pip install pyrift

What it does

Detects silent Python behaviour differences that linters and security
scanners both miss — code that runs without errors but produces wrong
results on different Python versions or PyPy.

Rules — 17 total

CPython version compatibility (10 rules)

ID What it catches
CPY001 Dict ordering assumption
CPY002 Exception.add_note() requires Python 3.11+
CPY003 X | Y union type syntax requires Python 3.10+
CPY004 tomllib requires Python 3.11+
CPY005 match/case requires Python 3.10+
CPY006 asyncio.timeout() / TaskGroup requires Python 3.11+
CPY007 21 modules removed in Python 3.13
CPY008 __slots__ + base class inheritance pitfall
CPY009 ExceptionGroup requires Python 3.11+
CPY010 @dataclass(slots=True) requires Python 3.10+

PyPy runtime differences (7 rules)

ID What it catches
PPY001 __del__ resource cleanup silently leaks on PyPy
PPY002 ctypes may silently fail on PyPy
PPY003 sys.getrefcount() meaningless on PyPy
PPY004 weakref.proxy() raises ReferenceError unpredictably
PPY005 File writes may be lost on PyPy without explicit flush
PPY006 Monkey-patching built-in types broken on PyPy
PPY007 sys.intern() identity not guaranteed on PyPy

Stats

  • 67 tests — all passing on Python 3.10, 3.11, 3.12, 3.13
  • Zero dependencies — pure Python
  • MIT license

Links