summaryrefslogtreecommitdiff
path: root/yaksh/code_evaluator.py
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh/code_evaluator.py')
-rw-r--r--yaksh/code_evaluator.py101
1 files changed, 40 insertions, 61 deletions
diff --git a/yaksh/code_evaluator.py b/yaksh/code_evaluator.py
index 381b2e8..aab99eb 100644
--- a/yaksh/code_evaluator.py
+++ b/yaksh/code_evaluator.py
@@ -3,16 +3,15 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer
import pwd
import os
import stat
-from os.path import isdir, dirname, abspath, join, isfile
+from os.path import isdir, dirname, abspath, join, isfile, exists
import signal
+import traceback
from multiprocessing import Process, Queue
import subprocess
import re
-import json
# Local imports.
from settings import SERVER_TIMEOUT
-
MY_DIR = abspath(dirname(__file__))
@@ -50,33 +49,13 @@ def delete_signal_handler():
class CodeEvaluator(object):
"""Tests the code obtained from Code Server"""
- def __init__(self, test_case_data, test, language, user_answer,
- ref_code_path=None, in_dir=None):
+ def __init__(self, in_dir=None):
msg = 'Code took more than %s seconds to run. You probably '\
'have an infinite loop in your code.' % SERVER_TIMEOUT
self.timeout_msg = msg
- self.test_case_data = test_case_data
- self.language = language.lower()
- self.user_answer = user_answer
- self.ref_code_path = ref_code_path
- self.test = test
self.in_dir = in_dir
- self.test_case_args = None
-
- # Public Protocol ##########
- @classmethod
- def from_json(cls, language, json_data, in_dir):
- json_data = json.loads(json_data)
- test_case_data = json_data.get("test_case_data")
- user_answer = json_data.get("user_answer")
- ref_code_path = json_data.get("ref_code_path")
- test = json_data.get("test")
-
- instance = cls(test_case_data, test, language, user_answer, ref_code_path,
- in_dir)
- return instance
-
- def evaluate(self):
+
+ def evaluate(self, **kwargs):
"""Evaluates given code with the test cases based on
given arguments in test_case_data.
@@ -98,54 +77,72 @@ class CodeEvaluator(object):
A tuple: (success, error message).
"""
- self._setup()
- success, err = self._evaluate(self.test_case_args)
- self._teardown()
+ self.setup()
+ success, err = self.safe_evaluate(**kwargs)
+ self.teardown()
result = {'success': success, 'error': err}
return result
# Private Protocol ##########
- def _setup(self):
+ def setup(self):
self._change_dir(self.in_dir)
- def _evaluate(self, args):
+ def safe_evaluate(self, user_answer, test_case_data):
+ """
+ Handles code evaluation along with compilation, signal handling
+ and Exception handling
+ """
+
# Add a new signal handler for the execution of this code.
prev_handler = create_signal_handler()
success = False
- args = args or []
# Do whatever testing needed.
try:
- success, err = self._check_code(*args)
+ for test_case in test_case_data:
+ self.compile_code(user_answer, **test_case)
+ success, err = self.check_code(user_answer, **test_case)
+ if not success:
+ break
except TimeoutException:
err = self.timeout_msg
- except:
- _type, value = sys.exc_info()[:2]
- err = "Error: {0}".format(repr(value))
+ except Exception:
+ err = "Error: {0}".format(traceback.format_exc(limit=0))
+
finally:
# Set back any original signal handler.
set_original_signal_handler(prev_handler)
return success, err
- def _teardown(self):
+ def teardown(self):
# Cancel the signal
delete_signal_handler()
- def _check_code(self):
+ def check_code(self):
raise NotImplementedError("check_code method not implemented")
+ def compile_code(self, user_answer, **kwargs):
+ pass
+
def create_submit_code_file(self, file_name):
- """ Write the code (`answer`) to a file and set the file path"""
- submit_f = open(file_name, 'w')
- submit_f.write(self.user_answer.lstrip())
- submit_f.close()
- submit_path = abspath(submit_f.name)
+ """ Set the file path for code (`answer`)"""
+ submit_path = abspath(file_name)
+ if not exists(submit_path):
+ submit_f = open(submit_path, 'w')
+ submit_f.close()
return submit_path
+
+ def write_to_submit_code_file(self, file_path, user_answer):
+ """ Write the code (`answer`) to a file"""
+ submit_f = open(file_path, 'w')
+ submit_f.write(user_answer.lstrip())
+ submit_f.close()
+
def _set_file_as_executable(self, fname):
os.chmod(fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
| stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP
@@ -175,24 +172,6 @@ class CodeEvaluator(object):
raise
return proc, stdout, stderr
- def _compile_command(self, cmd, *args, **kw):
- """Compiles C/C++/java code and returns errors if any.
- Run a command in a subprocess while blocking, the process is killed
- if it takes more than 2 seconds to run. Return the Popen object, the
- stderr.
- """
- try:
- proc_compile = subprocess.Popen(cmd, shell=True, stdin=None,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out, err = proc_compile.communicate()
- except TimeoutException:
- # Runaway code, so kill it.
- proc_compile.kill()
- # Re-raise exception.
- raise
- return proc_compile, err
-
def _change_dir(self, in_dir):
if in_dir is not None and isdir(in_dir):
os.chdir(in_dir)