Spaces:
Sleeping
Sleeping
| """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)}" | |