python-code-quality 0.2.3__tar.gz → 0.3.1__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.
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/PKG-INFO +136 -112
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/README.md +133 -109
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/pyproject.toml +19 -16
- python_code_quality-0.3.1/pyproject.toml.orig +71 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/api.py +9 -3
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/cli.py +12 -14
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/config/config.toml +13 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/context_hash.py +58 -15
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/execution_engine.py +172 -61
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/localtypes.py +4 -2
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/common.py +2 -7
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/coverageparser.py +7 -18
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/interrogateparser.py +31 -24
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/pytestparser.py +1 -1
- python_code_quality-0.3.1/src/py_cq/parsers/ruffformatparser.py +62 -0
- python_code_quality-0.3.1/src/py_cq/source_file.py +199 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/table_formatter.py +1 -1
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/tool_registry.py +1 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/__init__.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/config/__init__.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/language_detector.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/llm_formatter.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/main.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/metric_aggregator.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/__init__.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/banditparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/compileparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/complexityparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/exitcodeparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/halsteadparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/linecountparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/maintainabilityparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/regexcountparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/ruffparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/typarser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/parsers/vultureparser.py +0 -0
- {python_code_quality-0.2.3 → python_code_quality-0.3.1}/src/py_cq/py.typed +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-code-quality
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Python Code Quality Analysis Tool - feed the results from
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Python Code Quality Analysis Tool - feed the results from 12 CQ tools straight into an LLM. Minimal tokens.
|
|
5
5
|
Author: Chris Kilner
|
|
6
6
|
Author-email: Chris Kilner <chris@rhiza.fr>
|
|
7
7
|
License-Expression: MIT
|
|
@@ -17,7 +17,7 @@ Requires-Dist: pytest-cov>=6.1.1
|
|
|
17
17
|
Requires-Dist: pytest-json-report>=1.5.0
|
|
18
18
|
Requires-Dist: radon>=6.0.1
|
|
19
19
|
Requires-Dist: rich>=14.0.0
|
|
20
|
-
Requires-Dist: ruff>=0.14.1
|
|
20
|
+
Requires-Dist: ruff>=0.14.1,<0.17
|
|
21
21
|
Requires-Dist: tomlkit>=0.13.0
|
|
22
22
|
Requires-Dist: ty>=0.0.17
|
|
23
23
|
Requires-Dist: typer>=0.16.0
|
|
@@ -35,7 +35,7 @@ Description-Content-Type: text/markdown
|
|
|
35
35
|
[](https://pypi.org/project/python-code-quality/)
|
|
36
36
|
[](LICENSE)
|
|
37
37
|
|
|
38
|
-
Run
|
|
38
|
+
Run 12 code quality tools, aggregate results into one score, and surface the single most critical defect as a focused markdown prompt — ready to pipe to any LLM.
|
|
39
39
|
|
|
40
40
|
This can dramatically reduce the amount of noise for LLMs (and humans) and remove the need for them to know about these tools.
|
|
41
41
|
|
|
@@ -65,6 +65,8 @@ uv tool install .
|
|
|
65
65
|
|
|
66
66
|
These tools are run in **parallel** except:
|
|
67
67
|
When running '-o llm', we run sequentially and exit early at the first error.
|
|
68
|
+
`coverage` is a special case: it starts alongside `pytest` and is cancelled if
|
|
69
|
+
`pytest` fails, scoring `0%` without a second test run.
|
|
68
70
|
|
|
69
71
|
| Order | Tool | Measures |
|
|
70
72
|
|----------|------|----------|
|
|
@@ -74,11 +76,12 @@ When running '-o llm', we run sequentially and exit early at the first error.
|
|
|
74
76
|
| 4 | bandit | Security vulnerabilities |
|
|
75
77
|
| 5 | pytest | Test pass rate |
|
|
76
78
|
| 6 | coverage | Test coverage |
|
|
77
|
-
| 7 |
|
|
78
|
-
| 8 |
|
|
79
|
-
| 9 | radon
|
|
80
|
-
| 10 |
|
|
81
|
-
| 11 |
|
|
79
|
+
| 7 | vulture | Dead code |
|
|
80
|
+
| 8 | interrogate | Docstring coverage |
|
|
81
|
+
| 9 | radon cc | Cyclomatic complexity |
|
|
82
|
+
| 10 | radon mi | Maintainability index |
|
|
83
|
+
| 11 | radon hal | Halstead volume / bug estimate |
|
|
84
|
+
| 12 | ruff format | Formatting (fraction of files already formatted) |
|
|
82
85
|
|
|
83
86
|
Diskcache is used to cache tool output for lightning fast re-runs. Sane defaults: <100 Mb, <5 days, No pickle risk.
|
|
84
87
|
|
|
@@ -99,7 +102,7 @@ cq check . --exclude demo # Exclude paths from all tools
|
|
|
99
102
|
cq check . --workers 1 # Run sequentially if you like things slow
|
|
100
103
|
cq check . --clear-cache # Clear cached results before running (rarely needed)
|
|
101
104
|
cq check . -o llm --hint # Append "run cq again to verify" (for human workflows)
|
|
102
|
-
cq config path/to/project/ # Show effective tool configuration
|
|
105
|
+
cq config --path path/to/project/ # Show effective tool configuration
|
|
103
106
|
cq is-fixed <fingerprint> # Check whether a specific issue has been resolved
|
|
104
107
|
```
|
|
105
108
|
|
|
@@ -248,14 +251,15 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
|
|
|
248
251
|
│ bandit │ 0.56s │ security │ 1.000 │ OK │
|
|
249
252
|
│ pytest │ 0.91s │ tests │ 1.000 │ OK │
|
|
250
253
|
│ coverage │ 1.26s │ coverage │ 0.910 │ OK │
|
|
251
|
-
│ radon cc │ 0.32s │ simplicity │ 0.982 │ OK │
|
|
252
|
-
│ radon mi │ 0.38s │ maintainability │ 0.869 │ OK │
|
|
253
|
-
│ radon hal │ 0.30s │ file_bug_free │ 0.928 │ OK │
|
|
254
|
-
│ radon hal │ │ file_smallness │ 0.851 │ OK │
|
|
255
|
-
│ radon hal │ │ functions_bug_free │ 0.913 │ OK │
|
|
256
|
-
│ radon hal │ │ functions_smallness │ 0.724 │ OK │
|
|
257
254
|
│ vulture │ 0.32s │ dead_code │ 1.000 │ OK │
|
|
258
255
|
│ interrogate │ 0.36s │ doc_coverage │ 1.000 │ OK │
|
|
256
|
+
│ radon-cc │ 0.32s │ simplicity │ 0.982 │ OK │
|
|
257
|
+
│ radon-mi │ 0.38s │ maintainability │ 0.869 │ OK │
|
|
258
|
+
│ radon-hal │ 0.30s │ file_bug_free │ 0.928 │ OK │
|
|
259
|
+
│ radon-hal │ │ file_smallness │ 0.851 │ OK │
|
|
260
|
+
│ radon-hal │ │ functions_bug_free │ 0.913 │ OK │
|
|
261
|
+
│ radon-hal │ │ functions_smallness │ 0.724 │ OK │
|
|
262
|
+
│ ruff-format │ 0.12s │ formatted │ 1.000 │ OK │
|
|
259
263
|
│ │ │ Score │ 0.965 │ │
|
|
260
264
|
└──────────────────┴──────────┴───────────────────────────┴─────────┴──────────┘
|
|
261
265
|
```
|
|
@@ -337,106 +341,126 @@ warning = 0.9
|
|
|
337
341
|
error = 0.7
|
|
338
342
|
```
|
|
339
343
|
|
|
340
|
-
Tool IDs match the keys in `config/config.
|
|
344
|
+
Tool IDs match the keys in `src/py_cq/config/config.toml`: `compile`, `ruff`, `ty`, `bandit`, `pytest`, `coverage`, `radon-cc`, `radon-mi`, `radon-hal`, `vulture`, `interrogate`, `ruff-format`.
|
|
341
345
|
|
|
342
346
|
|
|
343
347
|
### Default config
|
|
344
348
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
349
|
+
Defined in `src/py_cq/config/config.toml` (sections are namespaced by language):
|
|
350
|
+
|
|
351
|
+
```toml
|
|
352
|
+
[python.compile]
|
|
353
|
+
command = "{python} -m compileall -r 10 -j 8 \"{context_path}\" -x .*venv|\\.claude"
|
|
354
|
+
parser = "CompileParser"
|
|
355
|
+
order = 1
|
|
356
|
+
warning_threshold = 0.9999
|
|
357
|
+
error_threshold = 0.9999
|
|
358
|
+
cache_invariant = "ast"
|
|
359
|
+
|
|
360
|
+
[python.ruff]
|
|
361
|
+
command = "{python} -m ruff check --output-format concise --no-cache \"{context_path}\" --exclude .claude{exclude}"
|
|
362
|
+
exclude_format = " --exclude {path}"
|
|
363
|
+
parser = "RuffParser"
|
|
364
|
+
order = 2
|
|
365
|
+
warning_threshold = 0.9999
|
|
366
|
+
error_threshold = 0.9
|
|
367
|
+
|
|
368
|
+
[python.ty]
|
|
369
|
+
command = "{python} -m ty check --output-format concise --color never \"{context_path}\" --exclude .claude{exclude}"
|
|
370
|
+
exclude_format = " --exclude {path}"
|
|
371
|
+
parser = "TyParser"
|
|
372
|
+
order = 3
|
|
373
|
+
warning_threshold = 0.9999
|
|
374
|
+
error_threshold = 0.8
|
|
375
|
+
run_in_target_env = true
|
|
376
|
+
extra_deps = ["ty"]
|
|
377
|
+
|
|
378
|
+
[python.bandit]
|
|
379
|
+
command = "{python} -m bandit -r {scan_targets} -f json -q -s B101 --severity-level medium{exclude}"
|
|
380
|
+
scan_exclude_names = [".venv", ".claude", "tests"]
|
|
381
|
+
exclude_format = " --exclude {abs_native_path}"
|
|
382
|
+
parser = "BanditParser"
|
|
383
|
+
order = 4
|
|
384
|
+
warning_threshold = 0.9999
|
|
385
|
+
error_threshold = 0.8
|
|
386
|
+
|
|
387
|
+
[python.pytest]
|
|
388
|
+
command = "{python} -m pytest -vv \"{context_path}\" --ignore .claude{exclude}"
|
|
389
|
+
exclude_format = " --ignore {path}"
|
|
390
|
+
parser = "PytestParser"
|
|
391
|
+
order = 5
|
|
392
|
+
warning_threshold = 1.0
|
|
393
|
+
error_threshold = 1.0
|
|
394
|
+
run_in_target_env = true
|
|
395
|
+
extra_deps = ["pytest"]
|
|
396
|
+
skip_for_file = true
|
|
397
|
+
cache_invariant = "ast"
|
|
398
|
+
|
|
399
|
+
[python.coverage]
|
|
400
|
+
command = "{python} -m coverage run --omit=*/tests/*,*/test_*.py -m pytest \"{context_path}\" --ignore .claude{exclude} && {python} -m coverage report --show-missing --omit=*/tests/*,*/test_*.py"
|
|
401
|
+
exclude_format = " --ignore {path}"
|
|
402
|
+
parser = "CoverageParser"
|
|
403
|
+
order = 6
|
|
404
|
+
warning_threshold = 0.9
|
|
405
|
+
error_threshold = 0.5
|
|
406
|
+
run_in_target_env = true
|
|
407
|
+
extra_deps = ["coverage", "pytest"]
|
|
408
|
+
skip_for_file = true
|
|
409
|
+
skip_if = "pytest"
|
|
410
|
+
cache_invariant = "ast"
|
|
411
|
+
|
|
412
|
+
[python.vulture]
|
|
413
|
+
command = "{python} -m vulture \"{context_path}\" --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git,.claude{exclude}"
|
|
414
|
+
exclude_format = ",{path}"
|
|
415
|
+
parser = "VultureParser"
|
|
416
|
+
order = 7
|
|
417
|
+
warning_threshold = 0.9999
|
|
418
|
+
error_threshold = 0.8
|
|
419
|
+
cache_invariant = "ast"
|
|
420
|
+
|
|
421
|
+
[python.interrogate]
|
|
422
|
+
command = "{python} -m interrogate \"{context_path}\" -e .claude{exclude} -v --fail-under 0"
|
|
423
|
+
exclude_format = " -e {path}"
|
|
424
|
+
parser = "InterrogateParser"
|
|
425
|
+
order = 8
|
|
426
|
+
warning_threshold = 0.8
|
|
427
|
+
error_threshold = 0.5
|
|
428
|
+
|
|
429
|
+
[python.interrogate.parser_config]
|
|
430
|
+
skip_empty_init = true
|
|
431
|
+
|
|
432
|
+
[python.radon-cc]
|
|
433
|
+
command = "{python} -m radon cc --json --exclude '.claude/**' \"{context_path}\""
|
|
434
|
+
parser = "ComplexityParser"
|
|
435
|
+
order = 9
|
|
436
|
+
gate_strict = false
|
|
437
|
+
warning_threshold = 0.6
|
|
438
|
+
error_threshold = 0.4
|
|
439
|
+
|
|
440
|
+
[python.radon-mi]
|
|
441
|
+
command = "{python} -m radon mi -s --json --exclude '.claude/**' \"{context_path}\""
|
|
442
|
+
parser = "MaintainabilityParser"
|
|
443
|
+
order = 10
|
|
444
|
+
gate_strict = false
|
|
445
|
+
warning_threshold = 0.6
|
|
446
|
+
error_threshold = 0.4
|
|
447
|
+
|
|
448
|
+
[python.radon-hal]
|
|
449
|
+
command = "{python} -m radon hal -f --json --exclude '.claude/**' \"{context_path}\""
|
|
450
|
+
parser = "HalsteadParser"
|
|
451
|
+
order = 11
|
|
452
|
+
gate_strict = false
|
|
453
|
+
warning_threshold = 0.35
|
|
454
|
+
error_threshold = 0.3
|
|
455
|
+
|
|
456
|
+
[python.ruff-format]
|
|
457
|
+
command = "{python} -m ruff format --check --output-format concise --no-cache \"{context_path}\" --exclude .claude --config \"include=['*.py','*.pyi','*.ipynb']\"{exclude}"
|
|
458
|
+
exclude_format = " --exclude {path}"
|
|
459
|
+
parser = "RuffFormatParser"
|
|
460
|
+
order = 12
|
|
461
|
+
gate_strict = false
|
|
462
|
+
warning_threshold = 0.9999
|
|
463
|
+
error_threshold = 0.5
|
|
440
464
|
```
|
|
441
465
|
|
|
442
466
|
## Respect
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](https://pypi.org/project/python-code-quality/)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
9
|
-
Run
|
|
9
|
+
Run 12 code quality tools, aggregate results into one score, and surface the single most critical defect as a focused markdown prompt — ready to pipe to any LLM.
|
|
10
10
|
|
|
11
11
|
This can dramatically reduce the amount of noise for LLMs (and humans) and remove the need for them to know about these tools.
|
|
12
12
|
|
|
@@ -36,6 +36,8 @@ uv tool install .
|
|
|
36
36
|
|
|
37
37
|
These tools are run in **parallel** except:
|
|
38
38
|
When running '-o llm', we run sequentially and exit early at the first error.
|
|
39
|
+
`coverage` is a special case: it starts alongside `pytest` and is cancelled if
|
|
40
|
+
`pytest` fails, scoring `0%` without a second test run.
|
|
39
41
|
|
|
40
42
|
| Order | Tool | Measures |
|
|
41
43
|
|----------|------|----------|
|
|
@@ -45,11 +47,12 @@ When running '-o llm', we run sequentially and exit early at the first error.
|
|
|
45
47
|
| 4 | bandit | Security vulnerabilities |
|
|
46
48
|
| 5 | pytest | Test pass rate |
|
|
47
49
|
| 6 | coverage | Test coverage |
|
|
48
|
-
| 7 |
|
|
49
|
-
| 8 |
|
|
50
|
-
| 9 | radon
|
|
51
|
-
| 10 |
|
|
52
|
-
| 11 |
|
|
50
|
+
| 7 | vulture | Dead code |
|
|
51
|
+
| 8 | interrogate | Docstring coverage |
|
|
52
|
+
| 9 | radon cc | Cyclomatic complexity |
|
|
53
|
+
| 10 | radon mi | Maintainability index |
|
|
54
|
+
| 11 | radon hal | Halstead volume / bug estimate |
|
|
55
|
+
| 12 | ruff format | Formatting (fraction of files already formatted) |
|
|
53
56
|
|
|
54
57
|
Diskcache is used to cache tool output for lightning fast re-runs. Sane defaults: <100 Mb, <5 days, No pickle risk.
|
|
55
58
|
|
|
@@ -70,7 +73,7 @@ cq check . --exclude demo # Exclude paths from all tools
|
|
|
70
73
|
cq check . --workers 1 # Run sequentially if you like things slow
|
|
71
74
|
cq check . --clear-cache # Clear cached results before running (rarely needed)
|
|
72
75
|
cq check . -o llm --hint # Append "run cq again to verify" (for human workflows)
|
|
73
|
-
cq config path/to/project/ # Show effective tool configuration
|
|
76
|
+
cq config --path path/to/project/ # Show effective tool configuration
|
|
74
77
|
cq is-fixed <fingerprint> # Check whether a specific issue has been resolved
|
|
75
78
|
```
|
|
76
79
|
|
|
@@ -219,14 +222,15 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
|
|
|
219
222
|
│ bandit │ 0.56s │ security │ 1.000 │ OK │
|
|
220
223
|
│ pytest │ 0.91s │ tests │ 1.000 │ OK │
|
|
221
224
|
│ coverage │ 1.26s │ coverage │ 0.910 │ OK │
|
|
222
|
-
│ radon cc │ 0.32s │ simplicity │ 0.982 │ OK │
|
|
223
|
-
│ radon mi │ 0.38s │ maintainability │ 0.869 │ OK │
|
|
224
|
-
│ radon hal │ 0.30s │ file_bug_free │ 0.928 │ OK │
|
|
225
|
-
│ radon hal │ │ file_smallness │ 0.851 │ OK │
|
|
226
|
-
│ radon hal │ │ functions_bug_free │ 0.913 │ OK │
|
|
227
|
-
│ radon hal │ │ functions_smallness │ 0.724 │ OK │
|
|
228
225
|
│ vulture │ 0.32s │ dead_code │ 1.000 │ OK │
|
|
229
226
|
│ interrogate │ 0.36s │ doc_coverage │ 1.000 │ OK │
|
|
227
|
+
│ radon-cc │ 0.32s │ simplicity │ 0.982 │ OK │
|
|
228
|
+
│ radon-mi │ 0.38s │ maintainability │ 0.869 │ OK │
|
|
229
|
+
│ radon-hal │ 0.30s │ file_bug_free │ 0.928 │ OK │
|
|
230
|
+
│ radon-hal │ │ file_smallness │ 0.851 │ OK │
|
|
231
|
+
│ radon-hal │ │ functions_bug_free │ 0.913 │ OK │
|
|
232
|
+
│ radon-hal │ │ functions_smallness │ 0.724 │ OK │
|
|
233
|
+
│ ruff-format │ 0.12s │ formatted │ 1.000 │ OK │
|
|
230
234
|
│ │ │ Score │ 0.965 │ │
|
|
231
235
|
└──────────────────┴──────────┴───────────────────────────┴─────────┴──────────┘
|
|
232
236
|
```
|
|
@@ -308,106 +312,126 @@ warning = 0.9
|
|
|
308
312
|
error = 0.7
|
|
309
313
|
```
|
|
310
314
|
|
|
311
|
-
Tool IDs match the keys in `config/config.
|
|
315
|
+
Tool IDs match the keys in `src/py_cq/config/config.toml`: `compile`, `ruff`, `ty`, `bandit`, `pytest`, `coverage`, `radon-cc`, `radon-mi`, `radon-hal`, `vulture`, `interrogate`, `ruff-format`.
|
|
312
316
|
|
|
313
317
|
|
|
314
318
|
### Default config
|
|
315
319
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
320
|
+
Defined in `src/py_cq/config/config.toml` (sections are namespaced by language):
|
|
321
|
+
|
|
322
|
+
```toml
|
|
323
|
+
[python.compile]
|
|
324
|
+
command = "{python} -m compileall -r 10 -j 8 \"{context_path}\" -x .*venv|\\.claude"
|
|
325
|
+
parser = "CompileParser"
|
|
326
|
+
order = 1
|
|
327
|
+
warning_threshold = 0.9999
|
|
328
|
+
error_threshold = 0.9999
|
|
329
|
+
cache_invariant = "ast"
|
|
330
|
+
|
|
331
|
+
[python.ruff]
|
|
332
|
+
command = "{python} -m ruff check --output-format concise --no-cache \"{context_path}\" --exclude .claude{exclude}"
|
|
333
|
+
exclude_format = " --exclude {path}"
|
|
334
|
+
parser = "RuffParser"
|
|
335
|
+
order = 2
|
|
336
|
+
warning_threshold = 0.9999
|
|
337
|
+
error_threshold = 0.9
|
|
338
|
+
|
|
339
|
+
[python.ty]
|
|
340
|
+
command = "{python} -m ty check --output-format concise --color never \"{context_path}\" --exclude .claude{exclude}"
|
|
341
|
+
exclude_format = " --exclude {path}"
|
|
342
|
+
parser = "TyParser"
|
|
343
|
+
order = 3
|
|
344
|
+
warning_threshold = 0.9999
|
|
345
|
+
error_threshold = 0.8
|
|
346
|
+
run_in_target_env = true
|
|
347
|
+
extra_deps = ["ty"]
|
|
348
|
+
|
|
349
|
+
[python.bandit]
|
|
350
|
+
command = "{python} -m bandit -r {scan_targets} -f json -q -s B101 --severity-level medium{exclude}"
|
|
351
|
+
scan_exclude_names = [".venv", ".claude", "tests"]
|
|
352
|
+
exclude_format = " --exclude {abs_native_path}"
|
|
353
|
+
parser = "BanditParser"
|
|
354
|
+
order = 4
|
|
355
|
+
warning_threshold = 0.9999
|
|
356
|
+
error_threshold = 0.8
|
|
357
|
+
|
|
358
|
+
[python.pytest]
|
|
359
|
+
command = "{python} -m pytest -vv \"{context_path}\" --ignore .claude{exclude}"
|
|
360
|
+
exclude_format = " --ignore {path}"
|
|
361
|
+
parser = "PytestParser"
|
|
362
|
+
order = 5
|
|
363
|
+
warning_threshold = 1.0
|
|
364
|
+
error_threshold = 1.0
|
|
365
|
+
run_in_target_env = true
|
|
366
|
+
extra_deps = ["pytest"]
|
|
367
|
+
skip_for_file = true
|
|
368
|
+
cache_invariant = "ast"
|
|
369
|
+
|
|
370
|
+
[python.coverage]
|
|
371
|
+
command = "{python} -m coverage run --omit=*/tests/*,*/test_*.py -m pytest \"{context_path}\" --ignore .claude{exclude} && {python} -m coverage report --show-missing --omit=*/tests/*,*/test_*.py"
|
|
372
|
+
exclude_format = " --ignore {path}"
|
|
373
|
+
parser = "CoverageParser"
|
|
374
|
+
order = 6
|
|
375
|
+
warning_threshold = 0.9
|
|
376
|
+
error_threshold = 0.5
|
|
377
|
+
run_in_target_env = true
|
|
378
|
+
extra_deps = ["coverage", "pytest"]
|
|
379
|
+
skip_for_file = true
|
|
380
|
+
skip_if = "pytest"
|
|
381
|
+
cache_invariant = "ast"
|
|
382
|
+
|
|
383
|
+
[python.vulture]
|
|
384
|
+
command = "{python} -m vulture \"{context_path}\" --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git,.claude{exclude}"
|
|
385
|
+
exclude_format = ",{path}"
|
|
386
|
+
parser = "VultureParser"
|
|
387
|
+
order = 7
|
|
388
|
+
warning_threshold = 0.9999
|
|
389
|
+
error_threshold = 0.8
|
|
390
|
+
cache_invariant = "ast"
|
|
391
|
+
|
|
392
|
+
[python.interrogate]
|
|
393
|
+
command = "{python} -m interrogate \"{context_path}\" -e .claude{exclude} -v --fail-under 0"
|
|
394
|
+
exclude_format = " -e {path}"
|
|
395
|
+
parser = "InterrogateParser"
|
|
396
|
+
order = 8
|
|
397
|
+
warning_threshold = 0.8
|
|
398
|
+
error_threshold = 0.5
|
|
399
|
+
|
|
400
|
+
[python.interrogate.parser_config]
|
|
401
|
+
skip_empty_init = true
|
|
402
|
+
|
|
403
|
+
[python.radon-cc]
|
|
404
|
+
command = "{python} -m radon cc --json --exclude '.claude/**' \"{context_path}\""
|
|
405
|
+
parser = "ComplexityParser"
|
|
406
|
+
order = 9
|
|
407
|
+
gate_strict = false
|
|
408
|
+
warning_threshold = 0.6
|
|
409
|
+
error_threshold = 0.4
|
|
410
|
+
|
|
411
|
+
[python.radon-mi]
|
|
412
|
+
command = "{python} -m radon mi -s --json --exclude '.claude/**' \"{context_path}\""
|
|
413
|
+
parser = "MaintainabilityParser"
|
|
414
|
+
order = 10
|
|
415
|
+
gate_strict = false
|
|
416
|
+
warning_threshold = 0.6
|
|
417
|
+
error_threshold = 0.4
|
|
418
|
+
|
|
419
|
+
[python.radon-hal]
|
|
420
|
+
command = "{python} -m radon hal -f --json --exclude '.claude/**' \"{context_path}\""
|
|
421
|
+
parser = "HalsteadParser"
|
|
422
|
+
order = 11
|
|
423
|
+
gate_strict = false
|
|
424
|
+
warning_threshold = 0.35
|
|
425
|
+
error_threshold = 0.3
|
|
426
|
+
|
|
427
|
+
[python.ruff-format]
|
|
428
|
+
command = "{python} -m ruff format --check --output-format concise --no-cache \"{context_path}\" --exclude .claude --config \"include=['*.py','*.pyi','*.ipynb']\"{exclude}"
|
|
429
|
+
exclude_format = " --exclude {path}"
|
|
430
|
+
parser = "RuffFormatParser"
|
|
431
|
+
order = 12
|
|
432
|
+
gate_strict = false
|
|
433
|
+
warning_threshold = 0.9999
|
|
434
|
+
error_threshold = 0.5
|
|
411
435
|
```
|
|
412
436
|
|
|
413
437
|
## Respect
|