rabbitinspect 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rabbitinspect-0.2.0/.github/dependabot.yml +45 -0
- rabbitinspect-0.2.0/.github/workflows/ci.yml +88 -0
- rabbitinspect-0.2.0/.github/workflows/publish.yml +87 -0
- rabbitinspect-0.2.0/.gitignore +25 -0
- rabbitinspect-0.2.0/.python-version +1 -0
- rabbitinspect-0.2.0/CHANGELOG.md +97 -0
- rabbitinspect-0.2.0/Cargo.lock +646 -0
- rabbitinspect-0.2.0/Cargo.toml +20 -0
- rabbitinspect-0.2.0/LICENSE +21 -0
- rabbitinspect-0.2.0/PKG-INFO +262 -0
- rabbitinspect-0.2.0/README.md +236 -0
- rabbitinspect-0.2.0/pyproject.toml +62 -0
- rabbitinspect-0.2.0/python/rabbitinspect/__init__.py +12 -0
- rabbitinspect-0.2.0/python/rabbitinspect/__main__.py +231 -0
- rabbitinspect-0.2.0/python/rabbitinspect/_core.pyi +8 -0
- rabbitinspect-0.2.0/python/rabbitinspect/py.typed +0 -0
- rabbitinspect-0.2.0/src/analyze.rs +629 -0
- rabbitinspect-0.2.0/src/checks.rs +3581 -0
- rabbitinspect-0.2.0/src/fix.rs +25 -0
- rabbitinspect-0.2.0/src/lib.rs +70 -0
- rabbitinspect-0.2.0/tests/fixtures/all_checks_bad.py +446 -0
- rabbitinspect-0.2.0/tests/fixtures/all_checks_good.py +332 -0
- rabbitinspect-0.2.0/tests/fixtures/sample_bad.py +92 -0
- rabbitinspect-0.2.0/tests/fixtures/sample_good.py +57 -0
- rabbitinspect-0.2.0/tests/test_checks.py +1430 -0
- rabbitinspect-0.2.0/uv.lock +216 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python runtime + dev dependencies pinned in pyproject.toml.
|
|
4
|
+
# Dependabot picks up the [project.optional-dependencies] groups
|
|
5
|
+
# automatically; PRs are grouped per-week to keep noise low.
|
|
6
|
+
- package-ecosystem: "pip"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: "weekly"
|
|
10
|
+
day: "monday"
|
|
11
|
+
open-pull-requests-limit: 5
|
|
12
|
+
labels:
|
|
13
|
+
- "dependencies"
|
|
14
|
+
groups:
|
|
15
|
+
python-deps:
|
|
16
|
+
patterns:
|
|
17
|
+
- "*"
|
|
18
|
+
|
|
19
|
+
# GitHub Actions versions (uses: actions/checkout@vN, etc.). Pin
|
|
20
|
+
# bumps land alongside ecosystem-wide security advisories.
|
|
21
|
+
- package-ecosystem: "github-actions"
|
|
22
|
+
directory: "/"
|
|
23
|
+
schedule:
|
|
24
|
+
interval: "weekly"
|
|
25
|
+
day: "monday"
|
|
26
|
+
open-pull-requests-limit: 3
|
|
27
|
+
labels:
|
|
28
|
+
- "dependencies"
|
|
29
|
+
- "ci"
|
|
30
|
+
|
|
31
|
+
# Rust crates (PyO3 hot path). Cargo.lock is tracked so security
|
|
32
|
+
# advisories on transitive deps surface as PRs.
|
|
33
|
+
- package-ecosystem: "cargo"
|
|
34
|
+
directory: "/"
|
|
35
|
+
schedule:
|
|
36
|
+
interval: "weekly"
|
|
37
|
+
day: "monday"
|
|
38
|
+
open-pull-requests-limit: 5
|
|
39
|
+
labels:
|
|
40
|
+
- "dependencies"
|
|
41
|
+
- "rust"
|
|
42
|
+
groups:
|
|
43
|
+
rust-deps:
|
|
44
|
+
patterns:
|
|
45
|
+
- "*"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
env:
|
|
10
|
+
CARGO_TERM_COLOR: always
|
|
11
|
+
PYTHON_VERSION: "3.14"
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
lint:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
21
|
+
- name: Install uv
|
|
22
|
+
run: pip install uv
|
|
23
|
+
- name: Install linters
|
|
24
|
+
run: uv pip install ruff ty tomli --system
|
|
25
|
+
- name: Run ruff
|
|
26
|
+
run: ruff check python/ tests/ --ignore=E501
|
|
27
|
+
- name: Run ty
|
|
28
|
+
run: ty check python/rabbitinspect/ --python-version 3.14
|
|
29
|
+
|
|
30
|
+
rust:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v6
|
|
34
|
+
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
35
|
+
- uses: Swatinem/rust-cache@v2
|
|
36
|
+
- name: Build
|
|
37
|
+
run: cargo build --release
|
|
38
|
+
- name: Test
|
|
39
|
+
run: cargo test
|
|
40
|
+
|
|
41
|
+
build-wheel:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v6
|
|
45
|
+
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
46
|
+
- uses: Swatinem/rust-cache@v2
|
|
47
|
+
- uses: actions/setup-python@v6
|
|
48
|
+
with:
|
|
49
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
50
|
+
- name: Install uv
|
|
51
|
+
run: pip install uv
|
|
52
|
+
- name: Build wheel
|
|
53
|
+
run: |
|
|
54
|
+
uv pip install maturin --system
|
|
55
|
+
maturin build --release --out dist
|
|
56
|
+
- uses: actions/upload-artifact@v7
|
|
57
|
+
with:
|
|
58
|
+
name: wheel
|
|
59
|
+
path: dist/*.whl
|
|
60
|
+
|
|
61
|
+
test-linux:
|
|
62
|
+
needs: build-wheel
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
strategy:
|
|
65
|
+
matrix:
|
|
66
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
70
|
+
with:
|
|
71
|
+
python-version: ${{ matrix.python-version }}
|
|
72
|
+
- name: Install uv
|
|
73
|
+
run: pip install uv
|
|
74
|
+
- uses: actions/cache@v5
|
|
75
|
+
with:
|
|
76
|
+
path: .venv
|
|
77
|
+
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml', 'uv.lock') }}
|
|
78
|
+
restore-keys: venv-${{ runner.os }}-${{ matrix.python-version }}-
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: uv sync --frozen
|
|
81
|
+
- uses: actions/download-artifact@v8
|
|
82
|
+
with:
|
|
83
|
+
name: wheel
|
|
84
|
+
path: dist/
|
|
85
|
+
- name: Install wheel
|
|
86
|
+
run: uv pip install dist/*.whl --reinstall
|
|
87
|
+
- name: Run tests
|
|
88
|
+
run: uv run pytest tests/ -v
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
wheels:
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
include:
|
|
12
|
+
- os: ubuntu-latest
|
|
13
|
+
target: x86_64
|
|
14
|
+
- os: ubuntu-24.04-arm
|
|
15
|
+
target: aarch64
|
|
16
|
+
- os: macos-latest
|
|
17
|
+
target: x86_64
|
|
18
|
+
- os: macos-latest
|
|
19
|
+
target: aarch64
|
|
20
|
+
- os: windows-latest
|
|
21
|
+
target: x86_64
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v6
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-python@v6
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.14"
|
|
29
|
+
|
|
30
|
+
- name: Build Wheels
|
|
31
|
+
uses: PyO3/maturin-action@v1.51.0
|
|
32
|
+
with:
|
|
33
|
+
target: ${{ matrix.target }}
|
|
34
|
+
args: --release --out dist --interpreter python3.10 python3.11 python3.12 python3.13
|
|
35
|
+
sccache: 'true'
|
|
36
|
+
manylinux: manylinux_2_28
|
|
37
|
+
|
|
38
|
+
- uses: actions/upload-artifact@v7
|
|
39
|
+
with:
|
|
40
|
+
name: wheels-${{ matrix.os }}-${{ matrix.target }}
|
|
41
|
+
path: dist/*.whl
|
|
42
|
+
|
|
43
|
+
sdist:
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v6
|
|
47
|
+
|
|
48
|
+
- name: Build sdist
|
|
49
|
+
uses: PyO3/maturin-action@v1.51.0
|
|
50
|
+
with:
|
|
51
|
+
command: sdist
|
|
52
|
+
args: --out dist
|
|
53
|
+
|
|
54
|
+
- uses: actions/upload-artifact@v7
|
|
55
|
+
with:
|
|
56
|
+
name: wheels-sdist
|
|
57
|
+
path: dist/*.tar.gz
|
|
58
|
+
|
|
59
|
+
publish:
|
|
60
|
+
needs: [wheels, sdist]
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
environment:
|
|
63
|
+
name: pypi
|
|
64
|
+
url: https://pypi.org/p/rabbitinspect
|
|
65
|
+
permissions:
|
|
66
|
+
id-token: write
|
|
67
|
+
contents: write
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/download-artifact@v8
|
|
70
|
+
with:
|
|
71
|
+
pattern: wheels-*
|
|
72
|
+
merge-multiple: true
|
|
73
|
+
path: dist/
|
|
74
|
+
|
|
75
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
76
|
+
with:
|
|
77
|
+
attestations: true
|
|
78
|
+
|
|
79
|
+
- uses: actions/checkout@v6
|
|
80
|
+
with:
|
|
81
|
+
fetch-depth: 0
|
|
82
|
+
|
|
83
|
+
- name: Create GitHub Release
|
|
84
|
+
uses: softprops/action-gh-release@v3
|
|
85
|
+
with:
|
|
86
|
+
files: dist/*
|
|
87
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Rust build artifacts
|
|
13
|
+
target/
|
|
14
|
+
|
|
15
|
+
# Compiled Python extensions (generated by maturin)
|
|
16
|
+
*.so
|
|
17
|
+
*.pyd
|
|
18
|
+
*.dylib
|
|
19
|
+
|
|
20
|
+
# uv lockfile (optional)
|
|
21
|
+
# uv.lock
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.vscode/
|
|
25
|
+
.idea/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.0] - 2026-05-31
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
#### Infrastructure
|
|
10
|
+
- `--select` / `--ignore` CLI flags for filtering checks
|
|
11
|
+
- `--format json` output option
|
|
12
|
+
- `# noqa: RABNNN` inline comment suppression
|
|
13
|
+
- `[tool.rabbitinspect]` configuration via `pyproject.toml`
|
|
14
|
+
- `tomli` fallback for Python 3.10 compatibility
|
|
15
|
+
- GitHub Actions CI with lint (ruff + ty), Rust build, wheel build, and multi-Python testing (3.10–3.14)
|
|
16
|
+
- GitHub Actions publish workflow with cibuildwheel for Linux (x86_64 + aarch64), macOS (x86_64 + arm64), and Windows
|
|
17
|
+
- Type stub (`_core.pyi`) for the compiled Rust extension
|
|
18
|
+
- Dev dependencies: `ruff`, `ty`, `tomli`
|
|
19
|
+
|
|
20
|
+
#### Rust refactoring
|
|
21
|
+
- `iter_fn_args()` helper eliminates repeated `posonlyargs.iter().chain(args.args.iter()).chain(kwonlyargs.iter())` pattern across 7 checkers
|
|
22
|
+
- `count_fn_args()` helper for counting function parameters
|
|
23
|
+
- Overlapping fix detection — `apply_fixes` skips fixes that overlap with already-applied regions
|
|
24
|
+
|
|
25
|
+
#### New checks (46 total)
|
|
26
|
+
|
|
27
|
+
| Code | Rule | Fix |
|
|
28
|
+
|------|------|-----|
|
|
29
|
+
| RAB046 | `sorted(x)[0]` → `min(x)` | ✅ |
|
|
30
|
+
| RAB047 | `sorted(x)[-1]` → `max(x)` | ✅ |
|
|
31
|
+
| RAB048 | `not x is None` → `x is not None` | ✅ |
|
|
32
|
+
| RAB049 | `x = x + 1` → `x += 1` | ✅ |
|
|
33
|
+
| RAB050 | `for i in range(len(seq))` — iterate directly | ❌ |
|
|
34
|
+
| RAB051 | `d.setdefault(k, []).append(v)` → `defaultdict` | ❌ |
|
|
35
|
+
| RAB052 | `type(x) == A or type(x) == B` → `isinstance(x, (A, B))` | ✅ |
|
|
36
|
+
| RAB053 | `x is True` / `x is False` → `x` / `not x` | ✅ |
|
|
37
|
+
| RAB054 | `if not x: x = y` → `x = x or y` | ✅ |
|
|
38
|
+
| RAB055 | Unused loop variable → `_` | ✅ |
|
|
39
|
+
| RAB056 | Nested `with` statements | ❌ |
|
|
40
|
+
| RAB057 | `s.startswith('a') or s.startswith('b')` → `s.startswith(('a', 'b'))` | ✅ |
|
|
41
|
+
| RAB058 | `return True if cond else False` → `return cond` | ✅ |
|
|
42
|
+
| RAB059 | `while True:` without `break` → infinite loop | ❌ |
|
|
43
|
+
| RAB060 | `sorted(x).sort()` → `x.sort()` | ✅ |
|
|
44
|
+
| RAB061 | `from module import *` — wildcard import | ❌ |
|
|
45
|
+
| RAB062 | Redundant `pass` after docstring | ✅ |
|
|
46
|
+
| RAB063 | `x is 5` / `x is "str"` → `x == 5` / `x == "str"` | ✅ |
|
|
47
|
+
| RAB064 | `__init__` returning non-None value | ✅ |
|
|
48
|
+
| RAB065 | `if True:` / `if False:` dead code | ❌ |
|
|
49
|
+
| RAB066 | Function definition inside a loop | ❌ |
|
|
50
|
+
| RAB067 | Variable/function shadows built-in name | ✅ |
|
|
51
|
+
| RAB068 | `raise Exc()` without `from` inside `except` | ❌ |
|
|
52
|
+
| RAB069 | `dict()` / `list()` / `tuple()` → `{}` / `[]` / `()` | ✅ |
|
|
53
|
+
| RAB070 | `x == ""` / `x == []` / `x == {}` → `not x` / `x` | ✅ |
|
|
54
|
+
| RAB071 | List comp inside `str.join()` → generator | ✅ |
|
|
55
|
+
| RAB072 | Except handler only re-raises | ❌ |
|
|
56
|
+
| RAB073 | Old-style `%` string formatting | ❌ |
|
|
57
|
+
| RAB074 | `os.path.*` → `pathlib.Path` | ❌ |
|
|
58
|
+
| RAB075 | `isinstance(x, (A,))` → `isinstance(x, A)` | ✅ |
|
|
59
|
+
| RAB076 | `str()` on value already a string | ✅ |
|
|
60
|
+
| RAB078 | `except Exception: pass` — silent swallow | ❌ |
|
|
61
|
+
| RAB079 | `__del__` method defined | ❌ |
|
|
62
|
+
| RAB080 | `list(d.keys())` / `list(d.values())` → `list(d)` | ✅ |
|
|
63
|
+
| RAB083 | Nested ternary expression | ❌ |
|
|
64
|
+
| RAB085 | `reversed(sorted(x))` → `sorted(x, reverse=True)` | ✅ |
|
|
65
|
+
| RAB087 | `{k: v for k, v in zip(...)}` → `dict(zip(...))` | ✅ |
|
|
66
|
+
| RAB088 | `while len(x) > 0` → `while x` | ✅ |
|
|
67
|
+
| RAB089 | `copy.copy(x)` → `x.copy()` | ✅ |
|
|
68
|
+
|
|
69
|
+
- Initial release with 43 checks (RAB001–RAB045, RAB101–RAB102)
|
|
70
|
+
- Rust+PyO3 analysis engine
|
|
71
|
+
- CLI with ruff-style output and `--fix` flag
|
|
72
|
+
- Auto-fix support for 22 checks
|
|
73
|
+
- Comprehensive test suite (255 tests)
|
|
74
|
+
- Native generics (RAB039) and union syntax (RAB044) checks
|
|
75
|
+
- Cognitive and cyclomatic complexity analysis
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
#### Bugs
|
|
80
|
+
- **RAB001**: `x += 1` no longer incorrectly reports `x` as unused (augmented assignment target is now also recorded as used)
|
|
81
|
+
- **RAB040**: `@dataclass(frozen=True)` now correctly produces `@dataclass(frozen=True, slots=True)`, preserving existing keyword arguments
|
|
82
|
+
- **RAB060**: `sorted(x, reverse=True).sort()` is now skipped (incorrect semantics)
|
|
83
|
+
- **RAB067**: Function definition fix no longer destroys the function body (only the name is replaced)
|
|
84
|
+
- **RAB068**: Uses a counter stack instead of a boolean for `enter_except`/`exit_except`, correctly handling nested except handlers; resets on function scope boundaries
|
|
85
|
+
- **B5**: `apply_fixes` now handles overlapping fix ranges by skipping fixes that overlap with already-applied regions (e.g., RAB052 + RAB006 on `type(x) == int or type(x) == str`)
|
|
86
|
+
- **B7**: `contains_name_ref` and `stmt_contains_name_ref` now handle `Await`, `Yield`, `YieldFrom`, `Match`, `ClassDef`, `AsyncFor`, `Import`, `ImportFrom`, `TypeAlias` — eliminating false positives in RAB055
|
|
87
|
+
- **B10**: `tomllib` import has a `try/except` fallback to `tomli` for Python 3.10
|
|
88
|
+
|
|
89
|
+
#### Code quality
|
|
90
|
+
- ComplexityChecker, FunctionLengthChecker, TooManyParamsChecker, CognitiveComplexityChecker now report the actual function position instead of `(0, 0)`
|
|
91
|
+
- RAB055 now handles `AsyncFor` loops in addition to `For`
|
|
92
|
+
- Fixture files have `# ruff: noqa` headers to avoid false positives in linting
|
|
93
|
+
- Duplicate `bad_range_len` function in test fixtures renamed
|
|
94
|
+
|
|
95
|
+
### Documentation
|
|
96
|
+
- Complete README rewrite with all 89 checks, CLI flags, `# noqa`, `pyproject.toml` config, and expanded performance rationale table
|
|
97
|
+
- CHANGELOG added
|