complexity-accounting 1.6.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.
- complexity_accounting-1.6.0/PKG-INFO +441 -0
- complexity_accounting-1.6.0/README.md +368 -0
- complexity_accounting-1.6.0/complexity_accounting/__init__.py +3 -0
- complexity_accounting-1.6.0/complexity_accounting/__main__.py +488 -0
- complexity_accounting-1.6.0/complexity_accounting/base_parser.py +396 -0
- complexity_accounting-1.6.0/complexity_accounting/cache.py +156 -0
- complexity_accounting-1.6.0/complexity_accounting/churn.py +70 -0
- complexity_accounting-1.6.0/complexity_accounting/config.py +171 -0
- complexity_accounting-1.6.0/complexity_accounting/coupling.py +356 -0
- complexity_accounting-1.6.0/complexity_accounting/cpp_parser.py +193 -0
- complexity_accounting-1.6.0/complexity_accounting/git_tracker.py +327 -0
- complexity_accounting-1.6.0/complexity_accounting/go_parser.py +173 -0
- complexity_accounting-1.6.0/complexity_accounting/halstead.py +258 -0
- complexity_accounting-1.6.0/complexity_accounting/html_report.py +346 -0
- complexity_accounting-1.6.0/complexity_accounting/java_parser.py +131 -0
- complexity_accounting-1.6.0/complexity_accounting/js_parser.py +160 -0
- complexity_accounting-1.6.0/complexity_accounting/models.py +434 -0
- complexity_accounting-1.6.0/complexity_accounting/plugin.py +116 -0
- complexity_accounting-1.6.0/complexity_accounting/rust_parser.py +144 -0
- complexity_accounting-1.6.0/complexity_accounting/sarif.py +171 -0
- complexity_accounting-1.6.0/complexity_accounting/scanner.py +552 -0
- complexity_accounting-1.6.0/complexity_accounting/ts_parser.py +176 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/PKG-INFO +441 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/SOURCES.txt +48 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/dependency_links.txt +1 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/entry_points.txt +3 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/requires.txt +70 -0
- complexity_accounting-1.6.0/complexity_accounting.egg-info/top_level.txt +1 -0
- complexity_accounting-1.6.0/pyproject.toml +110 -0
- complexity_accounting-1.6.0/setup.cfg +4 -0
- complexity_accounting-1.6.0/tests/test_cache.py +198 -0
- complexity_accounting-1.6.0/tests/test_churn.py +103 -0
- complexity_accounting-1.6.0/tests/test_class_metrics.py +307 -0
- complexity_accounting-1.6.0/tests/test_config.py +292 -0
- complexity_accounting-1.6.0/tests/test_coupling.py +250 -0
- complexity_accounting-1.6.0/tests/test_cpp_parser.py +832 -0
- complexity_accounting-1.6.0/tests/test_e2e.py +649 -0
- complexity_accounting-1.6.0/tests/test_git_tracker.py +417 -0
- complexity_accounting-1.6.0/tests/test_go_parser.py +666 -0
- complexity_accounting-1.6.0/tests/test_halstead.py +164 -0
- complexity_accounting-1.6.0/tests/test_html_report.py +169 -0
- complexity_accounting-1.6.0/tests/test_java_parser.py +575 -0
- complexity_accounting-1.6.0/tests/test_js_parser.py +643 -0
- complexity_accounting-1.6.0/tests/test_main.py +830 -0
- complexity_accounting-1.6.0/tests/test_opensandbox.py +127 -0
- complexity_accounting-1.6.0/tests/test_plugin.py +87 -0
- complexity_accounting-1.6.0/tests/test_rust_parser.py +659 -0
- complexity_accounting-1.6.0/tests/test_sarif.py +194 -0
- complexity_accounting-1.6.0/tests/test_scanner.py +1453 -0
- complexity_accounting-1.6.0/tests/test_ts_parser.py +760 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: complexity-accounting
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: Measure Net Complexity Score for codebases — cognitive complexity, trend tracking, CI integration
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/zhanglpg/code-complexity-measure
|
|
7
|
+
Project-URL: Repository, https://github.com/zhanglpg/code-complexity-measure
|
|
8
|
+
Project-URL: Issues, https://github.com/zhanglpg/code-complexity-measure/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/zhanglpg/code-complexity-measure/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: complexity,cognitive-complexity,cyclomatic-complexity,code-quality,static-analysis,maintainability,ncs
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Classifier: Topic :: Software Development :: Testing
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: libcst>=1.0.0
|
|
27
|
+
Requires-Dist: tomli>=1.0.0; python_version < "3.11"
|
|
28
|
+
Provides-Extra: go
|
|
29
|
+
Requires-Dist: tree-sitter>=0.21.0; extra == "go"
|
|
30
|
+
Requires-Dist: tree-sitter-go>=0.21.0; extra == "go"
|
|
31
|
+
Provides-Extra: java
|
|
32
|
+
Requires-Dist: tree-sitter>=0.21.0; extra == "java"
|
|
33
|
+
Requires-Dist: tree-sitter-java>=0.21.0; extra == "java"
|
|
34
|
+
Provides-Extra: cpp
|
|
35
|
+
Requires-Dist: tree-sitter>=0.21.0; extra == "cpp"
|
|
36
|
+
Requires-Dist: tree-sitter-cpp>=0.21.0; extra == "cpp"
|
|
37
|
+
Provides-Extra: js
|
|
38
|
+
Requires-Dist: tree-sitter>=0.21.0; extra == "js"
|
|
39
|
+
Requires-Dist: tree-sitter-javascript>=0.21.0; extra == "js"
|
|
40
|
+
Provides-Extra: ts
|
|
41
|
+
Requires-Dist: tree-sitter>=0.21.0; extra == "ts"
|
|
42
|
+
Requires-Dist: tree-sitter-typescript>=0.21.0; extra == "ts"
|
|
43
|
+
Provides-Extra: rust
|
|
44
|
+
Requires-Dist: tree-sitter>=0.24.0; python_version >= "3.10" and extra == "rust"
|
|
45
|
+
Requires-Dist: tree-sitter>=0.23.0; python_version < "3.10" and extra == "rust"
|
|
46
|
+
Requires-Dist: tree-sitter-rust>=0.23.0; python_version >= "3.10" and extra == "rust"
|
|
47
|
+
Requires-Dist: tree-sitter-rust<0.23.3,>=0.23.0; python_version < "3.10" and extra == "rust"
|
|
48
|
+
Provides-Extra: test
|
|
49
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
50
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: tree-sitter>=0.24.0; python_version >= "3.10" and extra == "all"
|
|
53
|
+
Requires-Dist: tree-sitter>=0.23.0; python_version < "3.10" and extra == "all"
|
|
54
|
+
Requires-Dist: tree-sitter-go>=0.21.0; extra == "all"
|
|
55
|
+
Requires-Dist: tree-sitter-java>=0.21.0; extra == "all"
|
|
56
|
+
Requires-Dist: tree-sitter-cpp>=0.21.0; extra == "all"
|
|
57
|
+
Requires-Dist: tree-sitter-javascript>=0.21.0; extra == "all"
|
|
58
|
+
Requires-Dist: tree-sitter-typescript>=0.21.0; extra == "all"
|
|
59
|
+
Requires-Dist: tree-sitter-rust>=0.23.0; python_version >= "3.10" and extra == "all"
|
|
60
|
+
Requires-Dist: tree-sitter-rust<0.23.3,>=0.23.0; python_version < "3.10" and extra == "all"
|
|
61
|
+
Provides-Extra: dev
|
|
62
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
63
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
64
|
+
Requires-Dist: tree-sitter>=0.24.0; python_version >= "3.10" and extra == "dev"
|
|
65
|
+
Requires-Dist: tree-sitter>=0.23.0; python_version < "3.10" and extra == "dev"
|
|
66
|
+
Requires-Dist: tree-sitter-go>=0.21.0; extra == "dev"
|
|
67
|
+
Requires-Dist: tree-sitter-java>=0.21.0; extra == "dev"
|
|
68
|
+
Requires-Dist: tree-sitter-cpp>=0.21.0; extra == "dev"
|
|
69
|
+
Requires-Dist: tree-sitter-javascript>=0.21.0; extra == "dev"
|
|
70
|
+
Requires-Dist: tree-sitter-typescript>=0.21.0; extra == "dev"
|
|
71
|
+
Requires-Dist: tree-sitter-rust>=0.23.0; python_version >= "3.10" and extra == "dev"
|
|
72
|
+
Requires-Dist: tree-sitter-rust<0.23.3,>=0.23.0; python_version < "3.10" and extra == "dev"
|
|
73
|
+
|
|
74
|
+
# Complexity Accounting Tool
|
|
75
|
+
|
|
76
|
+
> "Complexity is the core problem of software." — Liping
|
|
77
|
+
|
|
78
|
+
Measures **Net Complexity Score (NCS)** — whether your codebase is an asset or liability to future development. CI-ready, git-aware, multi-language, built for real engineering teams.
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install complexity-accounting
|
|
84
|
+
|
|
85
|
+
# Scan a directory
|
|
86
|
+
python -m complexity_accounting scan /path/to/code
|
|
87
|
+
|
|
88
|
+
# JSON output (for CI)
|
|
89
|
+
python -m complexity_accounting scan /path/to/code --json
|
|
90
|
+
|
|
91
|
+
# Compare branches
|
|
92
|
+
python -m complexity_accounting compare --base main --head HEAD --repo .
|
|
93
|
+
|
|
94
|
+
# Trend over commits
|
|
95
|
+
python -m complexity_accounting trend --repo . --commits 20
|
|
96
|
+
|
|
97
|
+
# CI gate: fail if NCS > 8
|
|
98
|
+
python -m complexity_accounting scan . --fail-above 8
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## What It Measures
|
|
102
|
+
|
|
103
|
+
| Metric | What | Why |
|
|
104
|
+
|--------|------|-----|
|
|
105
|
+
| **Cognitive Complexity** | How hard is the code to understand | Primary signal — measures human burden |
|
|
106
|
+
| **Cyclomatic Complexity** | Number of decision paths | Classic metric, good for test coverage estimation |
|
|
107
|
+
| **Net Complexity Score** | Weighted aggregate with hotspot, churn, and coupling penalties | Single number for CI gates |
|
|
108
|
+
| **Hotspots** | Functions above threshold (default 10) | Identifies refactoring targets |
|
|
109
|
+
| **Churn Factor** | How frequently files change | Penalizes volatile, complex code |
|
|
110
|
+
| **Coupling Factor** | Import fan-out (efferent coupling) | Penalizes tightly coupled modules |
|
|
111
|
+
|
|
112
|
+
### Net Complexity Score (NCS)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
NCS = (w_cog * avg_cognitive + w_cyc * avg_cyclomatic) * (1 + hotspot_ratio) * churn_factor * coupling_factor
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
- **Weights** — cognitive: 0.7, cyclomatic: 0.3 (configurable)
|
|
119
|
+
- **hotspot_ratio** = functions above threshold / total functions
|
|
120
|
+
- **churn_factor** = 1.0 + log(avg_file_churn) / 10
|
|
121
|
+
- **coupling_factor** = 1.0 + avg_efferent_coupling / max_efferent_coupling
|
|
122
|
+
- Rating: low <=3 | moderate <=6 | concerning <=10 | critical >10
|
|
123
|
+
|
|
124
|
+
## Supported Languages
|
|
125
|
+
|
|
126
|
+
| Language | Backend | Install |
|
|
127
|
+
|----------|---------|---------|
|
|
128
|
+
| Python | libcst | included |
|
|
129
|
+
| Go | tree-sitter-go | `pip install complexity-accounting[go]` |
|
|
130
|
+
| Java | tree-sitter-java | `pip install complexity-accounting[java]` |
|
|
131
|
+
| TypeScript | tree-sitter-typescript | `pip install complexity-accounting[ts]` |
|
|
132
|
+
| JavaScript | tree-sitter-javascript | `pip install complexity-accounting[js]` |
|
|
133
|
+
| Rust | tree-sitter-rust | `pip install complexity-accounting[rust]` |
|
|
134
|
+
| C/C++ | tree-sitter-cpp | `pip install complexity-accounting[cpp]` |
|
|
135
|
+
|
|
136
|
+
## CLI Reference
|
|
137
|
+
|
|
138
|
+
### `scan` — Analyze files and directories
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
python -m complexity_accounting scan <path> [options]
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
| Option | Description | Default |
|
|
145
|
+
|--------|-------------|---------|
|
|
146
|
+
| `--json` | JSON output | off |
|
|
147
|
+
| `--threshold N` | Hotspot cognitive complexity threshold | 10 |
|
|
148
|
+
| `--top N` | Show top N complex functions | 20 |
|
|
149
|
+
| `--fail-above FLOAT` | Exit 1 if NCS exceeds value | none |
|
|
150
|
+
| `--config PATH` | Path to .complexity.toml | auto-detect |
|
|
151
|
+
| `--weights KEY=VAL` | Override NCS weights (e.g. `cognitive=0.7,cyclomatic=0.3`) | config |
|
|
152
|
+
| `--churn-days N` | Days of git history for churn analysis | 90 |
|
|
153
|
+
| `--churn-commits N` | Max commits for churn analysis | 100 |
|
|
154
|
+
| `--no-churn` | Skip churn factor calculation | off |
|
|
155
|
+
| `--no-coupling` | Skip coupling factor calculation | off |
|
|
156
|
+
| `--output FILE` / `-o` | Write output to file instead of stdout | stdout |
|
|
157
|
+
|
|
158
|
+
### `compare` — Diff complexity between git refs
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
python -m complexity_accounting compare --base REF --head REF [options]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| Option | Description | Default |
|
|
165
|
+
|--------|-------------|---------|
|
|
166
|
+
| `--base REF` | Base reference (branch, tag, SHA) | required |
|
|
167
|
+
| `--head REF` | Head reference | HEAD |
|
|
168
|
+
| `--repo PATH` | Git repository path | . |
|
|
169
|
+
| `--json` | JSON output | off |
|
|
170
|
+
| `--markdown` | Markdown output (for PR comments) | off |
|
|
171
|
+
| `--full` | Scan all files, not just changed ones | off |
|
|
172
|
+
|
|
173
|
+
### `trend` — Complexity over recent commits
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
python -m complexity_accounting trend --repo . [options]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Option | Description | Default |
|
|
180
|
+
|--------|-------------|---------|
|
|
181
|
+
| `--repo PATH` | Git repository path | . |
|
|
182
|
+
| `--commits N` | Number of commits to analyze | 10 |
|
|
183
|
+
| `--ref REF` | Starting reference | HEAD |
|
|
184
|
+
| `--json` | JSON output | off |
|
|
185
|
+
|
|
186
|
+
## Configuration
|
|
187
|
+
|
|
188
|
+
Configuration precedence: **CLI args > .complexity.toml > pyproject.toml `[tool.complexity-accounting]` > defaults**
|
|
189
|
+
|
|
190
|
+
### `.complexity.toml`
|
|
191
|
+
|
|
192
|
+
```toml
|
|
193
|
+
hotspot-threshold = 8
|
|
194
|
+
weight-cognitive = 0.8
|
|
195
|
+
weight-cyclomatic = 0.2
|
|
196
|
+
risk-low = 5
|
|
197
|
+
risk-moderate = 10
|
|
198
|
+
risk-high = 20
|
|
199
|
+
churn-days = 90
|
|
200
|
+
churn-commits = 100
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Or in `pyproject.toml`:
|
|
204
|
+
|
|
205
|
+
```toml
|
|
206
|
+
[tool.complexity-accounting]
|
|
207
|
+
hotspot-threshold = 8
|
|
208
|
+
weight-cognitive = 0.8
|
|
209
|
+
weight-cyclomatic = 0.2
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## GitHub Action
|
|
213
|
+
|
|
214
|
+
Use this action in any repository to automatically report complexity scores on pushes and pull requests.
|
|
215
|
+
|
|
216
|
+
### Quick Start
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
# .github/workflows/complexity.yml
|
|
220
|
+
name: Complexity Check
|
|
221
|
+
on: [push, pull_request]
|
|
222
|
+
permissions:
|
|
223
|
+
contents: read
|
|
224
|
+
pull-requests: write
|
|
225
|
+
|
|
226
|
+
jobs:
|
|
227
|
+
complexity:
|
|
228
|
+
runs-on: ubuntu-latest
|
|
229
|
+
steps:
|
|
230
|
+
- uses: actions/checkout@v4
|
|
231
|
+
with:
|
|
232
|
+
fetch-depth: 0
|
|
233
|
+
- uses: zhanglpg/code-complexity-measure@main
|
|
234
|
+
with:
|
|
235
|
+
path: '.'
|
|
236
|
+
fail-above: '8'
|
|
237
|
+
post-comment: 'true'
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Inputs
|
|
241
|
+
|
|
242
|
+
| Input | Description | Default |
|
|
243
|
+
|-------|-------------|---------|
|
|
244
|
+
| `path` | Path to scan | `.` |
|
|
245
|
+
| `threshold` | Cognitive complexity hotspot threshold | `10` |
|
|
246
|
+
| `fail-above` | Fail the check if NCS exceeds this value | _(none)_ |
|
|
247
|
+
| `output-format` | Output format: `json` or `markdown` | `markdown` |
|
|
248
|
+
| `python-version` | Python version to use | `3.11` |
|
|
249
|
+
| `post-comment` | Post results as a PR comment (`true`/`false`) | `false` |
|
|
250
|
+
| `update-comment` | Update existing PR comment instead of creating duplicates | `true` |
|
|
251
|
+
| `extras` | Comma-separated language extras to install (e.g. `go,java,cpp`) | _(none)_ |
|
|
252
|
+
|
|
253
|
+
### Outputs
|
|
254
|
+
|
|
255
|
+
| Output | Description |
|
|
256
|
+
|--------|-------------|
|
|
257
|
+
| `ncs` | Net Complexity Score (float) |
|
|
258
|
+
| `hotspot-count` | Number of hotspot functions (int) |
|
|
259
|
+
| `pass` | Whether the scan passed the threshold (`true`/`false`) |
|
|
260
|
+
| `delta` | NCS delta from comparison, if available (float) |
|
|
261
|
+
|
|
262
|
+
### Features
|
|
263
|
+
|
|
264
|
+
- **Job Summary** — Every run writes a complexity report to the GitHub Actions Job Summary, visible on the workflow run page.
|
|
265
|
+
- **PR Comments** — When `post-comment: 'true'`, posts a detailed comparison report as a PR comment. Subsequent pushes update the same comment instead of creating duplicates.
|
|
266
|
+
- **Push & PR Support** — On `pull_request` events, compares the PR base vs head. On `push` events, compares `HEAD~1` vs `HEAD`.
|
|
267
|
+
- **Threshold Gating** — Set `fail-above` to fail the check if NCS exceeds the value. The Job Summary and PR comment are always posted, even when the check fails.
|
|
268
|
+
- **Multi-Language** — Set `extras: 'go,java'` to install Go and Java support via tree-sitter.
|
|
269
|
+
- **Pip Caching** — Dependencies are cached across runs for faster execution.
|
|
270
|
+
|
|
271
|
+
### Full Example
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
name: Complexity Check
|
|
275
|
+
on:
|
|
276
|
+
push:
|
|
277
|
+
branches: [main]
|
|
278
|
+
pull_request:
|
|
279
|
+
|
|
280
|
+
permissions:
|
|
281
|
+
contents: read
|
|
282
|
+
pull-requests: write # Required for PR comments
|
|
283
|
+
|
|
284
|
+
jobs:
|
|
285
|
+
complexity:
|
|
286
|
+
runs-on: ubuntu-latest
|
|
287
|
+
steps:
|
|
288
|
+
- uses: actions/checkout@v4
|
|
289
|
+
with:
|
|
290
|
+
fetch-depth: 0 # Full history needed for comparison
|
|
291
|
+
|
|
292
|
+
- name: Complexity Check
|
|
293
|
+
id: complexity
|
|
294
|
+
uses: zhanglpg/code-complexity-measure@main
|
|
295
|
+
with:
|
|
296
|
+
path: 'src'
|
|
297
|
+
threshold: '10'
|
|
298
|
+
fail-above: '8'
|
|
299
|
+
post-comment: 'true'
|
|
300
|
+
extras: 'go'
|
|
301
|
+
|
|
302
|
+
- name: Use outputs
|
|
303
|
+
if: always()
|
|
304
|
+
run: |
|
|
305
|
+
echo "NCS: ${{ steps.complexity.outputs.ncs }}"
|
|
306
|
+
echo "Hotspots: ${{ steps.complexity.outputs.hotspot-count }}"
|
|
307
|
+
echo "Passed: ${{ steps.complexity.outputs.pass }}"
|
|
308
|
+
echo "Delta: ${{ steps.complexity.outputs.delta }}"
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
> **Note:** `fetch-depth: 0` is required for comparison reports. `permissions: pull-requests: write` is required for PR comments.
|
|
312
|
+
|
|
313
|
+
See [`examples/complexity-check.yml`](examples/complexity-check.yml) for a copy-pasteable workflow.
|
|
314
|
+
|
|
315
|
+
### Manual Workflow Step
|
|
316
|
+
|
|
317
|
+
You can also use the CLI directly without the composite action:
|
|
318
|
+
|
|
319
|
+
```yaml
|
|
320
|
+
- name: Complexity Gate
|
|
321
|
+
run: |
|
|
322
|
+
pip install complexity-accounting
|
|
323
|
+
python -m complexity_accounting scan . --fail-above 8
|
|
324
|
+
|
|
325
|
+
- name: PR Complexity Delta
|
|
326
|
+
run: |
|
|
327
|
+
python -m complexity_accounting compare \
|
|
328
|
+
--base origin/main --head HEAD --repo . --markdown \
|
|
329
|
+
> complexity-report.md
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Pre-commit Hook
|
|
333
|
+
|
|
334
|
+
Add complexity checking to your [pre-commit](https://pre-commit.com/) config:
|
|
335
|
+
|
|
336
|
+
```yaml
|
|
337
|
+
# .pre-commit-config.yaml
|
|
338
|
+
repos:
|
|
339
|
+
- repo: https://github.com/zhanglpg/code-complexity-measure
|
|
340
|
+
rev: main
|
|
341
|
+
hooks:
|
|
342
|
+
- id: complexity-check
|
|
343
|
+
args: ['--fail-above', '8']
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Architecture
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
complexity_accounting/
|
|
350
|
+
├── scanner.py # Core: cognitive + cyclomatic complexity via libcst
|
|
351
|
+
├── git_tracker.py # Git-aware: compare refs, track trends, PR deltas
|
|
352
|
+
├── churn.py # Git churn analysis (modification frequency)
|
|
353
|
+
├── coupling.py # Import coupling analysis (efferent coupling)
|
|
354
|
+
├── go_parser.py # Go support via tree-sitter
|
|
355
|
+
├── java_parser.py # Java support via tree-sitter
|
|
356
|
+
├── ts_parser.py # TypeScript support via tree-sitter
|
|
357
|
+
├── js_parser.py # JavaScript support via tree-sitter
|
|
358
|
+
├── rust_parser.py # Rust support via tree-sitter
|
|
359
|
+
├── cpp_parser.py # C/C++ support via tree-sitter
|
|
360
|
+
├── config.py # Configuration loading (.complexity.toml, pyproject.toml)
|
|
361
|
+
├── __main__.py # CLI entry point
|
|
362
|
+
└── __init__.py
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
- **libcst** for Python AST parsing (preserves comments, whitespace, position info)
|
|
366
|
+
- **tree-sitter** for Go, Java, TypeScript, JavaScript, Rust, and C/C++ parsing
|
|
367
|
+
- Pure Python, no external services
|
|
368
|
+
- Graceful degradation — churn/coupling are optional, tool works without git
|
|
369
|
+
|
|
370
|
+
## Installation
|
|
371
|
+
|
|
372
|
+
```bash
|
|
373
|
+
# Core (Python analysis only — uses libcst, no extra dependencies)
|
|
374
|
+
pip install complexity-accounting
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Install for Specific Languages
|
|
378
|
+
|
|
379
|
+
Each non-Python language uses [tree-sitter](https://tree-sitter.github.io/) for parsing and is installed as an optional extra:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
# Go
|
|
383
|
+
pip install complexity-accounting[go]
|
|
384
|
+
|
|
385
|
+
# Java
|
|
386
|
+
pip install complexity-accounting[java]
|
|
387
|
+
|
|
388
|
+
# TypeScript
|
|
389
|
+
pip install complexity-accounting[ts]
|
|
390
|
+
|
|
391
|
+
# JavaScript
|
|
392
|
+
pip install complexity-accounting[js]
|
|
393
|
+
|
|
394
|
+
# Rust
|
|
395
|
+
pip install complexity-accounting[rust]
|
|
396
|
+
|
|
397
|
+
# C / C++
|
|
398
|
+
pip install complexity-accounting[cpp]
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
You can combine multiple extras in a single install:
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# Go + Java + TypeScript
|
|
405
|
+
pip install complexity-accounting[go,java,ts]
|
|
406
|
+
|
|
407
|
+
# All supported languages
|
|
408
|
+
pip install complexity-accounting[go,java,ts,js,rust,cpp]
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Development
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
pip install complexity-accounting[dev]
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Requirements
|
|
418
|
+
|
|
419
|
+
- Python >= 3.8
|
|
420
|
+
- libcst >= 1.0.0
|
|
421
|
+
- tomli >= 1.0.0 (Python < 3.11 only)
|
|
422
|
+
|
|
423
|
+
## Testing
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# All tests
|
|
427
|
+
pytest
|
|
428
|
+
|
|
429
|
+
# With coverage
|
|
430
|
+
pytest --cov --cov-report=term-missing
|
|
431
|
+
|
|
432
|
+
# Skip optional language tests
|
|
433
|
+
pytest -m "not go and not java"
|
|
434
|
+
|
|
435
|
+
# End-to-end only
|
|
436
|
+
pytest -m e2e
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## License
|
|
440
|
+
|
|
441
|
+
MIT
|