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.
Files changed (50) hide show
  1. complexity_accounting-1.6.0/PKG-INFO +441 -0
  2. complexity_accounting-1.6.0/README.md +368 -0
  3. complexity_accounting-1.6.0/complexity_accounting/__init__.py +3 -0
  4. complexity_accounting-1.6.0/complexity_accounting/__main__.py +488 -0
  5. complexity_accounting-1.6.0/complexity_accounting/base_parser.py +396 -0
  6. complexity_accounting-1.6.0/complexity_accounting/cache.py +156 -0
  7. complexity_accounting-1.6.0/complexity_accounting/churn.py +70 -0
  8. complexity_accounting-1.6.0/complexity_accounting/config.py +171 -0
  9. complexity_accounting-1.6.0/complexity_accounting/coupling.py +356 -0
  10. complexity_accounting-1.6.0/complexity_accounting/cpp_parser.py +193 -0
  11. complexity_accounting-1.6.0/complexity_accounting/git_tracker.py +327 -0
  12. complexity_accounting-1.6.0/complexity_accounting/go_parser.py +173 -0
  13. complexity_accounting-1.6.0/complexity_accounting/halstead.py +258 -0
  14. complexity_accounting-1.6.0/complexity_accounting/html_report.py +346 -0
  15. complexity_accounting-1.6.0/complexity_accounting/java_parser.py +131 -0
  16. complexity_accounting-1.6.0/complexity_accounting/js_parser.py +160 -0
  17. complexity_accounting-1.6.0/complexity_accounting/models.py +434 -0
  18. complexity_accounting-1.6.0/complexity_accounting/plugin.py +116 -0
  19. complexity_accounting-1.6.0/complexity_accounting/rust_parser.py +144 -0
  20. complexity_accounting-1.6.0/complexity_accounting/sarif.py +171 -0
  21. complexity_accounting-1.6.0/complexity_accounting/scanner.py +552 -0
  22. complexity_accounting-1.6.0/complexity_accounting/ts_parser.py +176 -0
  23. complexity_accounting-1.6.0/complexity_accounting.egg-info/PKG-INFO +441 -0
  24. complexity_accounting-1.6.0/complexity_accounting.egg-info/SOURCES.txt +48 -0
  25. complexity_accounting-1.6.0/complexity_accounting.egg-info/dependency_links.txt +1 -0
  26. complexity_accounting-1.6.0/complexity_accounting.egg-info/entry_points.txt +3 -0
  27. complexity_accounting-1.6.0/complexity_accounting.egg-info/requires.txt +70 -0
  28. complexity_accounting-1.6.0/complexity_accounting.egg-info/top_level.txt +1 -0
  29. complexity_accounting-1.6.0/pyproject.toml +110 -0
  30. complexity_accounting-1.6.0/setup.cfg +4 -0
  31. complexity_accounting-1.6.0/tests/test_cache.py +198 -0
  32. complexity_accounting-1.6.0/tests/test_churn.py +103 -0
  33. complexity_accounting-1.6.0/tests/test_class_metrics.py +307 -0
  34. complexity_accounting-1.6.0/tests/test_config.py +292 -0
  35. complexity_accounting-1.6.0/tests/test_coupling.py +250 -0
  36. complexity_accounting-1.6.0/tests/test_cpp_parser.py +832 -0
  37. complexity_accounting-1.6.0/tests/test_e2e.py +649 -0
  38. complexity_accounting-1.6.0/tests/test_git_tracker.py +417 -0
  39. complexity_accounting-1.6.0/tests/test_go_parser.py +666 -0
  40. complexity_accounting-1.6.0/tests/test_halstead.py +164 -0
  41. complexity_accounting-1.6.0/tests/test_html_report.py +169 -0
  42. complexity_accounting-1.6.0/tests/test_java_parser.py +575 -0
  43. complexity_accounting-1.6.0/tests/test_js_parser.py +643 -0
  44. complexity_accounting-1.6.0/tests/test_main.py +830 -0
  45. complexity_accounting-1.6.0/tests/test_opensandbox.py +127 -0
  46. complexity_accounting-1.6.0/tests/test_plugin.py +87 -0
  47. complexity_accounting-1.6.0/tests/test_rust_parser.py +659 -0
  48. complexity_accounting-1.6.0/tests/test_sarif.py +194 -0
  49. complexity_accounting-1.6.0/tests/test_scanner.py +1453 -0
  50. 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