Spaces:
Runtime error
Runtime error
| """ | |
| Code Executor β Sandboxed Python execution for CodeReviewEnv. | |
| Runs Python code + test cases in an isolated namespace. | |
| Returns execution results, stdout, stderr, and test pass/fail. | |
| This makes CodeReviewEnv a REAL tool server: agents run code, | |
| see actual failures, and submit fixes that are verified by execution. | |
| """ | |
| import io | |
| import sys | |
| import traceback | |
| from typing import Any, Dict, List, Optional, Tuple | |
| # Maximum execution time (seconds) and output length | |
| EXEC_TIMEOUT = 5 | |
| MAX_OUTPUT_LEN = 4096 | |
| def execute_code(code: str, test_code: str = "") -> Dict[str, Any]: | |
| """Execute Python code + test cases in an isolated namespace. | |
| Args: | |
| code: The source code to execute | |
| test_code: Test assertions to run after the code | |
| Returns: | |
| { | |
| "success": bool, | |
| "stdout": str, | |
| "stderr": str, | |
| "error": str or None, | |
| "tests_passed": int, | |
| "tests_failed": int, | |
| "test_results": [{"name": str, "passed": bool, "error": str}], | |
| } | |
| """ | |
| namespace: Dict[str, Any] = {} | |
| stdout_capture = io.StringIO() | |
| stderr_capture = io.StringIO() | |
| result = { | |
| "success": False, | |
| "stdout": "", | |
| "stderr": "", | |
| "error": None, | |
| "tests_passed": 0, | |
| "tests_failed": 0, | |
| "test_results": [], | |
| } | |
| # Step 1: Execute the main code | |
| old_stdout, old_stderr = sys.stdout, sys.stderr | |
| try: | |
| sys.stdout = stdout_capture | |
| sys.stderr = stderr_capture | |
| exec(code, namespace) | |
| result["success"] = True | |
| except Exception as e: | |
| result["error"] = f"{type(e).__name__}: {e}" | |
| result["success"] = False | |
| finally: | |
| sys.stdout = old_stdout | |
| sys.stderr = old_stderr | |
| result["stdout"] = stdout_capture.getvalue()[:MAX_OUTPUT_LEN] | |
| result["stderr"] = stderr_capture.getvalue()[:MAX_OUTPUT_LEN] | |
| # Step 2: Run test cases | |
| if test_code and result["success"]: | |
| test_results = _run_tests(test_code, namespace) | |
| result["test_results"] = test_results | |
| result["tests_passed"] = sum(1 for t in test_results if t["passed"]) | |
| result["tests_failed"] = sum(1 for t in test_results if not t["passed"]) | |
| return result | |
| def _run_tests(test_code: str, namespace: Dict) -> List[Dict[str, Any]]: | |
| """Run individual test assertions and collect results.""" | |
| results = [] | |
| # Split test code into individual assertions | |
| lines = test_code.strip().split('\n') | |
| test_blocks = [] | |
| current_block = [] | |
| for line in lines: | |
| stripped = line.strip() | |
| if stripped.startswith('# test:') or stripped.startswith('# Test:'): | |
| if current_block: | |
| test_blocks.append(('\n'.join(current_block), current_block[0].strip())) | |
| current_block = [] | |
| current_block.append(line) | |
| if current_block: | |
| test_blocks.append(('\n'.join(current_block), current_block[0].strip())) | |
| # If no labeled blocks, treat each assert as a test | |
| if len(test_blocks) <= 1: | |
| test_blocks = [] | |
| for line in lines: | |
| stripped = line.strip() | |
| if stripped and not stripped.startswith('#'): | |
| test_blocks.append((line, stripped[:60])) | |
| for code_block, name in test_blocks: | |
| try: | |
| exec(code_block, namespace) | |
| results.append({"name": name, "passed": True, "error": None}) | |
| except AssertionError as e: | |
| results.append({"name": name, "passed": False, "error": f"AssertionError: {e}"}) | |
| except Exception as e: | |
| results.append({"name": name, "passed": False, "error": f"{type(e).__name__}: {e}"}) | |
| return results | |
| def apply_fix_and_test( | |
| original_code: str, | |
| fix_code: str, | |
| test_code: str, | |
| ) -> Dict[str, Any]: | |
| """Apply agent's fix to the code and run tests. | |
| The fix_code can be either: | |
| 1. Complete replacement code | |
| 2. A patch description (we try to apply it) | |
| Returns execution results with test pass/fail. | |
| """ | |
| # Try the fix as complete replacement first | |
| result = execute_code(fix_code, test_code) | |
| if result["tests_passed"] > 0: | |
| return result | |
| # If that didn't work, try prepending original code context | |
| combined = original_code + "\n\n" + fix_code | |
| result = execute_code(combined, test_code) | |
| return result | |
| # βββ Test Case Templates βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # These map snippet names to test cases that validate correctness. | |
| # Tests are written against the ORIGINAL (clean) code β they should | |
| # PASS on clean code and FAIL on buggy code. | |
| SNIPPET_TESTS: Dict[str, str] = { | |
| "binary_search": """\ | |
| assert binary_search([1,2,3,4,5], 3) == 2 | |
| assert binary_search([1,2,3,4,5], 1) == 0 | |
| assert binary_search([1,2,3,4,5], 5) == 4 | |
| assert binary_search([1,2,3,4,5], 6) == -1 | |
| assert binary_search([], 1) == -1 | |
| assert binary_search([1], 1) == 0 | |
| """, | |
| "fibonacci": """\ | |
| assert fibonacci(0) == 0 | |
| assert fibonacci(1) == 1 | |
| assert fibonacci(2) == 1 | |
| assert fibonacci(5) == 5 | |
| assert fibonacci(10) == 55 | |
| """, | |
| "max_subarray": """\ | |
| assert max_subarray([1, -2, 3, 4, -1]) == 7 | |
| assert max_subarray([-1, -2, -3]) == -1 | |
| assert max_subarray([5]) == 5 | |
| assert max_subarray([]) == 0 | |
| """, | |
| "is_palindrome": """\ | |
| assert is_palindrome("racecar") == True | |
| assert is_palindrome("hello") == False | |
| assert is_palindrome("A man a plan a canal Panama") == True | |
| assert is_palindrome("") == True | |
| """, | |
| "merge_sort": """\ | |
| assert merge_sort([3,1,4,1,5]) == [1,1,3,4,5] | |
| assert merge_sort([]) == [] | |
| assert merge_sort([1]) == [1] | |
| assert merge_sort([5,4,3,2,1]) == [1,2,3,4,5] | |
| """, | |
| "flatten_dict": """\ | |
| assert flatten_dict({"a": 1, "b": {"c": 2}}) == {"a": 1, "b.c": 2} | |
| assert flatten_dict({}) == {} | |
| assert flatten_dict({"x": {"y": {"z": 1}}}) == {"x.y.z": 1} | |
| """, | |
| "validate_email": """\ | |
| assert validate_email("user@example.com") == True | |
| assert validate_email("bad") == False | |
| assert validate_email("@example.com") == False | |
| assert validate_email("user@.com") == False | |
| assert validate_email("") == False | |
| """, | |
| "group_by": """\ | |
| result = group_by([1,2,3,4,5], lambda x: x % 2) | |
| assert result[0] == [2, 4] | |
| assert result[1] == [1, 3, 5] | |
| """, | |
| "matrix_multiply": """\ | |
| assert matrix_multiply([[1,2],[3,4]], [[5,6],[7,8]]) == [[19,22],[43,50]] | |
| assert matrix_multiply([[1]], [[2]]) == [[2]] | |
| """, | |
| "csv_parser": """\ | |
| assert parse_csv("a,b,c") == [["a", "b", "c"]] | |
| assert parse_csv("1,2\\n3,4") == [["1", "2"], ["3", "4"]] | |
| """, | |
| "topological_sort": """\ | |
| result = topological_sort({"a": ["b"], "b": ["c"], "c": []}) | |
| assert result.index("a") < result.index("b") | |
| assert result.index("b") < result.index("c") | |
| """, | |
| "lru_cache": """\ | |
| cache = LRUCache(2) | |
| cache.put("a", 1) | |
| cache.put("b", 2) | |
| assert cache.get("a") == 1 | |
| cache.put("c", 3) | |
| assert cache.get("b") == -1 | |
| """, | |
| } | |