Releases: BHUVANSH855/PyRift
Release list
pyrift v0.8.0 — 104 rules, 519 tests, version-guard awareness, dynamic imports
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 Selfno 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
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
feat: v0.6.0 — target-aware scanning, baseline engine, fingerprinting…
pyrift v0.5.0 — 90 rules, 316 tests
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
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
What changed
Fixed
- CPY001 false positive — dict view comparisons against
setand
frozensetare now correctly skipped. Only comparisons against
listandtupleare 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
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