python-code-quality 0.3.0__py3-none-any.whl → 0.3.1__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/api.py CHANGED
@@ -148,7 +148,9 @@ class CQ:
148
148
  if clear_cache:
149
149
  _cache.clear()
150
150
 
151
- def raw(self, *, early_exit: bool = False, order: str = "severity") -> list[ToolResult]:
151
+ def raw(
152
+ self, *, early_exit: bool = False, order: str = "severity"
153
+ ) -> list[ToolResult]:
152
154
  """Run all tools and return parsed results before aggregation."""
153
155
  return run_tools(
154
156
  self._registry.values(),
@@ -218,7 +220,7 @@ class CQ:
218
220
  )
219
221
  if fp.tool not in tool_registry:
220
222
  raise ValueError(f"Unknown tool: {fp.tool!r}")
221
-
223
+
222
224
  if fp.code and fp.path:
223
225
  # Specific issue: target only the affected file for a fast re-check
224
226
  file_path = Path(fp.path)
@@ -242,7 +244,11 @@ class CQ:
242
244
 
243
245
  only_registry = {fp.tool: tool_registry[fp.tool]}
244
246
  tool_results = run_tools(
245
- only_registry.values(), target, max_workers=1, early_exit=False, excludes=[],
247
+ only_registry.values(),
248
+ target,
249
+ max_workers=1,
250
+ early_exit=False,
251
+ excludes=[],
246
252
  project_root=str(self.path),
247
253
  )
248
254
 
py_cq/cli.py CHANGED
@@ -107,7 +107,7 @@ def callback(
107
107
  help="Show version and dependencies",
108
108
  ),
109
109
  ) -> None:
110
- """Feed the results from 11+ code quality tools to an LLM. Try: cq check . -o llm"""
110
+ """Feed the results from 12 code quality tools to an LLM. Try: cq check . -o llm"""
111
111
  import sys
112
112
 
113
113
  if isinstance(sys.stdout, io.TextIOWrapper):
@@ -124,7 +124,7 @@ def check(
124
124
  OutputMode.TABLE,
125
125
  "--output",
126
126
  "-o",
127
- help="Output mode: table (default), score, json, llm",
127
+ help="Output mode: table (default), score, json, raw, llm, llm-json",
128
128
  ),
129
129
  log_level: str = typer.Option(
130
130
  "CRITICAL",
@@ -172,7 +172,7 @@ def check(
172
172
  help="Issue selection order for -o llm/llm-json: severity (most severe first) or phase (first non-clean phase, in dependency order)",
173
173
  ),
174
174
  ):
175
- """Feed the results from 11+ code quality tools to an LLM. Try: cq check . -o llm""" # --help
175
+ """Feed the results from 12 code quality tools to an LLM. Try: cq check . -o llm""" # --help
176
176
  path_obj = Path(path)
177
177
  if not path_obj.exists():
178
178
  raise typer.BadParameter(f"Path does not exist: {path}")
py_cq/config/config.toml CHANGED
@@ -101,3 +101,12 @@ order = 11
101
101
  gate_strict = false
102
102
  warning_threshold = 0.35
103
103
  error_threshold = 0.3
104
+
105
+ [python.ruff-format]
106
+ command = "{python} -m ruff format --check --output-format concise --no-cache \"{context_path}\" --exclude .claude --config \"include=['*.py','*.pyi','*.ipynb']\"{exclude}"
107
+ exclude_format = " --exclude {path}"
108
+ parser = "RuffFormatParser"
109
+ order = 12
110
+ gate_strict = false
111
+ warning_threshold = 0.9999
112
+ error_threshold = 0.5
py_cq/execution_engine.py CHANGED
@@ -328,7 +328,9 @@ def run_tool(
328
328
  timestamp=timestamp,
329
329
  project_path=project_dir,
330
330
  )
331
- _cache.set(cache_key, raw_result.to_dict(), expire=5 * 24 * 60 * 60, tag=project_tag)
331
+ _cache.set(
332
+ cache_key, raw_result.to_dict(), expire=5 * 24 * 60 * 60, tag=project_tag
333
+ )
332
334
  return raw_result
333
335
 
334
336
 
@@ -386,7 +388,9 @@ def run_tools(
386
388
  t_hash0 = time.perf_counter()
387
389
  root = project_root or str(Path(path).resolve())
388
390
  shared_hash = get_context_hash(root)
389
- log.debug(f"context_hash: {(time.perf_counter() - t_hash0) * 1000:.1f}ms {shared_hash}")
391
+ log.debug(
392
+ f"context_hash: {(time.perf_counter() - t_hash0) * 1000:.1f}ms {shared_hash}"
393
+ )
390
394
 
391
395
  # Cache keys are content-based, so a changed project naturally produces new
392
396
  # keys; stale entries age out via TTL + size_limit (no blanket eviction).
@@ -398,7 +402,9 @@ def run_tools(
398
402
  if any(tc.cache_invariant == "ast" for tc in tool_configs):
399
403
  t_norm0 = time.perf_counter()
400
404
  norm_hash = get_context_hash(root, normalize=True)
401
- log.debug(f"context_hash(ast): {(time.perf_counter() - t_norm0) * 1000:.1f}ms {norm_hash}")
405
+ log.debug(
406
+ f"context_hash(ast): {(time.perf_counter() - t_norm0) * 1000:.1f}ms {norm_hash}"
407
+ )
402
408
 
403
409
  def _hash_for(tool_config: ToolConfig) -> str:
404
410
  return norm_hash if tool_config.cache_invariant == "ast" else shared_hash
@@ -410,7 +416,14 @@ def run_tools(
410
416
  # Only pass cancel_event when present so patched run_tool stubs in tests
411
417
  # (which don't declare the kwarg) keep working for non-cancellable tools.
412
418
  extra = {"cancel_event": cancel_event} if cancel_event is not None else {}
413
- raw_result = run_tool(tool_config, path, excludes, precomputed_hash=_hash_for(tool_config), project_tag=root, **extra)
419
+ raw_result = run_tool(
420
+ tool_config,
421
+ path,
422
+ excludes,
423
+ precomputed_hash=_hash_for(tool_config),
424
+ project_tag=root,
425
+ **extra,
426
+ )
414
427
  tr = tool_config.parser_class(tool_config.parser_config).parse(raw_result)
415
428
  tr.duration_s = time.perf_counter() - t0
416
429
  return tool_config.order, tr
@@ -423,7 +436,9 @@ def run_tools(
423
436
  try:
424
437
  prioritized.append(_run_and_parse(tool_config))
425
438
  except Exception as exc: # noqa: BLE001 - a crashing tool must not abort the run
426
- log.error(f"{tool_config.name} generated an exception: {exc} {exc.__traceback__}")
439
+ log.error(
440
+ f"{tool_config.name} generated an exception: {exc} {exc.__traceback__}"
441
+ )
427
442
  n_skipped = n_total - i - 1
428
443
  if n_skipped:
429
444
  remaining = ", ".join(tc.name for tc in sorted_configs[i + 1 :])
@@ -477,7 +492,10 @@ def run_tools(
477
492
  _, dep_tr = dep_future.result()
478
493
  except Exception: # noqa: BLE001 - a crashed dep cancels nothing
479
494
  return
480
- if dep_tr.metrics and min(dep_tr.metrics.values()) < dep_config.error_threshold:
495
+ if (
496
+ dep_tr.metrics
497
+ and min(dep_tr.metrics.values()) < dep_config.error_threshold
498
+ ):
481
499
  log.debug(f"{name}: cancelling because {dep_config.name} failed")
482
500
  ev.set()
483
501
 
@@ -485,8 +503,8 @@ def run_tools(
485
503
  if tc.name in cancel_events:
486
504
  dep_config = configs_by_name[tc.skip_if]
487
505
  name_to_future[tc.skip_if].add_done_callback(
488
- lambda fut, ev=cancel_events[tc.name], dc=dep_config, nm=tc.name: _cancel_on_dep_failure(
489
- fut, ev, dc, nm
506
+ lambda fut, ev=cancel_events[tc.name], dc=dep_config, nm=tc.name: (
507
+ _cancel_on_dep_failure(fut, ev, dc, nm)
490
508
  )
491
509
  )
492
510
  for future in as_completed(future_to_tool):
py_cq/localtypes.py CHANGED
@@ -60,11 +60,11 @@ class ToolConfig:
60
60
  default_factory=list
61
61
  ) # Top-level dir/file names to omit from {scan_targets}
62
62
  skip_for_file: bool = False # If True, skip when context_path is a single file
63
- gate_strict: bool = True # If False, small regressions above warning_threshold are accepted
64
- skip_if: str = "" # Tool name; if that tool's score is below its error_threshold, skip this tool
65
- cache_invariant: str = (
66
- "" # "ast": key the cache on the docstring-stripped AST, ignoring docstrings/comments/format
63
+ gate_strict: bool = (
64
+ True # If False, small regressions above warning_threshold are accepted
67
65
  )
66
+ skip_if: str = "" # Tool name; if that tool's score is below its error_threshold, skip this tool
67
+ cache_invariant: str = "" # "ast": key the cache on the docstring-stripped AST, ignoring docstrings/comments/format
68
68
 
69
69
 
70
70
  @dataclass
py_cq/parsers/common.py CHANGED
@@ -47,9 +47,7 @@ def format_source_context(
47
47
  error_offset = line - context_start # 0-based index of the error line in raw_lines
48
48
  collected = []
49
49
  for i, rline in enumerate(raw_lines):
50
- if i > error_offset and (
51
- rline.startswith(("def ", "async def ", "class "))
52
- ):
50
+ if i > error_offset and (rline.startswith(("def ", "async def ", "class "))):
53
51
  break
54
52
  collected.append(f"{context_start + i}: {rline}")
55
53
  src = "\n".join(collected)
@@ -32,7 +32,10 @@ def _format_missing_docstring(file_str: str, line: int, code: str, message: str)
32
32
  )
33
33
 
34
34
  if code == "D100":
35
- return base + "\n\nInsert a module-level docstring as the very first statement in the file."
35
+ return (
36
+ base
37
+ + "\n\nInsert a module-level docstring as the very first statement in the file."
38
+ )
36
39
 
37
40
  try:
38
41
  tree = get_source(file_str).tree
@@ -74,6 +77,7 @@ def _format_missing_docstring(file_str: str, line: int, code: str, message: str)
74
77
 
75
78
  return base + "\n\nInsert a docstring as the first statement in the body."
76
79
 
80
+
77
81
  _ROW_RE = re.compile(
78
82
  r"^\|\s+(.+?)\s+\|\s+(\d+)\s+\|\s+(\d+)\s+\|\s+\d+\s+\|\s+(\d+(?:\.\d+)?)%\s*\|"
79
83
  )
@@ -85,7 +89,9 @@ def _load_interrogate_cfg(context_path: str) -> dict:
85
89
  """Read [tool.interrogate] from the nearest pyproject.toml."""
86
90
  p = Path(context_path).resolve()
87
91
  for candidate in [p, *p.parents]:
88
- pyproject = (candidate if candidate.is_dir() else candidate.parent) / "pyproject.toml"
92
+ pyproject = (
93
+ candidate if candidate.is_dir() else candidate.parent
94
+ ) / "pyproject.toml"
89
95
  if pyproject.exists():
90
96
  try:
91
97
  data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
@@ -109,7 +115,9 @@ def _skip_node(name: str, cfg: dict) -> bool:
109
115
  return bool(is_semiprivate and cfg.get("ignore-semiprivate"))
110
116
 
111
117
 
112
- def _missing_docstrings(file_path: Path, cfg: dict | None = None) -> list[tuple[int, str, str]]:
118
+ def _missing_docstrings(
119
+ file_path: Path, cfg: dict | None = None
120
+ ) -> list[tuple[int, str, str]]:
113
121
  """Return (line, kind, source_line) for each node missing a docstring.
114
122
 
115
123
  kind is 'module', 'def', or 'class'. source_line is the verbatim text of
@@ -0,0 +1,62 @@
1
+ """Parses output from ruff format --check into a standardized ToolResult.
2
+
3
+ The output is one line per unformatted file. ruff >= 0.16 honours
4
+ ``--output-format concise``::
5
+
6
+ <file>:<line>:<col>: unformatted: File would be reformatted
7
+
8
+ while older versions ignore it (it needs preview mode) and print::
9
+
10
+ Would reformat: <file>
11
+
12
+ Either is followed by a summary line such as
13
+ ``2 files would be reformatted, 30 files already formatted`` or
14
+ ``32 files already formatted``.
15
+
16
+ The score is the fraction of checked files that are already formatted,
17
+ taken from the summary so it stays correct if the per-file format changes."""
18
+
19
+ import re
20
+
21
+ from py_cq.localtypes import AbstractParser, RawResult, ToolResult
22
+ from py_cq.parsers.common import extract_first_issue
23
+
24
+ _FILE_RE = re.compile(r"^(?:Would reformat: (.+)|(.+):\d+:\d+: unformatted: .*)$")
25
+ _FORMATTED_RE = re.compile(r"(\d+) files? already formatted")
26
+ _UNFORMATTED_RE = re.compile(r"(\d+) files? would be reformatted")
27
+
28
+
29
+ class RuffFormatParser(AbstractParser):
30
+ """Parses ``ruff format --check --output-format concise`` output into a ToolResult."""
31
+
32
+ def parse(self, raw_result: RawResult) -> ToolResult:
33
+ """Collect unformatted files and score the fraction already formatted."""
34
+ stdout = raw_result.stdout or ""
35
+ # One issue per file, with no line: the line ruff reports is the first
36
+ # diff hunk, which would make the fingerprint unstable across edits.
37
+ files: dict[str, list] = {}
38
+ for line in stdout.splitlines():
39
+ m = _FILE_RE.match(line)
40
+ if m:
41
+ files[(m.group(1) or m.group(2)).replace("\\", "/")] = [{}]
42
+ m = _FORMATTED_RE.search(stdout)
43
+ formatted = int(m.group(1)) if m else 0
44
+ m = _UNFORMATTED_RE.search(stdout)
45
+ unformatted = max(int(m.group(1)) if m else 0, len(files))
46
+ total = formatted + unformatted
47
+ score = formatted / total if total else 1.0
48
+ return ToolResult(raw=raw_result, metrics={"formatted": score}, details=files)
49
+
50
+ def format_llm_message(
51
+ self, tr: ToolResult, *, context_lines: int = 15, limit: int = 1
52
+ ) -> str:
53
+ """Ask for the formatter to be run rather than a hand edit."""
54
+ result = extract_first_issue(tr.details)
55
+ if result is None:
56
+ return "ruff format reported issues (no details available)"
57
+ file, _ = result
58
+ return (
59
+ f"{file} - **not formatted**. Run the formatter, do not edit by hand:\n\n"
60
+ f"```bash\nruff format {file}\n```\n\n"
61
+ "Other files may also need formatting; `ruff format .` fixes them all."
62
+ )
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-code-quality
3
- Version: 0.3.0
4
- Summary: Python Code Quality Analysis Tool - feed the results from 11 CQ tools straight into an LLM. Minimal tokens.
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
@@ -35,7 +35,7 @@ Description-Content-Type: text/markdown
35
35
  [![Python versions](https://img.shields.io/pypi/pyversions/python-code-quality?)](https://pypi.org/project/python-code-quality/)
36
36
  [![License](https://img.shields.io/github/license/rhiza-fr/py-cq)](LICENSE)
37
37
 
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.
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
 
@@ -81,6 +81,7 @@ When running '-o llm', we run sequentially and exit early at the first error.
81
81
  | 9 | radon cc | Cyclomatic complexity |
82
82
  | 10 | radon mi | Maintainability index |
83
83
  | 11 | radon hal | Halstead volume / bug estimate |
84
+ | 12 | ruff format | Formatting (fraction of files already formatted) |
84
85
 
85
86
  Diskcache is used to cache tool output for lightning fast re-runs. Sane defaults: <100 Mb, <5 days, No pickle risk.
86
87
 
@@ -101,7 +102,7 @@ cq check . --exclude demo # Exclude paths from all tools
101
102
  cq check . --workers 1 # Run sequentially if you like things slow
102
103
  cq check . --clear-cache # Clear cached results before running (rarely needed)
103
104
  cq check . -o llm --hint # Append "run cq again to verify" (for human workflows)
104
- cq config path/to/project/ # Show effective tool configuration
105
+ cq config --path path/to/project/ # Show effective tool configuration
105
106
  cq is-fixed <fingerprint> # Check whether a specific issue has been resolved
106
107
  ```
107
108
 
@@ -250,14 +251,15 @@ Then invoke it with `/cq-fix` in Claude Code. The `$(...)` embeds the live `cq`
250
251
  │ bandit │ 0.56s │ security │ 1.000 │ OK │
251
252
  │ pytest │ 0.91s │ tests │ 1.000 │ OK │
252
253
  │ coverage │ 1.26s │ coverage │ 0.910 │ OK │
253
- │ radon cc │ 0.32s │ simplicity │ 0.982 │ OK │
254
- │ radon mi │ 0.38s │ maintainability │ 0.869 │ OK │
255
- │ radon hal │ 0.30s │ file_bug_free │ 0.928 │ OK │
256
- │ radon hal │ │ file_smallness │ 0.851 │ OK │
257
- │ radon hal │ │ functions_bug_free │ 0.913 │ OK │
258
- │ radon hal │ │ functions_smallness │ 0.724 │ OK │
259
254
  │ vulture │ 0.32s │ dead_code │ 1.000 │ OK │
260
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 │
261
263
  │ │ │ Score │ 0.965 │ │
262
264
  └──────────────────┴──────────┴───────────────────────────┴─────────┴──────────┘
263
265
  ```
@@ -339,7 +341,7 @@ warning = 0.9
339
341
  error = 0.7
340
342
  ```
341
343
 
342
- 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`.
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`.
343
345
 
344
346
 
345
347
  ### Default config
@@ -450,6 +452,15 @@ order = 11
450
452
  gate_strict = false
451
453
  warning_threshold = 0.35
452
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
453
464
  ```
454
465
 
455
466
  ## Respect
@@ -1,28 +1,29 @@
1
1
  py_cq/__init__.py,sha256=-C6_QzQeydxft3ndlExTgWnvlqH8fJNPJxfySXULQmU,56
2
- py_cq/api.py,sha256=AxhTQVX4ACZmgCpdfJgB2_1VXtClxc531NkRoLK1vA0,10118
3
- py_cq/cli.py,sha256=aaLnBXF81fkUtCvO7DGzmogcq50X5bF5dC4XFC4sbqY,13814
2
+ py_cq/api.py,sha256=u0ajk6ZYWFGjSsLYkRfUBBtL_Vw0HHZbWpa1AM79y8Y,10172
3
+ py_cq/cli.py,sha256=zciffdqyz_TXO8xfTlItWBS8s8eFGhG7Iv0I2M9eBK4,13827
4
4
  py_cq/config/__init__.py,sha256=f0wc51O_3kGDTZUnCbGv8_zWnC5yYGl4NWcf2buSImQ,670
5
- py_cq/config/config.toml,sha256=fco0qKWfIg84e3ex2pmAcSPYBmcHdbiqL-Geo__EIkM,3017
5
+ py_cq/config/config.toml,sha256=TnUzP2cKKsyfN9GbnGeveBnqKTQl_PEYggOrpqBPg3s,3357
6
6
  py_cq/context_hash.py,sha256=uKMkN394v6QYMukZj9usbxnq8px3i1khyIRPKwe09DE,5614
7
- py_cq/execution_engine.py,sha256=vAbNDCHP5c-2ADWs9SM0eCEpZBiabhpl-WZp6Er3qb4,20644
7
+ py_cq/execution_engine.py,sha256=nuW-N8X1ZmtxzkohFxxYvVPBrBIR2TPExMsPQCTAZ6A,20865
8
8
  py_cq/language_detector.py,sha256=rh5bAA3LyCQR3RODmx_EalqRNYvSYK2SJzh2hIkxOUo,1139
9
9
  py_cq/llm_formatter.py,sha256=nCV3nFdxJAi2CnH9FKb5tB-0w-yjLWmjywQI5GJ2cSU,8412
10
- py_cq/localtypes.py,sha256=mt4sqUg1bz2BenirGA18X4CdtyZahTAuKyOfwFnwfSE,7907
10
+ py_cq/localtypes.py,sha256=_g6RpV-JS6T0lD_Uqq4iA5e2Fw6RM56Lqrv_GiP4gm8,7907
11
11
  py_cq/main.py,sha256=5dgr8Zk1LNK5M-0wncYVksBp0qE-jWZYqmOXfb1eOhk,400
12
12
  py_cq/metric_aggregator.py,sha256=M2ymo62S7p7qPUqjjoiPg4IVyXQhLMuTr9-jxLiFjCY,853
13
13
  py_cq/parsers/__init__.py,sha256=uCy7R0cnvDPNvB5aWMLgM3FB9nDcu1jwUmznFMRROSY,28
14
14
  py_cq/parsers/banditparser.py,sha256=YqpWljU5D4IhLdtzat7XVGBm9NXrbOQbr9LI9NKybK8,3298
15
- py_cq/parsers/common.py,sha256=r8UD7pch-txlJSTsJrOff2o3_0WHRlZhgKbJ-C58L7g,13818
15
+ py_cq/parsers/common.py,sha256=ViYneYOG4RTlbHbSU4GN9kB_M1gikukiwQ81CTajAqA,13796
16
16
  py_cq/parsers/compileparser.py,sha256=jl0DloyXTKqVHRIUft-t5lvJOndY-PdLPrXB38v9zuA,6927
17
17
  py_cq/parsers/complexityparser.py,sha256=mX1WHPRgBBc6kOqHfubowRbYXY0E1k4JVwr908Cj10U,5582
18
18
  py_cq/parsers/coverageparser.py,sha256=QGjZ8JJF0G-0uiZ07BzxSnblGiysHtOwq0SYvWrtOhA,7441
19
19
  py_cq/parsers/exitcodeparser.py,sha256=b4LWIwwklPwCX3MnqNsGQC1slQU56DKE05vJ0OdWVoA,957
20
20
  py_cq/parsers/halsteadparser.py,sha256=789c_WWfomskM4i7SUEbKvB67-F2y5nfqt48aFXOusY,10192
21
- py_cq/parsers/interrogateparser.py,sha256=55HZ2j1Rz34eremwGx-W9oIMI21DIqwxEG524UgsAhk,11249
21
+ py_cq/parsers/interrogateparser.py,sha256=KDqXTdnJ5JzWhN4ziRda90nZCQOJaKn3CCiq4Rh0IRw,11314
22
22
  py_cq/parsers/linecountparser.py,sha256=-hqebwG4j7_QugzGLUUQRcPukGHicV2nbIp1pR8ZcAw,1310
23
23
  py_cq/parsers/maintainabilityparser.py,sha256=3a4m93XNtUurw3IxEI1Iae9idgJY6qiEt7HMYl1wTu0,4793
24
24
  py_cq/parsers/pytestparser.py,sha256=cIaTs2XxgeJlVragLEVTZcrbB-bzfNYYMdUrakRa-rQ,11545
25
25
  py_cq/parsers/regexcountparser.py,sha256=zGzHEYDIori6aiWnVkRFixdE7fWt66npAAWjzvpoBF4,1592
26
+ py_cq/parsers/ruffformatparser.py,sha256=UXff5Qwh9i0goiSTJ_AaaIsmMSssUjNY2O_dERXjsFw,2636
26
27
  py_cq/parsers/ruffparser.py,sha256=uE0QEaZ4Ch7IsWY_2ZkfHXPU0TYPGsGPfv66hGe5G34,7634
27
28
  py_cq/parsers/typarser.py,sha256=x835OrapG1aUteW2NhC5U0bhj1w1pMtbfmbvb74-1AI,8077
28
29
  py_cq/parsers/vultureparser.py,sha256=-yGAXzRY4_fzLRTk7dfwDrrRZ-n97j1Ph5_xo3c6TfU,2229
@@ -30,7 +31,7 @@ py_cq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
31
  py_cq/source_file.py,sha256=Uyv-CSVeliFnE6TpRB4Y15ykFQs4n0r9-amzxXXlqN0,7562
31
32
  py_cq/table_formatter.py,sha256=-22nzVIOaDe3QOBmZ2iBPH7ewIEIPEn5WYSjCoB4Hj4,1608
32
33
  py_cq/tool_registry.py,sha256=0s0sD9_iQW-HU0SIKSS8CFDlrzW0c-vlYrAFODEHiSc,1894
33
- python_code_quality-0.3.0.dist-info/WHEEL,sha256=ZFFp7t7R4RYQ5KYZkmiFWoQvHay7SrTmn-6ZYfoFZ3U,80
34
- python_code_quality-0.3.0.dist-info/entry_points.txt,sha256=cfWbTw7eYO6Trv1-Z_odL6Zta9CqYU6Vk9lAHdfB60Q,40
35
- python_code_quality-0.3.0.dist-info/METADATA,sha256=hQBSoblR8TKmTPRriXRt5Ed-uO9jexstNj0nPU4Li4A,16213
36
- python_code_quality-0.3.0.dist-info/RECORD,,
34
+ python_code_quality-0.3.1.dist-info/WHEEL,sha256=xTCBFIZIIyRSxyowOv5Wqg_jFU6KsdIffuulBB09Ph8,80
35
+ python_code_quality-0.3.1.dist-info/entry_points.txt,sha256=cfWbTw7eYO6Trv1-Z_odL6Zta9CqYU6Vk9lAHdfB60Q,40
36
+ python_code_quality-0.3.1.dist-info/METADATA,sha256=E3HJ8qZESv7gyGqBQrSiQeeyDTyFYe9v7cm6Kt8x8_8,16739
37
+ python_code_quality-0.3.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.12.7
2
+ Generator: uv 0.13.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any