52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
|
|
import sys
|
|
import traceback
|
|
import time
|
|
import io
|
|
|
|
def run_code_against_tests(user_code, test_code):
|
|
import tempfile
|
|
import subprocess
|
|
local_ns = {}
|
|
output = ''
|
|
start = time.perf_counter()
|
|
error = None
|
|
passed = False
|
|
try:
|
|
# Check if unittest is used in test_code
|
|
if 'unittest' in test_code:
|
|
# Write user code + test code to a temp file
|
|
with tempfile.NamedTemporaryFile('w+', suffix='.py', delete=False) as f:
|
|
f.write(user_code + '\n' + test_code)
|
|
f.flush()
|
|
f_name = f.name
|
|
# Run the file as a subprocess
|
|
proc = subprocess.run([sys.executable, f_name], capture_output=True, text=True, timeout=10)
|
|
output = proc.stdout + proc.stderr
|
|
passed = proc.returncode == 0
|
|
error = None if passed else output
|
|
else:
|
|
# Capture stdout
|
|
old_stdout = sys.stdout
|
|
sys.stdout = mystdout = io.StringIO()
|
|
# Execute user code
|
|
exec(user_code, {}, local_ns)
|
|
# Execute test code (should raise AssertionError if fail)
|
|
exec(test_code, local_ns, local_ns)
|
|
passed = True
|
|
except Exception as e:
|
|
passed = False
|
|
error = traceback.format_exc()
|
|
finally:
|
|
if 'mystdout' in locals():
|
|
output = mystdout.getvalue() or output
|
|
sys.stdout = old_stdout if 'old_stdout' in locals() else sys.stdout
|
|
runtime = time.perf_counter() - start
|
|
result = {
|
|
'passed': passed,
|
|
'output': output,
|
|
'runtime': runtime,
|
|
'error': error if not passed else None
|
|
}
|
|
return result
|