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.
@@ -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