Source code for grader.code_runner
import os
import subprocess
import datetime
import signal
import time
import sys
CURRENT_FOLDER = os.path.abspath(os.path.dirname(__file__))
SANDBOX_DIR = os.path.join(os.path.dirname(CURRENT_FOLDER), "sandbox")
TEST_RUN_CMD = [sys.executable, os.path.join(SANDBOX_DIR, "run_test")]
DOCKER_SANDBOX = [sys.executable, os.path.join(SANDBOX_DIR, 'run_tests_docker_sandbox')]
[docs]def read_proc_results(proc, decode):
stdout = proc.stdout.read()
stderr = proc.stderr.read()
if decode:
stdout = stdout.decode('utf-8')
stderr = stderr.decode('utf-8')
status = proc.returncode
return status, stdout, stderr
[docs]def microseconds_passed(time_delta):
return time_delta.microseconds + time_delta.seconds * 10**7
[docs]def call_command(cmd, timeout=float('inf'), cwd=None, decode=True, **subproc_options):
if cwd is None:
cwd = os.getcwd()
start = datetime.datetime.now()
subproc = subprocess.Popen(
cmd,
cwd=cwd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
**subproc_options
)
reached_timeout = False
while subproc.poll() is None:
time.sleep(0.02)
now = datetime.datetime.now()
if microseconds_passed(now-start) >= timeout * 10**6:
subproc.kill()
os.kill(subproc.pid, signal.SIGKILL)
os.waitpid(-1, os.WNOHANG)
reached_timeout = True
#break
status, stdout, stderr = read_proc_results(subproc, decode)
if reached_timeout:
status = 1
return status, stdout, stderr
[docs]def call_test(test_index, tester_path, solution_path, options):
# this assumes that tester, solution resides in the same path
#working_dir = os.getcwd()#os.path.dirname(tester_path)
cmd = TEST_RUN_CMD + [
tester_path,
solution_path,
str(test_index)
]
timeout = options.get('timeout', 1.0)
status, stdout, stderr = call_command(cmd, timeout)
return status == 0, stdout, stderr
[docs]def call_sandbox(sandbox_cmd, tester_path, solution_path):
cmd = sandbox_cmd + [tester_path, solution_path]
return call_command(cmd)