python-code-quality 0.1.11__py3-none-any.whl → 0.1.14__py3-none-any.whl
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.
- py_cq/__init__.py +0 -4
- py_cq/cli.py +22 -3
- py_cq/config/config.yaml +12 -6
- py_cq/execution_engine.py +33 -7
- py_cq/localtypes.py +1 -0
- py_cq/parsers/__init__.py +1 -0
- py_cq/parsers/interrogateparser.py +4 -4
- py_cq/tool_registry.py +1 -0
- {python_code_quality-0.1.11.dist-info → python_code_quality-0.1.14.dist-info}/METADATA +54 -48
- {python_code_quality-0.1.11.dist-info → python_code_quality-0.1.14.dist-info}/RECORD +12 -12
- {python_code_quality-0.1.11.dist-info → python_code_quality-0.1.14.dist-info}/WHEEL +1 -1
- {python_code_quality-0.1.11.dist-info → python_code_quality-0.1.14.dist-info}/entry_points.txt +0 -0
py_cq/__init__.py
CHANGED
|
@@ -4,7 +4,3 @@ The module defines a single function, `hello`, which returns the string
|
|
|
4
4
|
`'Hello from py_cq!'`. It can serve as a minimal example, placeholder, or
|
|
5
5
|
testing stub in larger applications."""
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
def hello() -> str:
|
|
9
|
-
"""Returns the greeting string `'Hello from py_cq!'`."""
|
|
10
|
-
return "Hello from py_cq!"
|
py_cq/cli.py
CHANGED
|
@@ -84,6 +84,7 @@ def _apply_user_config(base: dict[str, ToolConfig], user_cfg: dict) -> dict[str,
|
|
|
84
84
|
run_in_target_env=tool_data.get("run_in_target_env", False),
|
|
85
85
|
extra_deps=tool_data.get("extra_deps", []),
|
|
86
86
|
parser_config=tool_data.get("parser_config", {}),
|
|
87
|
+
exclude_format=tool_data.get("exclude_format", ""),
|
|
87
88
|
)
|
|
88
89
|
except KeyError as e:
|
|
89
90
|
raise typer.BadParameter(f"[tool.cq.tools.{tool_id}] missing required field {e}")
|
|
@@ -125,6 +126,15 @@ def check(
|
|
|
125
126
|
language: str | None = typer.Option(
|
|
126
127
|
None, "--language", "-l", help="Override language detection (e.g. python, typescript, rust)"
|
|
127
128
|
),
|
|
129
|
+
only: str | None = typer.Option(
|
|
130
|
+
None, "--only", help="Comma-separated tool IDs to run (e.g. ruff,ty,pytest)"
|
|
131
|
+
),
|
|
132
|
+
skip: str | None = typer.Option(
|
|
133
|
+
None, "--skip", help="Comma-separated tool IDs to skip (e.g. bandit,vulture)"
|
|
134
|
+
),
|
|
135
|
+
exclude: str | None = typer.Option(
|
|
136
|
+
None, "--exclude", help="Comma-separated paths to exclude (e.g. demo,docs)"
|
|
137
|
+
),
|
|
128
138
|
):
|
|
129
139
|
"""Feed the results from 11+ code quality tools to an LLM. Try: cq check . -o llm""" # --help
|
|
130
140
|
path_obj = Path(path)
|
|
@@ -153,18 +163,27 @@ def check(
|
|
|
153
163
|
user_cfg = load_user_config(path_obj)
|
|
154
164
|
context_lines: int = int(user_cfg.get("context_lines", 15))
|
|
155
165
|
effective_registry = _apply_user_config(tool_registry, user_cfg)
|
|
166
|
+
if only:
|
|
167
|
+
keep = set(only.split(","))
|
|
168
|
+
effective_registry = {k: v for k, v in effective_registry.items() if k in keep}
|
|
169
|
+
if skip:
|
|
170
|
+
drop = set(skip.split(","))
|
|
171
|
+
effective_registry = {k: v for k, v in effective_registry.items() if k not in drop}
|
|
172
|
+
config_excludes: list[str] = user_cfg.get("exclude", [])
|
|
173
|
+
cli_excludes: list[str] = [e.strip() for e in exclude.split(",")] if exclude else []
|
|
174
|
+
excludes = list(dict.fromkeys(config_excludes + cli_excludes))
|
|
156
175
|
if clear_cache:
|
|
157
176
|
tool_cache.clear()
|
|
158
|
-
tool_results = run_tools(effective_registry.values(), path, workers, early_exit=(output == OutputMode.LLM))
|
|
177
|
+
tool_results = run_tools(effective_registry.values(), path, workers, early_exit=(output == OutputMode.LLM), excludes=excludes)
|
|
159
178
|
# for tr in tool_results:
|
|
160
179
|
# log.debug(json.dumps(tr.to_dict(), indent=2))
|
|
161
180
|
combined_metrics = aggregate_metrics(path=path, metrics=tool_results)
|
|
162
181
|
if output == OutputMode.SCORE:
|
|
163
182
|
console.print(combined_metrics.score)
|
|
164
183
|
elif output == OutputMode.JSON:
|
|
165
|
-
|
|
184
|
+
print(json.dumps([tr.to_dict() for tr in tool_results], indent=2))
|
|
166
185
|
elif output == OutputMode.RAW:
|
|
167
|
-
|
|
186
|
+
print(json.dumps([tr.raw.to_dict() for tr in tool_results], indent=2))
|
|
168
187
|
elif output == OutputMode.LLM:
|
|
169
188
|
# log.setLevel("CRITICAL")
|
|
170
189
|
from py_cq.llm_formatter import format_for_llm
|
py_cq/config/config.yaml
CHANGED
|
@@ -8,14 +8,16 @@ python:
|
|
|
8
8
|
error_threshold: 0.9999
|
|
9
9
|
|
|
10
10
|
ruff:
|
|
11
|
-
command: "{python} -m ruff check --output-format concise --no-cache \"{context_path}\""
|
|
11
|
+
command: "{python} -m ruff check --output-format concise --no-cache \"{context_path}\"{exclude}"
|
|
12
|
+
exclude_format: " --exclude {path}"
|
|
12
13
|
parser: "RuffParser"
|
|
13
14
|
order: 2
|
|
14
15
|
warning_threshold: 0.9999
|
|
15
16
|
error_threshold: 0.9
|
|
16
17
|
|
|
17
18
|
ty:
|
|
18
|
-
command: "{python} -m ty check --output-format concise --color never \"{context_path}\""
|
|
19
|
+
command: "{python} -m ty check --output-format concise --color never \"{context_path}\"{exclude}"
|
|
20
|
+
exclude_format: " --exclude {path}"
|
|
19
21
|
parser: "TyParser"
|
|
20
22
|
order: 3
|
|
21
23
|
warning_threshold: 0.9999
|
|
@@ -25,14 +27,16 @@ python:
|
|
|
25
27
|
- ty
|
|
26
28
|
|
|
27
29
|
bandit:
|
|
28
|
-
command: "{python} -m bandit -r \"{context_path}\" -f json -q -s B101 --severity-level medium --exclude \"{input_path_posix}/.venv,{input_path_posix}/tests\""
|
|
30
|
+
command: "{python} -m bandit -r \"{context_path}\" -f json -q -s B101 --severity-level medium --exclude \"{input_path_posix}/.venv,{input_path_posix}/tests{exclude}\""
|
|
31
|
+
exclude_format: ",{input_path_posix}/{path}"
|
|
29
32
|
parser: "BanditParser"
|
|
30
33
|
order: 4
|
|
31
34
|
warning_threshold: 0.9999
|
|
32
35
|
error_threshold: 0.8
|
|
33
36
|
|
|
34
37
|
pytest:
|
|
35
|
-
command: "{python} -m pytest -v \"{context_path}\""
|
|
38
|
+
command: "{python} -m pytest -v \"{context_path}\"{exclude}"
|
|
39
|
+
exclude_format: " --ignore {path}"
|
|
36
40
|
parser: "PytestParser"
|
|
37
41
|
order: 5
|
|
38
42
|
warning_threshold: 1.0
|
|
@@ -74,14 +78,16 @@ python:
|
|
|
74
78
|
error_threshold: 0.3
|
|
75
79
|
|
|
76
80
|
vulture:
|
|
77
|
-
command: "{python} -m vulture \"{context_path}\" --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git"
|
|
81
|
+
command: "{python} -m vulture \"{context_path}\" --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git{exclude}"
|
|
82
|
+
exclude_format: ",{path}"
|
|
78
83
|
parser: "VultureParser"
|
|
79
84
|
order: 10
|
|
80
85
|
warning_threshold: 0.9999
|
|
81
86
|
error_threshold: 0.8
|
|
82
87
|
|
|
83
88
|
interrogate:
|
|
84
|
-
command: "{python} -m interrogate \"{context_path}\" -v --fail-under 0"
|
|
89
|
+
command: "{python} -m interrogate \"{context_path}\" -e tests{exclude} -v --fail-under 0"
|
|
90
|
+
exclude_format: " -e {path}"
|
|
85
91
|
parser: "InterrogateParser"
|
|
86
92
|
order: 11
|
|
87
93
|
warning_threshold: 0.8
|
py_cq/execution_engine.py
CHANGED
|
@@ -41,7 +41,29 @@ def _find_project_root(path: Path) -> Path | None:
|
|
|
41
41
|
return None
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def
|
|
44
|
+
def _dep_in_venv(dep: str, project_root: Path) -> bool:
|
|
45
|
+
"""Return True if `dep` is installed in the project's .venv."""
|
|
46
|
+
venv = project_root / ".venv"
|
|
47
|
+
if not venv.exists():
|
|
48
|
+
return False
|
|
49
|
+
for subdir in ("Scripts", "bin"):
|
|
50
|
+
for suffix in ("", ".exe", ".cmd"):
|
|
51
|
+
if (venv / subdir / f"{dep}{suffix}").exists():
|
|
52
|
+
return True
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _build_exclude_str(exclude_format: str, excludes: list[str], **extra_vars: str) -> str:
|
|
57
|
+
if not exclude_format or not excludes:
|
|
58
|
+
return ""
|
|
59
|
+
parts = []
|
|
60
|
+
for exc in excludes:
|
|
61
|
+
abs_posix_path = Path(exc).resolve().as_posix()
|
|
62
|
+
parts.append(exclude_format.format(path=exc, abs_posix_path=abs_posix_path, **extra_vars))
|
|
63
|
+
return "".join(parts)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def run_tool(tool_config: ToolConfig, context_path: str, excludes: list[str] | None = None) -> RawResult:
|
|
45
67
|
"""Runs a tool defined by its configuration and returns the execution result.
|
|
46
68
|
|
|
47
69
|
Args:
|
|
@@ -60,7 +82,7 @@ def run_tool(tool_config: ToolConfig, context_path: str) -> RawResult:
|
|
|
60
82
|
>>> result.return_code
|
|
61
83
|
0"""
|
|
62
84
|
python = sys.executable
|
|
63
|
-
path = context_path
|
|
85
|
+
path = str(Path(context_path))
|
|
64
86
|
if tool_config.run_in_target_env:
|
|
65
87
|
uv = shutil.which("uv")
|
|
66
88
|
if uv:
|
|
@@ -72,11 +94,15 @@ def run_tool(tool_config: ToolConfig, context_path: str) -> RawResult:
|
|
|
72
94
|
project_root = _find_project_root(resolved)
|
|
73
95
|
abs_dir = str(project_root) if project_root else str(resolved.parent)
|
|
74
96
|
path = str(resolved)
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
project_root_path = Path(abs_dir)
|
|
98
|
+
missing_deps = [d for d in tool_config.extra_deps if not _dep_in_venv(d, project_root_path)]
|
|
99
|
+
with_flags = " ".join(f"--with {dep}" for dep in missing_deps)
|
|
100
|
+
no_sync = "--no-sync" if sys.executable.startswith(abs_dir) else ""
|
|
101
|
+
python = f'"{uv}" run {no_sync} --directory "{abs_dir}" {with_flags}'.strip()
|
|
77
102
|
abs_context_path = str(Path(context_path).resolve())
|
|
78
103
|
input_path_posix = Path(context_path).as_posix().rstrip("/")
|
|
79
|
-
|
|
104
|
+
exclude = _build_exclude_str(tool_config.exclude_format, excludes or [], input_path_posix=input_path_posix)
|
|
105
|
+
command = tool_config.command.format(context_path=path, abs_context_path=abs_context_path, input_path_posix=input_path_posix, python=python, exclude=exclude)
|
|
80
106
|
cache_key = f"{command}:{get_context_hash(context_path)}"
|
|
81
107
|
if cache_key in _cache:
|
|
82
108
|
log.info(f"Cache hit: {command}")
|
|
@@ -96,7 +122,7 @@ def run_tool(tool_config: ToolConfig, context_path: str) -> RawResult:
|
|
|
96
122
|
return raw_result
|
|
97
123
|
|
|
98
124
|
|
|
99
|
-
def run_tools(tool_configs: Collection[ToolConfig], path: str, max_workers: int = 0, early_exit: bool = False) -> list[ToolResult]:
|
|
125
|
+
def run_tools(tool_configs: Collection[ToolConfig], path: str, max_workers: int = 0, early_exit: bool = False, excludes: list[str] | None = None) -> list[ToolResult]:
|
|
100
126
|
"""Run multiple tools and return their parsed results.
|
|
101
127
|
|
|
102
128
|
Runs each tool specified in *tool_configs* on the file or directory at
|
|
@@ -138,7 +164,7 @@ def run_tools(tool_configs: Collection[ToolConfig], path: str, max_workers: int
|
|
|
138
164
|
>>> results = run_tools(configs, '/path/to/project', parallel=True)"""
|
|
139
165
|
def _run_and_parse(tool_config: ToolConfig) -> tuple[int, ToolResult]:
|
|
140
166
|
t0 = time.perf_counter()
|
|
141
|
-
raw_result = run_tool(tool_config, path)
|
|
167
|
+
raw_result = run_tool(tool_config, path, excludes)
|
|
142
168
|
tr = tool_config.parser_class(tool_config.parser_config).parse(raw_result)
|
|
143
169
|
tr.duration_s = time.perf_counter() - t0
|
|
144
170
|
return tool_config.order, tr
|
py_cq/localtypes.py
CHANGED
|
@@ -22,6 +22,7 @@ class ToolConfig:
|
|
|
22
22
|
run_in_target_env: bool = False # If True, run in target project's env via uv
|
|
23
23
|
extra_deps: list[str] = field(default_factory=list) # Extra deps to inject via uv --with
|
|
24
24
|
parser_config: dict[str, Any] = field(default_factory=dict)
|
|
25
|
+
exclude_format: str = "" # Per-path template for --exclude injection, e.g. " --exclude {path}"
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
@dataclass
|
py_cq/parsers/__init__.py
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tool Response parsers"""
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Interrogate is invoked with ``-v --fail-under 0``, producing a table of
|
|
4
4
|
per-file docstring coverage on stdout::
|
|
5
5
|
|
|
6
|
-
| src/foo.py | 5 | 2 | 60% |
|
|
7
|
-
| TOTAL | 5 | 2 | 60% |
|
|
6
|
+
| src/foo.py | 5 | 2 | 3 | 60% |
|
|
7
|
+
| TOTAL | 5 | 2 | 3 | 60.0% |
|
|
8
8
|
|
|
9
9
|
The parser extracts per-file coverage and the TOTAL row, storing the TOTAL
|
|
10
10
|
as the ``doc_coverage`` metric (0.0–1.0).
|
|
@@ -14,7 +14,7 @@ import re
|
|
|
14
14
|
|
|
15
15
|
from py_cq.localtypes import AbstractParser, RawResult, ToolResult
|
|
16
16
|
|
|
17
|
-
_ROW_RE = re.compile(r"^\|\s+(.+?)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+(\d+)%\s
|
|
17
|
+
_ROW_RE = re.compile(r"^\|\s+(.+?)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+\d+\s+\|\s+(\d+(?:\.\d+)?)%\s*\|")
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class InterrogateParser(AbstractParser):
|
|
@@ -30,7 +30,7 @@ class InterrogateParser(AbstractParser):
|
|
|
30
30
|
name = m.group(1).strip()
|
|
31
31
|
total = int(m.group(2))
|
|
32
32
|
miss = int(m.group(3))
|
|
33
|
-
cover =
|
|
33
|
+
cover = float(m.group(4))
|
|
34
34
|
if name == "TOTAL":
|
|
35
35
|
total_coverage = cover / 100.0
|
|
36
36
|
elif total > 0:
|
py_cq/tool_registry.py
CHANGED
|
@@ -30,6 +30,7 @@ def load_tool_configs() -> dict[str, ToolConfig]:
|
|
|
30
30
|
run_in_target_env=tool_data.get("run_in_target_env", False),
|
|
31
31
|
extra_deps=tool_data.get("extra_deps", []),
|
|
32
32
|
parser_config=tool_data.get("parser_config", {}),
|
|
33
|
+
exclude_format=tool_data.get("exclude_format", ""),
|
|
33
34
|
)
|
|
34
35
|
return registry
|
|
35
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-code-quality
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
4
4
|
Summary: Python Code Quality Analysis Tool - feed the results from 11 CQ tools straight into an LLM. Minimal tokens.
|
|
5
5
|
Author: Chris Kilner
|
|
6
6
|
Author-email: Chris Kilner <chris@rhiza.fr>
|
|
@@ -31,43 +31,19 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
|
|
32
32
|
[](https://github.com/rhiza-fr/py-cq/actions/workflows/ci.yml)
|
|
33
33
|
[](https://codecov.io/gh/rhiza-fr/py-cq)
|
|
34
|
-
[](https://pypi.org/project/python-code-quality/)
|
|
35
|
-
[](https://pypi.org/project/python-code-quality/)
|
|
34
|
+
[](https://pypi.org/project/python-code-quality/)
|
|
35
|
+
[](https://pypi.org/project/python-code-quality/)
|
|
36
36
|
[](LICENSE)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Why? It removes the mental burden of understanding all these tools and parsing their results.
|
|
41
|
-
|
|
42
|
-
The primary workflow is:
|
|
38
|
+
Run 11+ 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.
|
|
43
39
|
|
|
44
40
|
```bash
|
|
45
|
-
|
|
46
|
-
cq check .
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```python
|
|
50
|
-
`data/problems/travelling_salesman/ts_bad.py:21` — **F841**: Local variable `unused_variable` is assigned to but never used
|
|
51
|
-
|
|
52
|
-
18: min_dist = float("inf")
|
|
53
|
-
19: nearest_city = None
|
|
54
|
-
20: for city in cities:
|
|
55
|
-
21: unused_variable = 67
|
|
56
|
-
22: dist = calc_dist(current_city, city)
|
|
57
|
-
23: if dist < min_dist:
|
|
58
|
-
24: min_dist = dist
|
|
59
|
-
25: nearest_city = city
|
|
60
|
-
|
|
61
|
-
Please fix only this issue. After fixing, run `cq check . -o llm` to verify.
|
|
62
|
-
```
|
|
63
|
-
Feed to an LLM with edit tools and repeat until there are no issues, e.g.
|
|
64
|
-
|
|
65
|
-
```python
|
|
66
|
-
cq check . -o llm | claude -p "fix this"
|
|
67
|
-
# or
|
|
68
|
-
cq check . -o llm | ollama run gpt-oss:20b "Explain how to fix this"
|
|
41
|
+
cq check . -o llm # top defect as markdown, pipe to an LLM
|
|
42
|
+
cq check . # table overview of all scores
|
|
43
|
+
cq check . -o score # numeric score only, exits 1 on errors (CI gate)
|
|
69
44
|
```
|
|
70
45
|
|
|
46
|
+

|
|
71
47
|
|
|
72
48
|
## Install
|
|
73
49
|
|
|
@@ -112,6 +88,9 @@ cq check . -o score # Numeric score only for CI
|
|
|
112
88
|
cq check . -o json # Detailed parsed JSON output for jq
|
|
113
89
|
cq check . -o raw # Raw tool output for debug
|
|
114
90
|
cq check path/to/file.py # Just one file (skips pytest and coverage)
|
|
91
|
+
cq check . --only ruff,ty # Run only specific tools
|
|
92
|
+
cq check . --skip bandit # Skip specific tools
|
|
93
|
+
cq check . --exclude demo # Exclude paths from all tools
|
|
115
94
|
cq check . --workers 1 # Run sequentially if you like things slow
|
|
116
95
|
cq check . --clear-cache # Clear cached results before running (rarely needed)
|
|
117
96
|
cq config path/to/project/ # Show effective tool configuration
|
|
@@ -131,10 +110,17 @@ Add a stop hook to your project's `.claude/settings.json` so Claude automaticall
|
|
|
131
110
|
```json
|
|
132
111
|
{
|
|
133
112
|
"hooks": {
|
|
134
|
-
"Stop": [
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
113
|
+
"Stop": [
|
|
114
|
+
{
|
|
115
|
+
"matcher": "",
|
|
116
|
+
"hooks": [
|
|
117
|
+
{
|
|
118
|
+
"type": "command",
|
|
119
|
+
"command": "cq check . -o score && echo 'CQ: all clear' || cq check . -o llm; true"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
138
124
|
}
|
|
139
125
|
}
|
|
140
126
|
```
|
|
@@ -231,6 +217,16 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
|
|
|
231
217
|
]
|
|
232
218
|
```
|
|
233
219
|
|
|
220
|
+
Both `json` and `raw` output pipe cleanly to `jq`:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Get the coverage section
|
|
224
|
+
cq check . -o raw | jq '.[] | select(.tool_name == "coverage")'
|
|
225
|
+
|
|
226
|
+
# Get parsed coverage metrics only
|
|
227
|
+
cq check . -o json | jq '.[] | select(.tool_name == "coverage") | .metrics'
|
|
228
|
+
```
|
|
229
|
+
|
|
234
230
|
## Configuration
|
|
235
231
|
|
|
236
232
|
Add a `[tool.cq]` section to your project's `pyproject.toml`:
|
|
@@ -240,6 +236,9 @@ Add a `[tool.cq]` section to your project's `pyproject.toml`:
|
|
|
240
236
|
# Skip tools that are slow or not relevant to your project
|
|
241
237
|
disable = ["coverage", "interrogate"]
|
|
242
238
|
|
|
239
|
+
# Exclude paths from all tools (merged with --exclude CLI flag)
|
|
240
|
+
exclude = ["demo", "docs"]
|
|
241
|
+
|
|
243
242
|
# Lines of source context shown around each defect in LLM output (default: 15)
|
|
244
243
|
context_lines = 15
|
|
245
244
|
|
|
@@ -258,21 +257,23 @@ Tool IDs match the keys in `config/config.yaml`: `compile`, `ruff`, `ty`, `bandi
|
|
|
258
257
|
python:
|
|
259
258
|
|
|
260
259
|
compile:
|
|
261
|
-
command: "{python} -m compileall -r 10 -j 8 {context_path} -x .*venv"
|
|
260
|
+
command: "{python} -m compileall -r 10 -j 8 \"{context_path}\" -x .*venv"
|
|
262
261
|
parser: "CompileParser"
|
|
263
262
|
order: 1
|
|
264
263
|
warning_threshold: 0.9999
|
|
265
264
|
error_threshold: 0.9999
|
|
266
265
|
|
|
267
266
|
ruff:
|
|
268
|
-
command: "{python} -m ruff check --output-format concise --no-cache {context_path}"
|
|
267
|
+
command: "{python} -m ruff check --output-format concise --no-cache \"{context_path}\"{exclude}"
|
|
268
|
+
exclude_format: " --exclude {path}"
|
|
269
269
|
parser: "RuffParser"
|
|
270
270
|
order: 2
|
|
271
271
|
warning_threshold: 0.9999
|
|
272
272
|
error_threshold: 0.9
|
|
273
273
|
|
|
274
274
|
ty:
|
|
275
|
-
command: "{python} -m ty check --output-format concise --color never {context_path}"
|
|
275
|
+
command: "{python} -m ty check --output-format concise --color never \"{context_path}\"{exclude}"
|
|
276
|
+
exclude_format: " --exclude {path}"
|
|
276
277
|
parser: "TyParser"
|
|
277
278
|
order: 3
|
|
278
279
|
warning_threshold: 0.9999
|
|
@@ -282,22 +283,26 @@ python:
|
|
|
282
283
|
- ty
|
|
283
284
|
|
|
284
285
|
bandit:
|
|
285
|
-
command: "{python} -m bandit -r {context_path} -f json -q -s B101 --severity-level medium --exclude {input_path_posix}/.venv,{input_path_posix}/tests"
|
|
286
|
+
command: "{python} -m bandit -r \"{context_path}\" -f json -q -s B101 --severity-level medium --exclude \"{input_path_posix}/.venv,{input_path_posix}/tests{exclude}\""
|
|
287
|
+
exclude_format: ",{input_path_posix}/{path}"
|
|
286
288
|
parser: "BanditParser"
|
|
287
289
|
order: 4
|
|
288
290
|
warning_threshold: 0.9999
|
|
289
291
|
error_threshold: 0.8
|
|
290
292
|
|
|
291
293
|
pytest:
|
|
292
|
-
command: "{python} -m pytest -v {context_path}"
|
|
294
|
+
command: "{python} -m pytest -v \"{context_path}\"{exclude}"
|
|
295
|
+
exclude_format: " --ignore {path}"
|
|
293
296
|
parser: "PytestParser"
|
|
294
297
|
order: 5
|
|
295
298
|
warning_threshold: 1.0
|
|
296
299
|
error_threshold: 1.0
|
|
297
300
|
run_in_target_env: true
|
|
301
|
+
extra_deps:
|
|
302
|
+
- pytest
|
|
298
303
|
|
|
299
304
|
coverage:
|
|
300
|
-
command: "{python} -m coverage run --omit=*/tests/*,*/test_*.py -m pytest {context_path} && {python} -m coverage report --omit=*/tests/*,*/test_*.py"
|
|
305
|
+
command: "{python} -m coverage run --omit=*/tests/*,*/test_*.py -m pytest \"{context_path}\" && {python} -m coverage report --omit=*/tests/*,*/test_*.py"
|
|
301
306
|
parser: "CoverageParser"
|
|
302
307
|
order: 6
|
|
303
308
|
warning_threshold: 0.9
|
|
@@ -308,40 +313,41 @@ python:
|
|
|
308
313
|
- pytest
|
|
309
314
|
|
|
310
315
|
radon-cc:
|
|
311
|
-
command: "{python} -m radon cc --json {context_path}"
|
|
316
|
+
command: "{python} -m radon cc --json \"{context_path}\""
|
|
312
317
|
parser: "ComplexityParser"
|
|
313
318
|
order: 7
|
|
314
319
|
warning_threshold: 0.6
|
|
315
320
|
error_threshold: 0.4
|
|
316
321
|
|
|
317
322
|
radon-mi:
|
|
318
|
-
command: "{python} -m radon mi -s --json {context_path}"
|
|
323
|
+
command: "{python} -m radon mi -s --json \"{context_path}\""
|
|
319
324
|
parser: "MaintainabilityParser"
|
|
320
325
|
order: 8
|
|
321
326
|
warning_threshold: 0.6
|
|
322
327
|
error_threshold: 0.4
|
|
323
328
|
|
|
324
329
|
radon-hal:
|
|
325
|
-
command: "{python} -m radon hal -f --json {context_path}"
|
|
330
|
+
command: "{python} -m radon hal -f --json \"{context_path}\""
|
|
326
331
|
parser: "HalsteadParser"
|
|
327
332
|
order: 9
|
|
328
333
|
warning_threshold: 0.5
|
|
329
334
|
error_threshold: 0.3
|
|
330
335
|
|
|
331
336
|
vulture:
|
|
332
|
-
command: "{python} -m vulture {context_path} --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git"
|
|
337
|
+
command: "{python} -m vulture \"{context_path}\" --min-confidence 80 --exclude .venv,dist,.*_cache,docs,.git{exclude}"
|
|
338
|
+
exclude_format: ",{path}"
|
|
333
339
|
parser: "VultureParser"
|
|
334
340
|
order: 10
|
|
335
341
|
warning_threshold: 0.9999
|
|
336
342
|
error_threshold: 0.8
|
|
337
343
|
|
|
338
344
|
interrogate:
|
|
339
|
-
command: "{python} -m interrogate {context_path} -v --fail-under 0"
|
|
345
|
+
command: "{python} -m interrogate \"{context_path}\" -e tests{exclude} -v --fail-under 0"
|
|
346
|
+
exclude_format: " -e {path}"
|
|
340
347
|
parser: "InterrogateParser"
|
|
341
348
|
order: 11
|
|
342
349
|
warning_threshold: 0.8
|
|
343
350
|
error_threshold: 0.3
|
|
344
|
-
|
|
345
351
|
```
|
|
346
352
|
|
|
347
353
|
## Respect
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
py_cq/__init__.py,sha256=
|
|
2
|
-
py_cq/cli.py,sha256=
|
|
1
|
+
py_cq/__init__.py,sha256=U2ysDtSFdv2mlXZz4w1Q42pfgfi6YY_3Ln24bkZq14I,260
|
|
2
|
+
py_cq/cli.py,sha256=RRQVPVOwG-EMYndMUhBfqBqm1S1kcaObhKOdfxrrYl0,11963
|
|
3
3
|
py_cq/config/__init__.py,sha256=f0wc51O_3kGDTZUnCbGv8_zWnC5yYGl4NWcf2buSImQ,670
|
|
4
|
-
py_cq/config/config.yaml,sha256=
|
|
4
|
+
py_cq/config/config.yaml,sha256=TPZJogpWbyf0Ml2mHrHzTNyTik3k07KPVGsA1wT9GEc,2696
|
|
5
5
|
py_cq/context_hash.py,sha256=h-i7Rhd7AUfLv9SkQvE79bjJvTsm_ZwoVwSmUKXWmfM,2977
|
|
6
|
-
py_cq/execution_engine.py,sha256=
|
|
6
|
+
py_cq/execution_engine.py,sha256=nAsCvldUfDagZnfOwXf4A37VQLxCGiv12T8ymutflC4,8697
|
|
7
7
|
py_cq/language_detector.py,sha256=6av5HaimcZ54RkN69xQmGgC0mxtTvGzPV3SL8NGG8Uc,1116
|
|
8
8
|
py_cq/llm_formatter.py,sha256=l74O5iqNWMR16789Xncoi93xOqgQJhW5IQK9_OyA9mE,1632
|
|
9
|
-
py_cq/localtypes.py,sha256=
|
|
9
|
+
py_cq/localtypes.py,sha256=UGI2kl1xB2TedKGByth3URiqJKY56YZMNds1hnLEzvU,6228
|
|
10
10
|
py_cq/main.py,sha256=VKoXI8R8rB2fEROBYoTVURfinLqyh8XTNIIWAOtH7dw,380
|
|
11
11
|
py_cq/metric_aggregator.py,sha256=M2ymo62S7p7qPUqjjoiPg4IVyXQhLMuTr9-jxLiFjCY,853
|
|
12
|
-
py_cq/parsers/__init__.py,sha256=
|
|
12
|
+
py_cq/parsers/__init__.py,sha256=YS3wPS0cMNU80zkdSZBEZOkqDKE6Jk--0Xd_bX7VMcA,27
|
|
13
13
|
py_cq/parsers/banditparser.py,sha256=Ju_CkuXtkVn1Th9aQ6mv6fTUTpb9pc1YD8Nzt_nMgFQ,2326
|
|
14
14
|
py_cq/parsers/common.py,sha256=thbziNjqaf-SY3Y0W-KmPwzlcC-YCV98Z8jubUJM7_4,5203
|
|
15
15
|
py_cq/parsers/compileparser.py,sha256=YsT7ePUDRjsUHTLqgRv4x6jJBCTt6cbm1mgxplzxETg,6256
|
|
@@ -17,7 +17,7 @@ py_cq/parsers/complexityparser.py,sha256=2t1-wmNjUu65fULcIm5jcgv7ZLWwjakyiY_r-Fx
|
|
|
17
17
|
py_cq/parsers/coverageparser.py,sha256=n4h_RCxKvJoYgp356PA4laAmFcngjQ41b_GXZvKkVgc,4041
|
|
18
18
|
py_cq/parsers/exitcodeparser.py,sha256=ZFL3EbPhGvFjm2qZhfLD1_5dNjR9ULYNQpKgy0Z_dGo,729
|
|
19
19
|
py_cq/parsers/halsteadparser.py,sha256=ZCN7LP1iUZ91tf3tlspKAPQrTEa78XVdE9Fjn9yPvYk,9008
|
|
20
|
-
py_cq/parsers/interrogateparser.py,sha256=
|
|
20
|
+
py_cq/parsers/interrogateparser.py,sha256=gk9pJ7yFXMzLjk6PP0X8fxW_gAE2DTIoWMsPqF2xIXs,2260
|
|
21
21
|
py_cq/parsers/linecountparser.py,sha256=nxWvFntuR8T6FDGpafrlevvt-jR3rwkbVo_t2JX4TF0,1067
|
|
22
22
|
py_cq/parsers/maintainabilityparser.py,sha256=Ax0ZFA6zzqYIWZH1hP1_GUtdVn2LIJ8SKWtqVNdszYs,3411
|
|
23
23
|
py_cq/parsers/pytestparser.py,sha256=3N1X4wKhJ2h-2U1GuM3gHWHpHxU9f0LPGcPaojra9W4,6377
|
|
@@ -26,8 +26,8 @@ py_cq/parsers/ruffparser.py,sha256=ZdIya4sct2PrsOyfKfMGmXHLh3Qu7HtFqXNY9IuNFog,2
|
|
|
26
26
|
py_cq/parsers/typarser.py,sha256=zrI0KS65MUGPxYPP74B6BRyTbjcPhKyQPjH2KZIyxN0,2495
|
|
27
27
|
py_cq/parsers/vultureparser.py,sha256=U6zC7P0ATA_N4SB90BahKF5QHMITf_z-NsOgrh_Q5rA,1995
|
|
28
28
|
py_cq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
-
py_cq/tool_registry.py,sha256=
|
|
30
|
-
python_code_quality-0.1.
|
|
31
|
-
python_code_quality-0.1.
|
|
32
|
-
python_code_quality-0.1.
|
|
33
|
-
python_code_quality-0.1.
|
|
29
|
+
py_cq/tool_registry.py,sha256=UfmwJH8rtmTY9kX02QaE4OJIWyboTMcXUavgb9R4fxc,1648
|
|
30
|
+
python_code_quality-0.1.14.dist-info/WHEEL,sha256=M4DeIjVCA49okfALADZoWX5JOGwnmHb-JOpQHtI-1c0,80
|
|
31
|
+
python_code_quality-0.1.14.dist-info/entry_points.txt,sha256=cfWbTw7eYO6Trv1-Z_odL6Zta9CqYU6Vk9lAHdfB60Q,40
|
|
32
|
+
python_code_quality-0.1.14.dist-info/METADATA,sha256=HR_8B9uca6SBAn7f74rMAnTOJ6LzODc5AF0w0Uiic28,12496
|
|
33
|
+
python_code_quality-0.1.14.dist-info/RECORD,,
|
{python_code_quality-0.1.11.dist-info → python_code_quality-0.1.14.dist-info}/entry_points.txt
RENAMED
|
File without changes
|