SecureCodeEnv / graders /documentation.py
vishaldhakad's picture
change in reward system to strict it between the 0-1
791664b
Raw
History Blame Contribute Delete
2.94 kB
"""SecureCodeEnv - Documentation & Structure Graders v4 β€” clamped scores"""
import ast
from graders.clamp import clamp
def grade_documentation(code: str) -> dict:
try:
tree = ast.parse(code)
except SyntaxError:
return {"score": clamp(0.0), "documented_fns": 0, "total_fns": 0,
"feedback": "Syntax error β€” cannot parse"}
functions = [n for n in ast.walk(tree)
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))]
if not functions:
has_mod_doc = bool(ast.get_docstring(tree))
return {"score": clamp(0.65 if has_mod_doc else 0.5),
"documented_fns": 0, "total_fns": 0,
"feedback": "No functions β€” module-level code only"}
scores = []
documented = typed = 0
for fn in functions:
s = 0.0
hd = bool(ast.get_docstring(fn))
hr = fn.returns is not None
hp = any(a.annotation is not None for a in fn.args.args)
if hd: documented += 1; s += 0.5
if hr or hp: typed += 1; s += 0.5
scores.append(s)
total = len(functions)
raw = sum(scores) / total
return {"score": clamp(raw), "documented_fns": documented,
"typed_fns": typed, "total_fns": total,
"feedback": _doc_feedback(raw, documented, typed, total)}
def grade_code_structure(code: str) -> dict:
try:
tree = ast.parse(code)
except SyntaxError:
return {"score": clamp(0.0), "checks": {}, "feedback": "Syntax error"}
lines = code.splitlines()
checks = {}
checks["no_bare_print"] = "print(" not in code
checks["no_bare_except"] = not any(
isinstance(n, ast.ExceptHandler) and n.type is None
for n in ast.walk(tree))
checks["reasonable_fn_size"] = not any(
isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and
(n.end_lineno or 0) - n.lineno > 50
for n in ast.walk(tree))
checks["no_todo_comments"] = not any(
any(kw in line.upper() for kw in ["# TODO", "# FIXME", "# HACK"])
for line in lines)
checks["handles_none"] = any(
token in code for token in
["None", "is not None", "if not ", "Optional", "is None"])
raw = sum(1 for v in checks.values() if v) / max(len(checks), 1)
return {"score": clamp(raw), "checks": checks,
"feedback": _struct_feedback(raw, checks)}
def _doc_feedback(score, documented, typed, total):
if score >= 0.85: return f"Well documented β€” {documented}/{total} docstrings, {typed}/{total} typed"
elif score >= 0.55: return f"Partial β€” {documented}/{total} docstrings, {typed}/{total} type hints"
return f"Poor β€” add docstrings and type hints to all {total} functions"
def _struct_feedback(score, checks):
if score >= 0.85: return "Clean code structure"
failing = [k for k, v in checks.items() if not v]
return f"Structure issues: {', '.join(failing)}"