complexipy 6.0.1__tar.gz → 6.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.
- {complexipy-6.0.1 → complexipy-6.2.0}/.pre-commit-config.yaml +1 -1
- complexipy-6.2.0/AGENTS.md +132 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/Cargo.lock +1 -1
- {complexipy-6.0.1 → complexipy-6.2.0}/Cargo.toml +1 -1
- {complexipy-6.0.1 → complexipy-6.2.0}/PKG-INFO +39 -45
- {complexipy-6.0.1 → complexipy-6.2.0}/README.md +38 -44
- complexipy-6.2.0/complexipy/main.py +392 -0
- complexipy-6.2.0/complexipy/types.py +84 -0
- complexipy-6.2.0/complexipy/utils/config.py +163 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/constants.py +2 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/csv.py +2 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/diff.py +149 -43
- complexipy-6.2.0/complexipy/utils/ignored.py +58 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/json.py +2 -0
- complexipy-6.2.0/complexipy/utils/output.py +502 -0
- complexipy-6.2.0/complexipy/utils/paths.py +79 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/snapshot.py +81 -2
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/toml.py +72 -135
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/index.md +46 -35
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/usage-guide.md +17 -16
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/index.md +46 -35
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/usage-guide.md +17 -15
- {complexipy-6.0.1 → complexipy-6.2.0}/pyproject.toml +3 -1
- {complexipy-6.0.1 → complexipy-6.2.0}/src/runner.rs +26 -15
- complexipy-6.0.1/complexipy/main.py +0 -771
- complexipy-6.0.1/complexipy/types.py +0 -43
- complexipy-6.0.1/complexipy/utils/output.py +0 -312
- {complexipy-6.0.1 → complexipy-6.2.0}/.mdformat.toml +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/LICENSE +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/build-wasm.sh +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/__init__.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/_complexipy.pyi +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/api.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/py.typed +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/__init__.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/cache.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/dataclasses.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/gitlab.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy/utils/sarif.py +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/complexipy.toml +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/about.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/comparison-with-ruff.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/about.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/comparison-with-ruff.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/img/complexipy_icon.svg +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/es/understanding-scores.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/img/complexipy_icon.svg +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/docs/understanding-scores.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/mkdocs.es.yml +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/mkdocs.yml +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/serve-web-version.sh +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/classes.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/cognitive_complexity.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/helpers/exclude.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/helpers.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/lib.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/refactor_plans.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/utils.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/src/wasm.rs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/uv.lock +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/.vscode-test.mjs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/.vscodeignore +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/CHANGELOG.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/LICENSE +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/README.md +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/eslint.config.mjs +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/extension.js +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/img/complexipy.png +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/img/complexipy_icon.png +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/img/complexipy_icon.svg +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/jsconfig.json +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/package-lock.json +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/package.json +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/test/extension.test.js +0 -0
- {complexipy-6.0.1 → complexipy-6.2.0}/vscode/complexipy/test/statusbar.test.js +0 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# complexipy
|
|
2
|
+
|
|
3
|
+
> Cognitive complexity analyzer for Python — measures how hard code is for humans to understand.
|
|
4
|
+
|
|
5
|
+
## Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Language:** Python 3.8+ (CLI/API) + Rust (core engine via PyO3/maturin)
|
|
8
|
+
- **Framework:** Typer (CLI), Rich (terminal output)
|
|
9
|
+
- **Package Manager:** uv (Python), Cargo (Rust)
|
|
10
|
+
- **Build:** maturin (Rust → Python extension), wasm-pack (Rust → WASM)
|
|
11
|
+
- **Docs:** MkDocs Material (EN + ES)
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
complexipy/
|
|
17
|
+
├── src/ # Rust core engine
|
|
18
|
+
│ ├── cognitive_complexity.rs # AST walking + complexity scoring algorithm
|
|
19
|
+
│ ├── classes.rs # Data types (FunctionComplexity, RefactorPlan, etc.)
|
|
20
|
+
│ ├── refactor_plans.rs # Deterministic refactor plan generation
|
|
21
|
+
│ ├── runner.rs # File/dir/URL processing, git clone
|
|
22
|
+
│ ├── lib.rs # PyO3 module entry
|
|
23
|
+
│ └── helpers/exclude.rs # Glob-based file exclusion
|
|
24
|
+
│
|
|
25
|
+
├── complexipy/ # Python CLI + API wrapper
|
|
26
|
+
│ ├── main.py # Typer CLI app (entrypoint, pure orchestrator)
|
|
27
|
+
│ ├── api.py # Python API (code_complexity, file_complexity)
|
|
28
|
+
│ ├── types.py # Enums + dataclasses (RunConfig, ExitReport)
|
|
29
|
+
│ ├── utils/ # Utilities organized by domain
|
|
30
|
+
│ │ ├── config.py # CLI + TOML config resolution (resolve_config)
|
|
31
|
+
│ │ ├── output.py # Rich console display + formatting
|
|
32
|
+
│ │ ├── paths.py # Output path resolution for export formats
|
|
33
|
+
│ │ ├── diff.py # Git diff computation + flag resolution
|
|
34
|
+
│ │ ├── snapshot.py # Snapshot evaluation + watermark
|
|
35
|
+
│ │ ├── ignored.py # Ignored-location reporting
|
|
36
|
+
│ │ ├── toml.py # TOML loading + argument resolution
|
|
37
|
+
│ │ ├── cache.py # Previous-run caching for delta reporting
|
|
38
|
+
│ │ ├── constants.py # Output filenames, legacy flag maps
|
|
39
|
+
│ │ ├── csv.py, json.py, # Export format writers
|
|
40
|
+
│ │ │ gitlab.py, sarif.py
|
|
41
|
+
│ │ └── dataclasses.py # FunctionRow, FileEntry display types
|
|
42
|
+
│ └── _complexipy.pyi # Type stubs for Rust extension
|
|
43
|
+
│
|
|
44
|
+
├── tests/ # pytest test suite
|
|
45
|
+
│ ├── main.py # Core tests + paper conformance
|
|
46
|
+
│ ├── src/ # Test fixture .py files
|
|
47
|
+
│ └── test_*.py # Utility module tests
|
|
48
|
+
│
|
|
49
|
+
├── docs/ # MkDocs content (EN + es/)
|
|
50
|
+
├── web/ # Browser demo (WASM + CodeMirror)
|
|
51
|
+
└── .github/workflows/ # CI, PR title check, release
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Commands
|
|
55
|
+
|
|
56
|
+
### Setup
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv sync
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Build (Rust extension)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv run maturin develop
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Test
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv run pytest tests/
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Lint, Format & Type Check
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv run ruff check .
|
|
78
|
+
uv run ruff format .
|
|
79
|
+
uv run ty check .
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Run
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv run complexipy <path>
|
|
86
|
+
uv run complexipy . --diff main --max-complexity-allowed 15
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Docs
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
uv run mkdocs serve
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Code Style
|
|
96
|
+
|
|
97
|
+
- No comments in code. The code must speak for itself.
|
|
98
|
+
- Docstrings only when necessary, and only about what the function does — never changelog or history notes.
|
|
99
|
+
- Conventional Commits: `type(scope): description` (e.g., `fix(diff): resolve path for nested invocation`).
|
|
100
|
+
- Pre-commit hooks: complexipy (self-dogfooding), mdformat, yamlfix.
|
|
101
|
+
- Ruff for linting and formatting (line-length 80, indent-width 4).
|
|
102
|
+
|
|
103
|
+
## Key Files
|
|
104
|
+
|
|
105
|
+
- `src/cognitive_complexity.rs` — Core algorithm: parses Python AST via ruff, computes cognitive complexity with nesting/structural/boolean increments
|
|
106
|
+
- `complexipy/main.py` — CLI entrypoint: pure orchestrator that delegates to utils modules
|
|
107
|
+
- `complexipy/types.py` — `RunConfig`, `ExitReport` dataclasses + enums (`ColorTypes`, `Sort`, `OutputFormat`)
|
|
108
|
+
- `complexipy/utils/config.py` — `resolve_config()`: merges CLI args + TOML into `RunConfig`
|
|
109
|
+
- `complexipy/utils/output.py` — Rich console display, `handle_display`, `handle_results_storage`
|
|
110
|
+
- `complexipy/utils/paths.py` — Output path resolution for CSV/JSON/GitLab/SARIF exports
|
|
111
|
+
- `complexipy/utils/diff.py` — Git diff computation, `resolve_diff_flags`, `handle_diff_output`
|
|
112
|
+
- `complexipy/utils/snapshot.py` — `evaluate_snapshot()`, `SnapshotEvaluation`, watermark logic
|
|
113
|
+
- `complexipy/utils/toml.py` — TOML loading, data-driven `get_arguments_value`
|
|
114
|
+
- `complexipy/_complexipy.pyi` — Type stubs for the Rust extension module
|
|
115
|
+
- `tests/main.py` — Core test suite including SonarSource paper conformance tests
|
|
116
|
+
|
|
117
|
+
## Conventions
|
|
118
|
+
|
|
119
|
+
- **Package manager:** Always use `uv` — `uv run pytest`, `uv run ruff`, `uv run complexipy`
|
|
120
|
+
- **Commits:** Only commit when explicitly asked. Never auto-commit.
|
|
121
|
+
- **PR titles:** Must follow Conventional Commits (enforced by CI).
|
|
122
|
+
- **Tests:** pytest with `CliRunner` for CLI tests, `unittest.mock.patch` for git operations in diff tests.
|
|
123
|
+
- **Dual-target Rust:** `#[cfg(feature = "python")]` for PyO3, `#[cfg(feature = "wasm")]` for wasm-bindgen. Shared logic uses `#[cfg(any(feature = "python", feature = "wasm"))]`.
|
|
124
|
+
- **GitHub CLI:** When available, use `gh` to retrieve context before making changes — check linked issues for requirements (`gh issue view <number>`), review open PRs for related work (`gh pr list`, `gh pr view <number>`), inspect CI status (`gh run list`, `gh run view <id>`), and search the repo (`gh search issues`, `gh search prs`). Always check the relevant issue or PR before implementing to understand the full scope and any prior discussion. If `gh` is not installed, skip these checks and work from the code and local context only.
|
|
125
|
+
|
|
126
|
+
## Anti-Patterns
|
|
127
|
+
|
|
128
|
+
- Do not add comments to code. Use descriptive variable/function names instead.
|
|
129
|
+
- Do not add docstrings that describe changelog or history. Docstrings describe what a function does.
|
|
130
|
+
- Do not commit without explicit user instruction.
|
|
131
|
+
- Do not use `pip` or `python -m` — use `uv run` for all commands.
|
|
132
|
+
- Do not modify `src/` (Rust) without understanding the PyO3/wasm-bindgen dual-target setup.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: complexipy
|
|
3
|
-
Version: 6.0
|
|
3
|
+
Version: 6.2.0
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Environment :: Console
|
|
6
6
|
Classifier: Intended Audience :: Developers
|
|
@@ -119,7 +119,7 @@ complexipy . --output-format gitlab --output complexipy-code-quality.json
|
|
|
119
119
|
complexipy . --diff HEAD~1
|
|
120
120
|
|
|
121
121
|
# Fail only on threshold-breaking regressions in a diff
|
|
122
|
-
complexipy . --diff main
|
|
122
|
+
complexipy . --diff main
|
|
123
123
|
# Analyze current directory while excluding files or directories with glob patterns
|
|
124
124
|
complexipy . --exclude "tests/**" --exclude "path/to/exclude.py"
|
|
125
125
|
|
|
@@ -285,32 +285,33 @@ Legacy TOML keys such as `output-json = true` and CLI flags such as
|
|
|
285
285
|
|
|
286
286
|
### CLI Options
|
|
287
287
|
|
|
288
|
-
| Flag | Description
|
|
289
|
-
| ------------------------------- |
|
|
290
|
-
| `--exclude` | Exclude glob patterns relative to each provided path. Use patterns like `tests/**` for directories or `src/legacy/file.py` for specific files.
|
|
291
|
-
| `--max-complexity-allowed` | Complexity threshold
|
|
292
|
-
| `--snapshot-create` | Save the current violations above the threshold into `complexipy-snapshot.json`
|
|
293
|
-
| `--snapshot-ignore` | Skip comparing against the snapshot even if it exists
|
|
294
|
-
| `--failed` | Show only functions above the complexity threshold
|
|
295
|
-
| `--suggest-refactors` | Show deterministic Rust AST-based refactor plans in rich CLI output. Ignored by `--plain`
|
|
296
|
-
| `--color <auto\|yes\|no>` | Use color
|
|
297
|
-
| `--sort <asc\|desc\|file_name>` | Sort results
|
|
298
|
-
| `--quiet` | Suppress output
|
|
299
|
-
| `--ignore-complexity` | Don't exit with error on threshold breach
|
|
300
|
-
| `--version` | Show installed complexipy version and exit
|
|
301
|
-
| `--top <n>` | Show only the `n` most complex functions, globally sorted by complexity descending
|
|
302
|
-
| `--plain` | Emit plain text lines as `<path> <function> <complexity>`. Cannot be combined with `--quiet`
|
|
303
|
-
| `--output-format <format>` | Select a machine-readable output format. Repeat the flag to request multiple formats (`json`, `csv`, `gitlab`, `sarif`)
|
|
304
|
-
| `--output <path>` | Write machine-readable output to a file or directory. Use a directory when emitting multiple formats
|
|
305
|
-
| `--diff <ref>` | Show a complexity diff against a git reference
|
|
306
|
-
| `--
|
|
307
|
-
| `--
|
|
308
|
-
| `--
|
|
309
|
-
| `--
|
|
310
|
-
| `--
|
|
311
|
-
| `--output-
|
|
312
|
-
| `--output-
|
|
313
|
-
| `--output-
|
|
288
|
+
| Flag | Description | Default |
|
|
289
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
290
|
+
| `--exclude` | Exclude glob patterns relative to each provided path. Use patterns like `tests/**` for directories or `src/legacy/file.py` for specific files. | |
|
|
291
|
+
| `--max-complexity-allowed` | Complexity threshold | `15` |
|
|
292
|
+
| `--snapshot-create` | Save the current violations above the threshold into `complexipy-snapshot.json` | `false` |
|
|
293
|
+
| `--snapshot-ignore` | Skip comparing against the snapshot even if it exists | `false` |
|
|
294
|
+
| `--failed` | Show only functions above the complexity threshold | `false` |
|
|
295
|
+
| `--suggest-refactors` | Show deterministic Rust AST-based refactor plans in rich CLI output. Ignored by `--plain` | `false` |
|
|
296
|
+
| `--color <auto\|yes\|no>` | Use color | `auto` |
|
|
297
|
+
| `--sort <asc\|desc\|file_name>` | Sort results | `asc` |
|
|
298
|
+
| `--quiet` | Suppress output | `false` |
|
|
299
|
+
| `--ignore-complexity` | Don't exit with error on threshold breach | `false` |
|
|
300
|
+
| `--version` | Show installed complexipy version and exit | - |
|
|
301
|
+
| `--top <n>` | Show only the `n` most complex functions, globally sorted by complexity descending | — |
|
|
302
|
+
| `--plain` | Emit plain text lines as `<path> <function> <complexity>`. Cannot be combined with `--quiet` | `false` |
|
|
303
|
+
| `--output-format <format>` | Select a machine-readable output format. Repeat the flag to request multiple formats (`json`, `csv`, `gitlab`, `sarif`) | — |
|
|
304
|
+
| `--output <path>` | Write machine-readable output to a file or directory. Use a directory when emitting multiple formats | — |
|
|
305
|
+
| `--diff <ref>` | Show a complexity diff against a git reference and enforce the threshold. Fails on regressions above `--max-complexity-allowed` (see [Complexity Diff](#complexity-diff)) | — |
|
|
306
|
+
| `--diff-only <ref>` | Show a complexity diff visually without affecting the exit code (see [Complexity Diff](#complexity-diff)) | — |
|
|
307
|
+
| `--ratchet`, `-R` | **Deprecated.** Use `--diff` instead, which now enforces by default | `false` |
|
|
308
|
+
| `--check-script` | Report module-level (script) complexity as a synthetic `<module>` entry | `false` |
|
|
309
|
+
| `--no-ignore` | Analyze every function, disregarding inline ignore comments (`# complexipy: ignore`, `# noqa: complexipy`) | `false` |
|
|
310
|
+
| `--report-ignored` | List every file:line where an ignore comment suppresses a function. Prints even under `--quiet` | `false` |
|
|
311
|
+
| `--output-json` | Deprecated alias for `--output-format json` | `false` |
|
|
312
|
+
| `--output-csv` | Deprecated alias for `--output-format csv` | `false` |
|
|
313
|
+
| `--output-gitlab` | Deprecated alias for `--output-format gitlab` | `false` |
|
|
314
|
+
| `--output-sarif` | Deprecated alias for `--output-format sarif` | `false` |
|
|
314
315
|
|
|
315
316
|
Example:
|
|
316
317
|
|
|
@@ -364,7 +365,7 @@ Use `--snapshot-ignore` if you need to temporarily bypass the snapshot gate (for
|
|
|
364
365
|
|
|
365
366
|
### Complexity Diff
|
|
366
367
|
|
|
367
|
-
Compare complexity against any git reference to see
|
|
368
|
+
Compare complexity against any git reference to see whether a branch or commit made things better or worse:
|
|
368
369
|
|
|
369
370
|
```bash
|
|
370
371
|
# Compare the working tree against the previous commit
|
|
@@ -372,29 +373,22 @@ complexipy . --diff HEAD~1
|
|
|
372
373
|
|
|
373
374
|
# Compare against a named branch
|
|
374
375
|
complexipy . --diff main
|
|
376
|
+
```
|
|
375
377
|
|
|
376
|
-
|
|
377
|
-
complexipy . --diff main --ratchet
|
|
378
|
+
By default `--diff` **enforces** the complexity threshold: the run exits with code `1` only when a change breaches the contract relative to `--max-complexity-allowed`:
|
|
378
379
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
```
|
|
380
|
+
- A new function is introduced above the threshold, or
|
|
381
|
+
- an existing function's complexity increases **and** ends above the threshold (already-over functions getting worse also fail).
|
|
382
382
|
|
|
383
|
-
|
|
383
|
+
Functions that regress but stay at or below the threshold (e.g. `3 → 4` with `-mx 15`) are **not** flagged — the threshold is still the main contract, and `--diff` only catches regressions that actually break it.
|
|
384
384
|
|
|
385
|
-
|
|
385
|
+
To see the diff visually without affecting the exit code, use `--diff-only` instead:
|
|
386
386
|
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
────────────────────────────────────────────────────────────────────────
|
|
390
|
-
REGRESSED src/api.py::handle_request 12 → 19 (+7)
|
|
391
|
-
IMPROVED src/utils.py::flatten_tree 22 → 14 (-8)
|
|
392
|
-
NEW src/auth.py::validate_token 17 (new)
|
|
393
|
-
────────────────────────────────────────────────────────────────────────
|
|
394
|
-
Net: 1 regressed, 1 improved, 1 new
|
|
387
|
+
```bash
|
|
388
|
+
complexipy . --diff-only HEAD~1
|
|
395
389
|
```
|
|
396
390
|
|
|
397
|
-
|
|
391
|
+
Requires `git` to be available and the analysed paths to be inside a git repository.
|
|
398
392
|
|
|
399
393
|
### Script Complexity
|
|
400
394
|
|
|
@@ -87,7 +87,7 @@ complexipy . --output-format gitlab --output complexipy-code-quality.json
|
|
|
87
87
|
complexipy . --diff HEAD~1
|
|
88
88
|
|
|
89
89
|
# Fail only on threshold-breaking regressions in a diff
|
|
90
|
-
complexipy . --diff main
|
|
90
|
+
complexipy . --diff main
|
|
91
91
|
# Analyze current directory while excluding files or directories with glob patterns
|
|
92
92
|
complexipy . --exclude "tests/**" --exclude "path/to/exclude.py"
|
|
93
93
|
|
|
@@ -253,32 +253,33 @@ Legacy TOML keys such as `output-json = true` and CLI flags such as
|
|
|
253
253
|
|
|
254
254
|
### CLI Options
|
|
255
255
|
|
|
256
|
-
| Flag | Description
|
|
257
|
-
| ------------------------------- |
|
|
258
|
-
| `--exclude` | Exclude glob patterns relative to each provided path. Use patterns like `tests/**` for directories or `src/legacy/file.py` for specific files.
|
|
259
|
-
| `--max-complexity-allowed` | Complexity threshold
|
|
260
|
-
| `--snapshot-create` | Save the current violations above the threshold into `complexipy-snapshot.json`
|
|
261
|
-
| `--snapshot-ignore` | Skip comparing against the snapshot even if it exists
|
|
262
|
-
| `--failed` | Show only functions above the complexity threshold
|
|
263
|
-
| `--suggest-refactors` | Show deterministic Rust AST-based refactor plans in rich CLI output. Ignored by `--plain`
|
|
264
|
-
| `--color <auto\|yes\|no>` | Use color
|
|
265
|
-
| `--sort <asc\|desc\|file_name>` | Sort results
|
|
266
|
-
| `--quiet` | Suppress output
|
|
267
|
-
| `--ignore-complexity` | Don't exit with error on threshold breach
|
|
268
|
-
| `--version` | Show installed complexipy version and exit
|
|
269
|
-
| `--top <n>` | Show only the `n` most complex functions, globally sorted by complexity descending
|
|
270
|
-
| `--plain` | Emit plain text lines as `<path> <function> <complexity>`. Cannot be combined with `--quiet`
|
|
271
|
-
| `--output-format <format>` | Select a machine-readable output format. Repeat the flag to request multiple formats (`json`, `csv`, `gitlab`, `sarif`)
|
|
272
|
-
| `--output <path>` | Write machine-readable output to a file or directory. Use a directory when emitting multiple formats
|
|
273
|
-
| `--diff <ref>` | Show a complexity diff against a git reference
|
|
274
|
-
| `--
|
|
275
|
-
| `--
|
|
276
|
-
| `--
|
|
277
|
-
| `--
|
|
278
|
-
| `--
|
|
279
|
-
| `--output-
|
|
280
|
-
| `--output-
|
|
281
|
-
| `--output-
|
|
256
|
+
| Flag | Description | Default |
|
|
257
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
258
|
+
| `--exclude` | Exclude glob patterns relative to each provided path. Use patterns like `tests/**` for directories or `src/legacy/file.py` for specific files. | |
|
|
259
|
+
| `--max-complexity-allowed` | Complexity threshold | `15` |
|
|
260
|
+
| `--snapshot-create` | Save the current violations above the threshold into `complexipy-snapshot.json` | `false` |
|
|
261
|
+
| `--snapshot-ignore` | Skip comparing against the snapshot even if it exists | `false` |
|
|
262
|
+
| `--failed` | Show only functions above the complexity threshold | `false` |
|
|
263
|
+
| `--suggest-refactors` | Show deterministic Rust AST-based refactor plans in rich CLI output. Ignored by `--plain` | `false` |
|
|
264
|
+
| `--color <auto\|yes\|no>` | Use color | `auto` |
|
|
265
|
+
| `--sort <asc\|desc\|file_name>` | Sort results | `asc` |
|
|
266
|
+
| `--quiet` | Suppress output | `false` |
|
|
267
|
+
| `--ignore-complexity` | Don't exit with error on threshold breach | `false` |
|
|
268
|
+
| `--version` | Show installed complexipy version and exit | - |
|
|
269
|
+
| `--top <n>` | Show only the `n` most complex functions, globally sorted by complexity descending | — |
|
|
270
|
+
| `--plain` | Emit plain text lines as `<path> <function> <complexity>`. Cannot be combined with `--quiet` | `false` |
|
|
271
|
+
| `--output-format <format>` | Select a machine-readable output format. Repeat the flag to request multiple formats (`json`, `csv`, `gitlab`, `sarif`) | — |
|
|
272
|
+
| `--output <path>` | Write machine-readable output to a file or directory. Use a directory when emitting multiple formats | — |
|
|
273
|
+
| `--diff <ref>` | Show a complexity diff against a git reference and enforce the threshold. Fails on regressions above `--max-complexity-allowed` (see [Complexity Diff](#complexity-diff)) | — |
|
|
274
|
+
| `--diff-only <ref>` | Show a complexity diff visually without affecting the exit code (see [Complexity Diff](#complexity-diff)) | — |
|
|
275
|
+
| `--ratchet`, `-R` | **Deprecated.** Use `--diff` instead, which now enforces by default | `false` |
|
|
276
|
+
| `--check-script` | Report module-level (script) complexity as a synthetic `<module>` entry | `false` |
|
|
277
|
+
| `--no-ignore` | Analyze every function, disregarding inline ignore comments (`# complexipy: ignore`, `# noqa: complexipy`) | `false` |
|
|
278
|
+
| `--report-ignored` | List every file:line where an ignore comment suppresses a function. Prints even under `--quiet` | `false` |
|
|
279
|
+
| `--output-json` | Deprecated alias for `--output-format json` | `false` |
|
|
280
|
+
| `--output-csv` | Deprecated alias for `--output-format csv` | `false` |
|
|
281
|
+
| `--output-gitlab` | Deprecated alias for `--output-format gitlab` | `false` |
|
|
282
|
+
| `--output-sarif` | Deprecated alias for `--output-format sarif` | `false` |
|
|
282
283
|
|
|
283
284
|
Example:
|
|
284
285
|
|
|
@@ -332,7 +333,7 @@ Use `--snapshot-ignore` if you need to temporarily bypass the snapshot gate (for
|
|
|
332
333
|
|
|
333
334
|
### Complexity Diff
|
|
334
335
|
|
|
335
|
-
Compare complexity against any git reference to see
|
|
336
|
+
Compare complexity against any git reference to see whether a branch or commit made things better or worse:
|
|
336
337
|
|
|
337
338
|
```bash
|
|
338
339
|
# Compare the working tree against the previous commit
|
|
@@ -340,29 +341,22 @@ complexipy . --diff HEAD~1
|
|
|
340
341
|
|
|
341
342
|
# Compare against a named branch
|
|
342
343
|
complexipy . --diff main
|
|
344
|
+
```
|
|
343
345
|
|
|
344
|
-
|
|
345
|
-
complexipy . --diff main --ratchet
|
|
346
|
+
By default `--diff` **enforces** the complexity threshold: the run exits with code `1` only when a change breaches the contract relative to `--max-complexity-allowed`:
|
|
346
347
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
```
|
|
348
|
+
- A new function is introduced above the threshold, or
|
|
349
|
+
- an existing function's complexity increases **and** ends above the threshold (already-over functions getting worse also fail).
|
|
350
350
|
|
|
351
|
-
|
|
351
|
+
Functions that regress but stay at or below the threshold (e.g. `3 → 4` with `-mx 15`) are **not** flagged — the threshold is still the main contract, and `--diff` only catches regressions that actually break it.
|
|
352
352
|
|
|
353
|
-
|
|
353
|
+
To see the diff visually without affecting the exit code, use `--diff-only` instead:
|
|
354
354
|
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
────────────────────────────────────────────────────────────────────────
|
|
358
|
-
REGRESSED src/api.py::handle_request 12 → 19 (+7)
|
|
359
|
-
IMPROVED src/utils.py::flatten_tree 22 → 14 (-8)
|
|
360
|
-
NEW src/auth.py::validate_token 17 (new)
|
|
361
|
-
────────────────────────────────────────────────────────────────────────
|
|
362
|
-
Net: 1 regressed, 1 improved, 1 new
|
|
355
|
+
```bash
|
|
356
|
+
complexipy . --diff-only HEAD~1
|
|
363
357
|
```
|
|
364
358
|
|
|
365
|
-
|
|
359
|
+
Requires `git` to be available and the analysed paths to be inside a git repository.
|
|
366
360
|
|
|
367
361
|
### Script Complexity
|
|
368
362
|
|