python-code-quality 0.1.10__tar.gz → 0.1.13__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 (32) hide show
  1. python_code_quality-0.1.10/README.md → python_code_quality-0.1.13/PKG-INFO +47 -0
  2. python_code_quality-0.1.10/PKG-INFO → python_code_quality-0.1.13/README.md +18 -26
  3. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/pyproject.toml +6 -1
  4. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/cli.py +14 -2
  5. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/execution_engine.py +15 -1
  6. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/__init__.py +0 -0
  7. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/config/__init__.py +0 -0
  8. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/config/config.yaml +0 -0
  9. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/context_hash.py +0 -0
  10. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/language_detector.py +0 -0
  11. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/llm_formatter.py +0 -0
  12. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/localtypes.py +0 -0
  13. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/main.py +0 -0
  14. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/metric_aggregator.py +0 -0
  15. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/__init__.py +0 -0
  16. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/banditparser.py +0 -0
  17. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/common.py +0 -0
  18. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/compileparser.py +0 -0
  19. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/complexityparser.py +0 -0
  20. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/coverageparser.py +0 -0
  21. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/exitcodeparser.py +0 -0
  22. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/halsteadparser.py +0 -0
  23. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/interrogateparser.py +0 -0
  24. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/linecountparser.py +0 -0
  25. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/maintainabilityparser.py +0 -0
  26. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/pytestparser.py +0 -0
  27. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/regexcountparser.py +0 -0
  28. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/ruffparser.py +0 -0
  29. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/typarser.py +0 -0
  30. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/parsers/vultureparser.py +0 -0
  31. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/py.typed +0 -0
  32. {python_code_quality-0.1.10 → python_code_quality-0.1.13}/src/py_cq/tool_registry.py +0 -0
@@ -1,5 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-code-quality
3
+ Version: 0.1.13
4
+ Summary: Python Code Quality Analysis Tool - feed the results from 11 CQ tools straight into an LLM. Minimal tokens.
5
+ Author: Chris Kilner
6
+ Author-email: Chris Kilner <chris@rhiza.fr>
7
+ License-Expression: MIT
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Requires-Dist: bandit>=1.8.0
12
+ Requires-Dist: coverage>=7.8.2
13
+ Requires-Dist: diskcache>=5.6.3
14
+ Requires-Dist: interrogate>=1.7.0
15
+ Requires-Dist: pytest>=8.4.0
16
+ Requires-Dist: pytest-cov>=6.1.1
17
+ Requires-Dist: pytest-json-report>=1.5.0
18
+ Requires-Dist: pyyaml>=6.0.2
19
+ Requires-Dist: radon>=6.0.1
20
+ Requires-Dist: rich>=14.0.0
21
+ Requires-Dist: ruff>=0.14.1
22
+ Requires-Dist: ty>=0.0.17
23
+ Requires-Dist: typer>=0.16.0
24
+ Requires-Dist: vulture>=2.14
25
+ Requires-Python: >=3.12
26
+ Project-URL: Homepage, https://github.com/rhiza-fr/py-cq
27
+ Project-URL: Repository, https://github.com/rhiza-fr/py-cq
28
+ Description-Content-Type: text/markdown
29
+
1
30
  # CQ - Python Code Quality Analysis Tool
2
31
 
32
+ [![CI](https://img.shields.io/github/actions/workflow/status/rhiza-fr/py-cq/ci.yml?label=CI)](https://github.com/rhiza-fr/py-cq/actions/workflows/ci.yml)
33
+ [![codecov](https://codecov.io/gh/rhiza-fr/py-cq/graph/badge.svg)](https://codecov.io/gh/rhiza-fr/py-cq)
34
+ [![PyPI version](https://img.shields.io/pypi/v/python-code-quality?)](https://pypi.org/project/python-code-quality/)
35
+ [![Python versions](https://img.shields.io/pypi/pyversions/python-code-quality?)](https://pypi.org/project/python-code-quality/)
36
+ [![License](https://img.shields.io/github/license/rhiza-fr/py-cq)](LICENSE)
37
+
3
38
  Feed the results from 11+ code quality tools to an LLM. Minimal tokens.
4
39
 
5
40
  Why? It removes the mental burden of understanding all these tools and parsing their results.
@@ -77,6 +112,8 @@ cq check . -o score # Numeric score only for CI
77
112
  cq check . -o json # Detailed parsed JSON output for jq
78
113
  cq check . -o raw # Raw tool output for debug
79
114
  cq check path/to/file.py # Just one file (skips pytest and coverage)
115
+ cq check . --only ruff,ty # Run only specific tools
116
+ cq check . --skip bandit # Skip specific tools
80
117
  cq check . --workers 1 # Run sequentially if you like things slow
81
118
  cq check . --clear-cache # Clear cached results before running (rarely needed)
82
119
  cq config path/to/project/ # Show effective tool configuration
@@ -196,6 +233,16 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
196
233
  ]
197
234
  ```
198
235
 
236
+ Both `json` and `raw` output pipe cleanly to `jq`:
237
+
238
+ ```bash
239
+ # Get the coverage section
240
+ cq check . -o raw | jq '.[] | select(.tool_name == "coverage")'
241
+
242
+ # Get parsed coverage metrics only
243
+ cq check . -o json | jq '.[] | select(.tool_name == "coverage") | .metrics'
244
+ ```
245
+
199
246
  ## Configuration
200
247
 
201
248
  Add a `[tool.cq]` section to your project's `pyproject.toml`:
@@ -1,31 +1,11 @@
1
- Metadata-Version: 2.4
2
- Name: python-code-quality
3
- Version: 0.1.10
4
- Summary: Python Code Quality Analysis Tool - feed the results from 11 CQ tools straight into an LLM. Minimal tokens.
5
- Author: Chris Kilner
6
- Author-email: Chris Kilner <chris@rhiza.fr>
7
- License-Expression: MIT
8
- Requires-Dist: bandit>=1.8.0
9
- Requires-Dist: coverage>=7.8.2
10
- Requires-Dist: diskcache>=5.6.3
11
- Requires-Dist: interrogate>=1.7.0
12
- Requires-Dist: pytest>=8.4.0
13
- Requires-Dist: pytest-cov>=6.1.1
14
- Requires-Dist: pytest-json-report>=1.5.0
15
- Requires-Dist: pyyaml>=6.0.2
16
- Requires-Dist: radon>=6.0.1
17
- Requires-Dist: rich>=14.0.0
18
- Requires-Dist: ruff>=0.14.1
19
- Requires-Dist: ty>=0.0.17
20
- Requires-Dist: typer>=0.16.0
21
- Requires-Dist: vulture>=2.14
22
- Requires-Python: >=3.12
23
- Project-URL: Homepage, https://github.com/rhiza-fr/py-cq
24
- Project-URL: Repository, https://github.com/rhiza-fr/py-cq
25
- Description-Content-Type: text/markdown
26
-
27
1
  # CQ - Python Code Quality Analysis Tool
28
2
 
3
+ [![CI](https://img.shields.io/github/actions/workflow/status/rhiza-fr/py-cq/ci.yml?label=CI)](https://github.com/rhiza-fr/py-cq/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/gh/rhiza-fr/py-cq/graph/badge.svg)](https://codecov.io/gh/rhiza-fr/py-cq)
5
+ [![PyPI version](https://img.shields.io/pypi/v/python-code-quality?)](https://pypi.org/project/python-code-quality/)
6
+ [![Python versions](https://img.shields.io/pypi/pyversions/python-code-quality?)](https://pypi.org/project/python-code-quality/)
7
+ [![License](https://img.shields.io/github/license/rhiza-fr/py-cq)](LICENSE)
8
+
29
9
  Feed the results from 11+ code quality tools to an LLM. Minimal tokens.
30
10
 
31
11
  Why? It removes the mental burden of understanding all these tools and parsing their results.
@@ -103,6 +83,8 @@ cq check . -o score # Numeric score only for CI
103
83
  cq check . -o json # Detailed parsed JSON output for jq
104
84
  cq check . -o raw # Raw tool output for debug
105
85
  cq check path/to/file.py # Just one file (skips pytest and coverage)
86
+ cq check . --only ruff,ty # Run only specific tools
87
+ cq check . --skip bandit # Skip specific tools
106
88
  cq check . --workers 1 # Run sequentially if you like things slow
107
89
  cq check . --clear-cache # Clear cached results before running (rarely needed)
108
90
  cq config path/to/project/ # Show effective tool configuration
@@ -222,6 +204,16 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
222
204
  ]
223
205
  ```
224
206
 
207
+ Both `json` and `raw` output pipe cleanly to `jq`:
208
+
209
+ ```bash
210
+ # Get the coverage section
211
+ cq check . -o raw | jq '.[] | select(.tool_name == "coverage")'
212
+
213
+ # Get parsed coverage metrics only
214
+ cq check . -o json | jq '.[] | select(.tool_name == "coverage") | .metrics'
215
+ ```
216
+
225
217
  ## Configuration
226
218
 
227
219
  Add a `[tool.cq]` section to your project's `pyproject.toml`:
@@ -1,11 +1,16 @@
1
1
  [project]
2
2
  name = "python-code-quality"
3
- version = "0.1.10"
3
+ version = "0.1.13"
4
4
  description = "Python Code Quality Analysis Tool - feed the results from 11 CQ tools straight into an LLM. Minimal tokens."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
7
7
  license = "MIT"
8
8
  authors = [{name = "Chris Kilner", email = "chris@rhiza.fr"}]
9
+ classifiers = [
10
+ "Programming Language :: Python :: 3.12",
11
+ "Programming Language :: Python :: 3.13",
12
+ "Programming Language :: Python :: 3.14",
13
+ ]
9
14
 
10
15
  dependencies = [
11
16
  "bandit>=1.8.0",
@@ -125,6 +125,12 @@ def check(
125
125
  language: str | None = typer.Option(
126
126
  None, "--language", "-l", help="Override language detection (e.g. python, typescript, rust)"
127
127
  ),
128
+ only: str | None = typer.Option(
129
+ None, "--only", help="Comma-separated tool IDs to run (e.g. ruff,ty,pytest)"
130
+ ),
131
+ skip: str | None = typer.Option(
132
+ None, "--skip", help="Comma-separated tool IDs to skip (e.g. bandit,vulture)"
133
+ ),
128
134
  ):
129
135
  """Feed the results from 11+ code quality tools to an LLM. Try: cq check . -o llm""" # --help
130
136
  path_obj = Path(path)
@@ -153,6 +159,12 @@ def check(
153
159
  user_cfg = load_user_config(path_obj)
154
160
  context_lines: int = int(user_cfg.get("context_lines", 15))
155
161
  effective_registry = _apply_user_config(tool_registry, user_cfg)
162
+ if only:
163
+ keep = set(only.split(","))
164
+ effective_registry = {k: v for k, v in effective_registry.items() if k in keep}
165
+ if skip:
166
+ drop = set(skip.split(","))
167
+ effective_registry = {k: v for k, v in effective_registry.items() if k not in drop}
156
168
  if clear_cache:
157
169
  tool_cache.clear()
158
170
  tool_results = run_tools(effective_registry.values(), path, workers, early_exit=(output == OutputMode.LLM))
@@ -162,9 +174,9 @@ def check(
162
174
  if output == OutputMode.SCORE:
163
175
  console.print(combined_metrics.score)
164
176
  elif output == OutputMode.JSON:
165
- console.print(json.dumps([tr.to_dict() for tr in tool_results], indent=2))
177
+ print(json.dumps([tr.to_dict() for tr in tool_results], indent=2))
166
178
  elif output == OutputMode.RAW:
167
- console.print(json.dumps([tr.raw.to_dict() for tr in tool_results], indent=2))
179
+ print(json.dumps([tr.raw.to_dict() for tr in tool_results], indent=2))
168
180
  elif output == OutputMode.LLM:
169
181
  # log.setLevel("CRITICAL")
170
182
  from py_cq.llm_formatter import format_for_llm
@@ -41,6 +41,18 @@ def _find_project_root(path: Path) -> Path | None:
41
41
  return None
42
42
 
43
43
 
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
+
44
56
  def run_tool(tool_config: ToolConfig, context_path: str) -> RawResult:
45
57
  """Runs a tool defined by its configuration and returns the execution result.
46
58
 
@@ -72,7 +84,9 @@ def run_tool(tool_config: ToolConfig, context_path: str) -> RawResult:
72
84
  project_root = _find_project_root(resolved)
73
85
  abs_dir = str(project_root) if project_root else str(resolved.parent)
74
86
  path = str(resolved)
75
- with_flags = " ".join(f"--with {dep}" for dep in tool_config.extra_deps)
87
+ project_root_path = Path(abs_dir)
88
+ missing_deps = [d for d in tool_config.extra_deps if not _dep_in_venv(d, project_root_path)]
89
+ with_flags = " ".join(f"--with {dep}" for dep in missing_deps)
76
90
  python = f'"{uv}" run --directory "{abs_dir}" {with_flags}'.rstrip()
77
91
  abs_context_path = str(Path(context_path).resolve())
78
92
  input_path_posix = Path(context_path).as_posix().rstrip("/")