python-code-quality 0.1.14__py3-none-any.whl → 0.1.15__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/cli.py +31 -2
- py_cq/parsers/common.py +106 -2
- py_cq/parsers/compileparser.py +8 -1
- py_cq/parsers/pytestparser.py +91 -4
- py_cq/parsers/typarser.py +19 -1
- {python_code_quality-0.1.14.dist-info → python_code_quality-0.1.15.dist-info}/METADATA +6 -2
- {python_code_quality-0.1.14.dist-info → python_code_quality-0.1.15.dist-info}/RECORD +9 -9
- {python_code_quality-0.1.14.dist-info → python_code_quality-0.1.15.dist-info}/WHEEL +0 -0
- {python_code_quality-0.1.14.dist-info → python_code_quality-0.1.15.dist-info}/entry_points.txt +0 -0
py_cq/cli.py
CHANGED
|
@@ -10,13 +10,14 @@ analysis.
|
|
|
10
10
|
Helper functions such as `format_as_table` convert the aggregated tool
|
|
11
11
|
results into a Rich Table for convenient console display.
|
|
12
12
|
"""
|
|
13
|
-
|
|
14
13
|
import copy
|
|
14
|
+
import io
|
|
15
15
|
import json
|
|
16
16
|
import logging
|
|
17
17
|
import tomllib
|
|
18
18
|
from enum import Enum
|
|
19
19
|
from importlib import import_module
|
|
20
|
+
from importlib.metadata import requires, version
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
|
|
22
23
|
import typer
|
|
@@ -100,8 +101,36 @@ class OutputMode(str, Enum):
|
|
|
100
101
|
RAW = "raw"
|
|
101
102
|
|
|
102
103
|
|
|
104
|
+
def _version_callback(value: bool) -> None:
|
|
105
|
+
if not value:
|
|
106
|
+
return
|
|
107
|
+
import re
|
|
108
|
+
import sys
|
|
109
|
+
if isinstance(sys.stdout, io.TextIOWrapper):
|
|
110
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
111
|
+
pkg = "python-code-quality"
|
|
112
|
+
pkg_version = version(pkg)
|
|
113
|
+
dep_versions: list[tuple[str, str]] = []
|
|
114
|
+
for req in (requires(pkg) or []):
|
|
115
|
+
if "; extra ==" in req:
|
|
116
|
+
continue
|
|
117
|
+
dep_name = re.split(r"[>=<!;\s\[]", req)[0]
|
|
118
|
+
try:
|
|
119
|
+
dep_versions.append((dep_name, version(dep_name)))
|
|
120
|
+
except Exception:
|
|
121
|
+
pass
|
|
122
|
+
typer.echo(f"{pkg} v{pkg_version}")
|
|
123
|
+
for dep_name, dep_ver in sorted(dep_versions):
|
|
124
|
+
typer.echo(f"\u251c\u2500\u2500 {dep_name} v{dep_ver}")
|
|
125
|
+
raise typer.Exit()
|
|
126
|
+
|
|
127
|
+
|
|
103
128
|
@app.callback()
|
|
104
|
-
def callback(
|
|
129
|
+
def callback(
|
|
130
|
+
_: bool = typer.Option(
|
|
131
|
+
False, "--version", "-V", callback=_version_callback, is_eager=True, help="Show version and dependencies"
|
|
132
|
+
),
|
|
133
|
+
) -> None:
|
|
105
134
|
"""Feed the results from 11+ code quality tools to an LLM. Try: cq check . -o llm"""
|
|
106
135
|
console = Console()
|
|
107
136
|
|
py_cq/parsers/common.py
CHANGED
|
@@ -12,6 +12,7 @@ performance metrics or error scores:
|
|
|
12
12
|
Both functions return a float and can be used directly in downstream analytics,
|
|
13
13
|
visualisation or decision-making pipelines."""
|
|
14
14
|
|
|
15
|
+
from pathlib import Path
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def read_source_lines(file_path: str, line: int, count: int = 5) -> str:
|
|
@@ -26,17 +27,118 @@ def read_source_lines(file_path: str, line: int, count: int = 5) -> str:
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
def format_source_context(file: str, line: int | str, context: int = 3, count: int = 8) -> str:
|
|
29
|
-
"""Return a fenced python code block for the source around `line`, or '' if unavailable.
|
|
30
|
+
"""Return a fenced python code block for the source around `line`, or '' if unavailable.
|
|
31
|
+
|
|
32
|
+
Stops before spilling into the next top-level ``def`` or ``class`` definition.
|
|
33
|
+
"""
|
|
30
34
|
if not isinstance(line, int):
|
|
31
35
|
return ""
|
|
32
36
|
context_start = max(1, line - context)
|
|
33
37
|
raw_lines = read_source_lines(file, context_start, count=count).splitlines()
|
|
34
38
|
if not raw_lines:
|
|
35
39
|
return ""
|
|
36
|
-
|
|
40
|
+
error_offset = line - context_start # 0-based index of the error line in raw_lines
|
|
41
|
+
collected = []
|
|
42
|
+
for i, rline in enumerate(raw_lines):
|
|
43
|
+
if i > error_offset and (
|
|
44
|
+
rline.startswith("def ")
|
|
45
|
+
or rline.startswith("async def ")
|
|
46
|
+
or rline.startswith("class ")
|
|
47
|
+
):
|
|
48
|
+
break
|
|
49
|
+
collected.append(f"{context_start + i}: {rline}")
|
|
50
|
+
src = "\n".join(collected)
|
|
37
51
|
return f"\n```python\n{src}\n```"
|
|
38
52
|
|
|
39
53
|
|
|
54
|
+
_PYTHON_KEYWORDS = frozenset([
|
|
55
|
+
"if", "elif", "else", "for", "while", "with", "assert", "return",
|
|
56
|
+
"raise", "import", "from", "class", "def", "lambda", "yield",
|
|
57
|
+
"del", "pass", "break", "continue", "not", "and", "or", "in", "is",
|
|
58
|
+
"print", "super", "type", "len", "range",
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def extract_callee_name(source_line: str) -> str | None:
|
|
63
|
+
"""Extract the primary callee function name from a source line, or None.
|
|
64
|
+
|
|
65
|
+
Prefers the RHS of an assignment so that ``result = func(...)`` returns
|
|
66
|
+
``func`` rather than the variable on the left. Python keywords and
|
|
67
|
+
built-ins listed in ``_PYTHON_KEYWORDS`` are excluded.
|
|
68
|
+
"""
|
|
69
|
+
import re
|
|
70
|
+
stripped = source_line.strip()
|
|
71
|
+
rhs = stripped
|
|
72
|
+
if "=" in stripped and not stripped.startswith(("assert", "return")):
|
|
73
|
+
rhs = stripped.split("=", 1)[1].strip()
|
|
74
|
+
m = re.search(r"\b([a-zA-Z_]\w*)\s*\(", rhs)
|
|
75
|
+
if m and m.group(1) not in _PYTHON_KEYWORDS:
|
|
76
|
+
return m.group(1)
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _find_project_root(hint_file: str) -> Path:
|
|
81
|
+
from pathlib import Path
|
|
82
|
+
root = Path(hint_file).resolve().parent
|
|
83
|
+
current = root
|
|
84
|
+
for _ in range(8):
|
|
85
|
+
if (current / "pyproject.toml").exists() or (current / "setup.py").exists():
|
|
86
|
+
return current
|
|
87
|
+
parent = current.parent
|
|
88
|
+
if parent == current:
|
|
89
|
+
break
|
|
90
|
+
current = parent
|
|
91
|
+
return root
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def find_in_project(func_name: str, hint_file: str, max_lines: int = 10) -> tuple[str, str]:
|
|
95
|
+
"""Find func_name definition in project files; same file first, then project-wide.
|
|
96
|
+
|
|
97
|
+
Returns ``(file_path, code_block)`` for the first match, or ``("", "")`` if not found.
|
|
98
|
+
"""
|
|
99
|
+
from pathlib import Path
|
|
100
|
+
result = find_function_source(hint_file, func_name, max_lines=max_lines)
|
|
101
|
+
if result:
|
|
102
|
+
return hint_file, result
|
|
103
|
+
root = _find_project_root(hint_file)
|
|
104
|
+
for py_file in sorted(root.rglob("*.py")):
|
|
105
|
+
if py_file.resolve() == Path(hint_file).resolve():
|
|
106
|
+
continue
|
|
107
|
+
r = find_function_source(str(py_file), func_name, max_lines=max_lines)
|
|
108
|
+
if r:
|
|
109
|
+
return str(py_file), r
|
|
110
|
+
return "", ""
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _relative_path(path: str) -> str:
|
|
114
|
+
"""Return path relative to cwd, normalised to forward slashes."""
|
|
115
|
+
from pathlib import Path
|
|
116
|
+
try:
|
|
117
|
+
return str(Path(path).relative_to(Path.cwd())).replace("\\", "/")
|
|
118
|
+
except ValueError:
|
|
119
|
+
return path.replace("\\", "/")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def format_callee_context(func_name: str, hint_file: str, max_lines: int = 10) -> str:
|
|
123
|
+
"""Return a labelled callee definition block, or '' if not found in project.
|
|
124
|
+
|
|
125
|
+
Output format::
|
|
126
|
+
|
|
127
|
+
Callee `func_name` — `relative/path/to/file.py`
|
|
128
|
+
```python
|
|
129
|
+
N: def func_name(...):
|
|
130
|
+
...
|
|
131
|
+
```
|
|
132
|
+
"""
|
|
133
|
+
import re
|
|
134
|
+
callee_file, code_block = find_in_project(func_name, hint_file, max_lines=max_lines)
|
|
135
|
+
if not code_block:
|
|
136
|
+
return ""
|
|
137
|
+
m = re.search(r"```python\n(\d+):", code_block)
|
|
138
|
+
line_ref = f":{m.group(1)}" if m else ""
|
|
139
|
+
return f"\n`{func_name}` is defined at: `{_relative_path(callee_file)}{line_ref}`{code_block}"
|
|
140
|
+
|
|
141
|
+
|
|
40
142
|
def find_function_source(file: str, func_name: str, max_lines: int = 15) -> str:
|
|
41
143
|
"""Return a fenced python block for the body of func_name, or '' if unavailable."""
|
|
42
144
|
from pathlib import Path
|
|
@@ -64,6 +166,8 @@ def find_function_source(file: str, func_name: str, max_lines: int = 15) -> str:
|
|
|
64
166
|
collected.append(line)
|
|
65
167
|
if len(collected) >= max_lines:
|
|
66
168
|
break
|
|
169
|
+
while collected and not collected[-1].strip():
|
|
170
|
+
collected.pop()
|
|
67
171
|
numbered = "\n".join(f"{start_idx + 1 + i}: {ln}" for i, ln in enumerate(collected))
|
|
68
172
|
return f"\n```python\n{numbered}\n```"
|
|
69
173
|
|
py_cq/parsers/compileparser.py
CHANGED
|
@@ -125,4 +125,11 @@ class CompileParser(AbstractParser):
|
|
|
125
125
|
typ = info.get("type", "Error")
|
|
126
126
|
help_msg = info.get("help", "")
|
|
127
127
|
code_block = format_source_context(file, line, count=context_lines) or (f"\n```python\n{info['src']}\n```" if info.get("src") else "")
|
|
128
|
-
|
|
128
|
+
callee = ""
|
|
129
|
+
src_line = info.get("src", "")
|
|
130
|
+
if src_line:
|
|
131
|
+
from py_cq.parsers.common import extract_callee_name, format_callee_context
|
|
132
|
+
func_name = extract_callee_name(src_line)
|
|
133
|
+
if func_name:
|
|
134
|
+
callee = format_callee_context(func_name, file)
|
|
135
|
+
return f"`{file}:{line}` — **{typ}**: {help_msg}{code_block}{callee}"
|
py_cq/parsers/pytestparser.py
CHANGED
|
@@ -13,6 +13,58 @@ import re as _re
|
|
|
13
13
|
from py_cq.localtypes import AbstractParser, RawResult, ToolResult
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def _last_call_line_for_test(stdout: str, test_name: str) -> str:
|
|
17
|
+
"""Return the last source line before E-lines in a test's failure section.
|
|
18
|
+
|
|
19
|
+
Captures both indented context lines and pytest's ``>``-prefixed
|
|
20
|
+
current-executing-line marker.
|
|
21
|
+
"""
|
|
22
|
+
lines = stdout.splitlines()
|
|
23
|
+
pattern = _re.compile(rf"_{{4,}}\s+{_re.escape(test_name)}\s+_{{4,}}")
|
|
24
|
+
in_section = False
|
|
25
|
+
last_src = ""
|
|
26
|
+
for line in lines:
|
|
27
|
+
if not in_section:
|
|
28
|
+
if pattern.search(line):
|
|
29
|
+
in_section = True
|
|
30
|
+
else:
|
|
31
|
+
stripped = line.strip()
|
|
32
|
+
if stripped.startswith(("_", "=")):
|
|
33
|
+
break
|
|
34
|
+
if stripped.startswith("E ") or stripped == "E":
|
|
35
|
+
break
|
|
36
|
+
if line.startswith((" ", "\t", ">")):
|
|
37
|
+
src = line.lstrip("> \t")
|
|
38
|
+
if src:
|
|
39
|
+
last_src = src
|
|
40
|
+
return last_src
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
_COLLECTION_FILE_RE = _re.compile(r'E\s+File "([^"]+)", line (\d+)')
|
|
44
|
+
_COLLECTION_ERROR_RE = _re.compile(r"E\s+(\w+(?:Error|Warning|Exception)):\s*(.*)")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _extract_collection_error(stdout: str) -> dict | None:
|
|
48
|
+
"""Return {file, line, type, help} if pytest stdout contains a collection error."""
|
|
49
|
+
file_match = None
|
|
50
|
+
error_match = None
|
|
51
|
+
for line in stdout.splitlines():
|
|
52
|
+
m = _COLLECTION_FILE_RE.search(line)
|
|
53
|
+
if m:
|
|
54
|
+
file_match = m
|
|
55
|
+
m = _COLLECTION_ERROR_RE.search(line)
|
|
56
|
+
if m:
|
|
57
|
+
error_match = m
|
|
58
|
+
if file_match and error_match:
|
|
59
|
+
return {
|
|
60
|
+
"file": file_match.group(1).replace("\\", "/"),
|
|
61
|
+
"line": int(file_match.group(2)),
|
|
62
|
+
"type": error_match.group(1),
|
|
63
|
+
"help": error_match.group(2).strip(),
|
|
64
|
+
}
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
|
|
16
68
|
def _extract_failure(stdout: str, test_name: str, max_lines: int) -> str:
|
|
17
69
|
"""Extract the failure section for test_name from pytest stdout."""
|
|
18
70
|
lines = stdout.splitlines()
|
|
@@ -102,8 +154,12 @@ class PytestParser(AbstractParser):
|
|
|
102
154
|
return tr
|
|
103
155
|
|
|
104
156
|
def format_llm_message(self, tr: ToolResult, *, context_lines: int = 15) -> str:
|
|
105
|
-
"""Return the first failing test with function body and
|
|
106
|
-
from py_cq.parsers.common import
|
|
157
|
+
"""Return the first failing test with function body, failure output, and callee signature."""
|
|
158
|
+
from py_cq.parsers.common import (
|
|
159
|
+
extract_callee_name,
|
|
160
|
+
find_function_source,
|
|
161
|
+
format_callee_context,
|
|
162
|
+
)
|
|
107
163
|
for file, tests in tr.details.items():
|
|
108
164
|
if not isinstance(tests, dict):
|
|
109
165
|
continue
|
|
@@ -111,13 +167,22 @@ class PytestParser(AbstractParser):
|
|
|
111
167
|
if status != "FAILED":
|
|
112
168
|
continue
|
|
113
169
|
header = f"`{file}::{test_name}` — test **FAILED**"
|
|
114
|
-
|
|
170
|
+
bare_name = test_name.split("[")[0]
|
|
171
|
+
body = find_function_source(file, bare_name, max_lines=context_lines)
|
|
115
172
|
failure = _extract_failure(tr.raw.stdout, test_name, max_lines=context_lines)
|
|
173
|
+
callee = ""
|
|
174
|
+
call_line = _last_call_line_for_test(tr.raw.stdout, test_name)
|
|
175
|
+
if call_line:
|
|
176
|
+
func_name = extract_callee_name(call_line)
|
|
177
|
+
if func_name and func_name != bare_name:
|
|
178
|
+
callee = format_callee_context(func_name, file)
|
|
116
179
|
parts = [header]
|
|
117
180
|
if body:
|
|
118
181
|
parts.append(body)
|
|
119
182
|
if failure:
|
|
120
183
|
parts.append(failure)
|
|
184
|
+
if callee:
|
|
185
|
+
parts.append(callee)
|
|
121
186
|
return "\n".join(parts)
|
|
122
187
|
if "no tests ran" in tr.raw.stdout:
|
|
123
188
|
return (
|
|
@@ -125,7 +190,29 @@ class PytestParser(AbstractParser):
|
|
|
125
190
|
"Add a `tests/` directory with at least one test file (e.g. `tests/test_basic.py`) "
|
|
126
191
|
"and write a first test covering a core function."
|
|
127
192
|
)
|
|
128
|
-
|
|
193
|
+
from py_cq.parsers.common import (
|
|
194
|
+
extract_callee_name,
|
|
195
|
+
format_callee_context,
|
|
196
|
+
format_source_context,
|
|
197
|
+
)
|
|
198
|
+
combined = tr.raw.stdout + tr.raw.stderr
|
|
199
|
+
err = _extract_collection_error(combined)
|
|
200
|
+
if err:
|
|
201
|
+
file, line, typ, help_msg = err["file"], err["line"], err["type"], err["help"]
|
|
202
|
+
code_block = format_source_context(file, line, count=context_lines) or ""
|
|
203
|
+
callee = ""
|
|
204
|
+
# try to find callee from the offending source line via format_source_context result
|
|
205
|
+
src_line = ""
|
|
206
|
+
for ln in (tr.raw.stdout + tr.raw.stderr).splitlines():
|
|
207
|
+
m = _re.match(r"E\s{6,}(\S.*)", ln)
|
|
208
|
+
if m:
|
|
209
|
+
src_line = m.group(1)
|
|
210
|
+
if src_line:
|
|
211
|
+
func_name = extract_callee_name(src_line)
|
|
212
|
+
if func_name:
|
|
213
|
+
callee = format_callee_context(func_name, file)
|
|
214
|
+
return f"`{file}:{line}` — **{typ}**: {help_msg}{code_block}{callee}"
|
|
215
|
+
output = combined.strip()
|
|
129
216
|
if output:
|
|
130
217
|
tail = "\n".join(output.splitlines()[-30:])
|
|
131
218
|
return f"pytest reported failures:\n\n```\n{tail}\n```"
|
py_cq/parsers/typarser.py
CHANGED
|
@@ -18,6 +18,16 @@ from py_cq.parsers.common import format_source_context, score_logistic_variant
|
|
|
18
18
|
|
|
19
19
|
_DIAG_RE = re.compile(r"^(.+):(\d+):\d+:\s+(error|warning)\[([^\]]+)\] (.+)$")
|
|
20
20
|
|
|
21
|
+
_CALL_CODES = frozenset([
|
|
22
|
+
"call-non-callable",
|
|
23
|
+
"missing-argument",
|
|
24
|
+
"unexpected-keyword",
|
|
25
|
+
"argument-type",
|
|
26
|
+
"too-many-positional-arguments",
|
|
27
|
+
"invalid-argument-type",
|
|
28
|
+
"no-matching-overload",
|
|
29
|
+
])
|
|
30
|
+
|
|
21
31
|
|
|
22
32
|
class TyParser(AbstractParser):
|
|
23
33
|
"""Parses raw output from ``ty check`` into a structured ToolResult."""
|
|
@@ -58,4 +68,12 @@ class TyParser(AbstractParser):
|
|
|
58
68
|
line = issue.get("line", "?")
|
|
59
69
|
code = issue.get("code", "")
|
|
60
70
|
message = issue.get("message", "")
|
|
61
|
-
|
|
71
|
+
src_ctx = format_source_context(file, line, count=context_lines)
|
|
72
|
+
callee = ""
|
|
73
|
+
if code in _CALL_CODES and isinstance(line, int):
|
|
74
|
+
from py_cq.parsers.common import extract_callee_name, format_callee_context, read_source_lines
|
|
75
|
+
src_line = read_source_lines(file, line, count=1)
|
|
76
|
+
func_name = extract_callee_name(src_line)
|
|
77
|
+
if func_name:
|
|
78
|
+
callee = format_callee_context(func_name, file)
|
|
79
|
+
return f"`{file}:{line}` — **{code}**: {message}{src_ctx}{callee}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-code-quality
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.15
|
|
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>
|
|
@@ -37,6 +37,10 @@ Description-Content-Type: text/markdown
|
|
|
37
37
|
|
|
38
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.
|
|
39
39
|
|
|
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
|
+
|
|
42
|
+
Note: It never edits your files. This is a job for you or an LLM. You may wish to run `ruff check --fix` and `ruff format` first.
|
|
43
|
+
|
|
40
44
|
```bash
|
|
41
45
|
cq check . -o llm # top defect as markdown, pipe to an LLM
|
|
42
46
|
cq check . # table overview of all scores
|
|
@@ -175,7 +179,7 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
|
|
|
175
179
|
```bash
|
|
176
180
|
> cq check . -o score
|
|
177
181
|
```
|
|
178
|
-
```
|
|
182
|
+
```
|
|
179
183
|
0.9662730667181059 # this is designed to approach but not reach 1.0
|
|
180
184
|
```
|
|
181
185
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
py_cq/__init__.py,sha256=U2ysDtSFdv2mlXZz4w1Q42pfgfi6YY_3Ln24bkZq14I,260
|
|
2
|
-
py_cq/cli.py,sha256=
|
|
2
|
+
py_cq/cli.py,sha256=HWTMtA9Gfn3YeO7B94kter6HNNSzPjyX1HLJQ1eNBvU,12936
|
|
3
3
|
py_cq/config/__init__.py,sha256=f0wc51O_3kGDTZUnCbGv8_zWnC5yYGl4NWcf2buSImQ,670
|
|
4
4
|
py_cq/config/config.yaml,sha256=TPZJogpWbyf0Ml2mHrHzTNyTik3k07KPVGsA1wT9GEc,2696
|
|
5
5
|
py_cq/context_hash.py,sha256=h-i7Rhd7AUfLv9SkQvE79bjJvTsm_ZwoVwSmUKXWmfM,2977
|
|
@@ -11,8 +11,8 @@ py_cq/main.py,sha256=VKoXI8R8rB2fEROBYoTVURfinLqyh8XTNIIWAOtH7dw,380
|
|
|
11
11
|
py_cq/metric_aggregator.py,sha256=M2ymo62S7p7qPUqjjoiPg4IVyXQhLMuTr9-jxLiFjCY,853
|
|
12
12
|
py_cq/parsers/__init__.py,sha256=YS3wPS0cMNU80zkdSZBEZOkqDKE6Jk--0Xd_bX7VMcA,27
|
|
13
13
|
py_cq/parsers/banditparser.py,sha256=Ju_CkuXtkVn1Th9aQ6mv6fTUTpb9pc1YD8Nzt_nMgFQ,2326
|
|
14
|
-
py_cq/parsers/common.py,sha256=
|
|
15
|
-
py_cq/parsers/compileparser.py,sha256=
|
|
14
|
+
py_cq/parsers/common.py,sha256=h3-eLyi0YNkk-2ZiNUKxZhIFZNHUf01kyAqCtFbxNIY,8803
|
|
15
|
+
py_cq/parsers/compileparser.py,sha256=EBoqZyPDkkfc9FssGkKrIATU6TDHSSB7xWeqrnOiMEc,6576
|
|
16
16
|
py_cq/parsers/complexityparser.py,sha256=2t1-wmNjUu65fULcIm5jcgv7ZLWwjakyiY_r-Fx1QQg,3983
|
|
17
17
|
py_cq/parsers/coverageparser.py,sha256=n4h_RCxKvJoYgp356PA4laAmFcngjQ41b_GXZvKkVgc,4041
|
|
18
18
|
py_cq/parsers/exitcodeparser.py,sha256=ZFL3EbPhGvFjm2qZhfLD1_5dNjR9ULYNQpKgy0Z_dGo,729
|
|
@@ -20,14 +20,14 @@ py_cq/parsers/halsteadparser.py,sha256=ZCN7LP1iUZ91tf3tlspKAPQrTEa78XVdE9Fjn9yPv
|
|
|
20
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
|
-
py_cq/parsers/pytestparser.py,sha256=
|
|
23
|
+
py_cq/parsers/pytestparser.py,sha256=_seSfvAD_88A-yDyWYpLuIrLL2Wjp3rbcqG3fNCNEnA,9705
|
|
24
24
|
py_cq/parsers/regexcountparser.py,sha256=KSoNh2spucXU06pxxr2QW0LrPLfJkFMAsmSgjooaFv0,1316
|
|
25
25
|
py_cq/parsers/ruffparser.py,sha256=ZdIya4sct2PrsOyfKfMGmXHLh3Qu7HtFqXNY9IuNFog,2275
|
|
26
|
-
py_cq/parsers/typarser.py,sha256=
|
|
26
|
+
py_cq/parsers/typarser.py,sha256=oJWudNyRZw-r_-gr2nIzDfS7YJGpt5K3otk9E4G5Ldo,3140
|
|
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
29
|
py_cq/tool_registry.py,sha256=UfmwJH8rtmTY9kX02QaE4OJIWyboTMcXUavgb9R4fxc,1648
|
|
30
|
-
python_code_quality-0.1.
|
|
31
|
-
python_code_quality-0.1.
|
|
32
|
-
python_code_quality-0.1.
|
|
33
|
-
python_code_quality-0.1.
|
|
30
|
+
python_code_quality-0.1.15.dist-info/WHEEL,sha256=M4DeIjVCA49okfALADZoWX5JOGwnmHb-JOpQHtI-1c0,80
|
|
31
|
+
python_code_quality-0.1.15.dist-info/entry_points.txt,sha256=cfWbTw7eYO6Trv1-Z_odL6Zta9CqYU6Vk9lAHdfB60Q,40
|
|
32
|
+
python_code_quality-0.1.15.dist-info/METADATA,sha256=bh2Ex3HJZiNMiJ_LaVtOE_MHf497VN3s0xH8ISWHmvs,12749
|
|
33
|
+
python_code_quality-0.1.15.dist-info/RECORD,,
|
|
File without changes
|
{python_code_quality-0.1.14.dist-info → python_code_quality-0.1.15.dist-info}/entry_points.txt
RENAMED
|
File without changes
|