orchestrata_ultimate.verification.review.checks_quality
Reference › orchestrata_ultimate › verification › review › checks_quality
The quality checks of the deterministic review, called by the review engine and by the refactor codemod's review checks. check_type_hints (check 17) requires annotations on public functions, with helpers for __init__ parameters, return annotations and parameters (skipping self and cls). check_mutable_defaults (check 18, DEFAULT_VALUES) flags mutable default arguments. check_docstrings (check 19) requires docstrings on public classes and functions, and check_line_length (check 21) flags lines longer than 88 characters by default. Each returns a list of issue tuples and only reads the parsed tree and source lines. Public-name tests come from helpers. The commit-time lint step is described on the ruff gate page.
At a glance
| Source | src/orchestrata_ultimate/verification/review/checks_quality.py |
| Lines of code | 207 |
| Classes | 0 |
| Functions | 7 |
| Imports (internal) | orchestrata_ultimate.verification.review.helpers, orchestrata_ultimate.verification.review.types |
| Imported by | orchestrata_ultimate.refactor.codemod.review_checks, orchestrata_ultimate.verification.review.engine |
| Tests that import it | tests/verification/review/test_checks_quality.py, tests/verification/test_checks_quality.py, tests/verification/test_review_checks.py, tests/verification/test_review_checks_expanded.py |
Class diagram
No classes; see Functions.
Dependency diagram
API
Functions
| Function | Signature | Summary |
|---|---|---|
check_type_hints |
check_type_hints(filepath: str, tree: ast.Module) -> list[Issue] |
Check 17: TYPE_HINTS -- public functions have annotations. |
_check_init_params |
_check_init_params(node: ast.FunctionDef | ast.AsyncFunctionDef, rel_name: str, issues: list[Issue]) -> None |
Check init parameter annotations (skip self). |
_check_return_annotation |
_check_return_annotation(node: ast.FunctionDef | ast.AsyncFunctionDef, rel_name: str, issues: list[Issue]) -> None |
Check that a function has a return type annotation. |
_check_param_annotations |
_check_param_annotations(node: ast.FunctionDef | ast.AsyncFunctionDef, rel_name: str, issues: list[Issue]) -> None |
Check parameter type annotations (skip self/cls). |
check_mutable_defaults |
check_mutable_defaults(filepath: str, tree: ast.Module) -> list[Issue] |
Check 18: DEFAULT_VALUES -- no mutable defaults. |
check_docstrings |
check_docstrings(filepath: str, tree: ast.Module) -> list[Issue] |
Check 19: DOCSTRINGS -- public classes and functions. |
check_line_length |
check_line_length(filepath: str, lines: list[str], max_len: int = 88) -> list[Issue] |
Check 21: LINE_LENGTH -- max characters per line. |
Source
"""Quality checks: type hints, mutable defaults, docstrings, line length.
Covers checklist items 17, 18, 19, 21 from the CODE_REVIEW_PROMPT.
"""
import ast
import os
from orchestrata_ultimate.verification.review.helpers import _is_public
from orchestrata_ultimate.verification.review.types import Issue
def check_type_hints(
filepath: str,
tree: ast.Module,
) -> list[Issue]:
"""Check 17: TYPE_HINTS -- public functions have annotations.
Args:
filepath: Absolute path to the file.
tree: Parsed AST module.
Returns:
List of missing type annotation issues.
"""
issues: list[Issue] = []
rel_name = os.path.basename(filepath)
for node in ast.walk(tree):
if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
continue
if not _is_public(node.name):
continue
if node.name == "__init__":
_check_init_params(node, rel_name, issues)
continue
_check_return_annotation(node, rel_name, issues)
_check_param_annotations(node, rel_name, issues)
return issues
def _check_init_params(
node: ast.FunctionDef | ast.AsyncFunctionDef,
rel_name: str,
issues: list[Issue],
) -> None:
"""Check __init__ parameter annotations (skip self)."""
for arg in node.args.args[1:]:
if arg.annotation is None:
issues.append(
(
"TYPE_HINTS",
rel_name,
f"L{node.lineno}: `{node.name}()` "
f"param '{arg.arg}' has no type annotation.",
)
)
def _check_return_annotation(
node: ast.FunctionDef | ast.AsyncFunctionDef,
rel_name: str,
issues: list[Issue],
) -> None:
"""Check that a function has a return type annotation."""
if node.returns is None:
issues.append(
(
"TYPE_HINTS",
rel_name,
f"L{node.lineno}: `{node.name}()` missing return type annotation.",
)
)
def _check_param_annotations(
node: ast.FunctionDef | ast.AsyncFunctionDef,
rel_name: str,
issues: list[Issue],
) -> None:
"""Check parameter type annotations (skip self/cls)."""
params = node.args.args
start = 0
if params and params[0].arg in ("self", "cls"):
start = 1
for arg in params[start:]:
if arg.annotation is None:
issues.append(
(
"TYPE_HINTS",
rel_name,
f"L{node.lineno}: `{node.name}()` "
f"param '{arg.arg}' has no type annotation.",
)
)
def check_mutable_defaults(
filepath: str,
tree: ast.Module,
) -> list[Issue]:
"""Check 18: DEFAULT_VALUES -- no mutable defaults.
Args:
filepath: Absolute path to the file.
tree: Parsed AST module.
Returns:
List of mutable default argument issues.
"""
issues: list[Issue] = []
rel_name = os.path.basename(filepath)
mutable_types = (ast.List, ast.Dict, ast.Set)
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
all_defaults = node.args.defaults + node.args.kw_defaults
for default in all_defaults:
if default is not None and isinstance(default, mutable_types):
issues.append(
(
"MUTABLE_DEFAULT",
rel_name,
f"L{node.lineno}: `{node.name}()` has "
f"mutable default argument. "
f"Use None instead.",
)
)
return issues
def check_docstrings(
filepath: str,
tree: ast.Module,
) -> list[Issue]:
"""Check 19: DOCSTRINGS -- public classes and functions.
Args:
filepath: Absolute path to the file.
tree: Parsed AST module.
Returns:
List of missing docstring issues.
"""
issues: list[Issue] = []
rel_name = os.path.basename(filepath)
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
if _is_public(node.name) and not ast.get_docstring(node):
issues.append(
(
"DOCSTRING",
rel_name,
f"L{node.lineno}: `{node.name}()` missing docstring.",
)
)
elif isinstance(node, ast.ClassDef):
if _is_public(node.name) and not ast.get_docstring(node):
issues.append(
(
"DOCSTRING",
rel_name,
f"L{node.lineno}: `{node.name}` class missing docstring.",
)
)
return issues
def check_line_length(
filepath: str,
lines: list[str],
max_len: int = 88,
) -> list[Issue]:
"""Check 21: LINE_LENGTH -- max characters per line.
Args:
filepath: Absolute path to the file.
lines: File lines.
max_len: Maximum allowed line length.
Returns:
List of line length violation issues.
"""
issues: list[Issue] = []
rel_name = os.path.basename(filepath)
violations = 0
for i, line in enumerate(lines, 1):
stripped = line.rstrip("\n\r")
if len(stripped) > max_len:
if "http://" in stripped or "https://" in stripped:
continue
violations += 1
if violations <= 3:
issues.append(
(
"LINE_LENGTH",
rel_name,
f"L{i}: {len(stripped)} chars (max {max_len}).",
)
)
if violations > 3:
issues.append(
(
"LINE_LENGTH",
rel_name,
f"...and {violations - 3} more lines over {max_len} chars.",
)
)
return issues