diff options
Diffstat (limited to 'yaksh')
28 files changed, 366 insertions, 236 deletions
diff --git a/yaksh/bash_code_evaluator.py b/yaksh/bash_code_evaluator.py index bce7f07..e148fa8 100644 --- a/yaksh/bash_code_evaluator.py +++ b/yaksh/bash_code_evaluator.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import traceback import pwd import os @@ -8,8 +9,8 @@ import subprocess import importlib # local imports -from code_evaluator import CodeEvaluator -from file_utils import copy_files, delete_files +from .code_evaluator import CodeEvaluator +from .file_utils import copy_files, delete_files class BashCodeEvaluator(CodeEvaluator): diff --git a/yaksh/bash_stdio_evaluator.py b/yaksh/bash_stdio_evaluator.py index 8ff0743..e5e0da6 100644 --- a/yaksh/bash_stdio_evaluator.py +++ b/yaksh/bash_stdio_evaluator.py @@ -1,11 +1,12 @@ #!/usr/bin/env python +from __future__ import unicode_literals import subprocess import os from os.path import isfile -# local imports -from stdio_evaluator import StdIOEvaluator -from file_utils import copy_files, delete_files +#local imports +from .stdio_evaluator import StdIOEvaluator +from .file_utils import copy_files, delete_files class BashStdioEvaluator(StdIOEvaluator): diff --git a/yaksh/code_evaluator.py b/yaksh/code_evaluator.py index 8a9b7a6..870a67f 100644 --- a/yaksh/code_evaluator.py +++ b/yaksh/code_evaluator.py @@ -1,5 +1,6 @@ +#!/usr/bin/env python +from __future__ import unicode_literals import sys -from SimpleXMLRPCServer import SimpleXMLRPCServer import pwd import os import stat @@ -9,8 +10,15 @@ import traceback from multiprocessing import Process, Queue import subprocess import re -# Local imports. -from settings import SERVER_TIMEOUT + +try: + from SimpleXMLRPCServer import SimpleXMLRPCServer +except ImportError: + # The above import will not work on Python-3.x. + from xmlrpc.server import SimpleXMLRPCServer + +# Local imports +from .settings import SERVER_TIMEOUT MY_DIR = abspath(dirname(__file__)) @@ -127,6 +135,7 @@ class CodeEvaluator(object): def teardown(self): # Cancel the signal delete_signal_handler() + self._change_dir(dirname(MY_DIR)) def check_code(self): raise NotImplementedError("check_code method not implemented") @@ -176,7 +185,7 @@ class CodeEvaluator(object): proc.kill() # Re-raise exception. raise - return proc, stdout, stderr + return proc, stdout.decode('utf-8'), stderr.decode('utf-8') def _change_dir(self, in_dir): if in_dir is not None and isdir(in_dir): diff --git a/yaksh/code_server.py b/yaksh/code_server.py index e19e9c8..b3c9c30 100755 --- a/yaksh/code_server.py +++ b/yaksh/code_server.py @@ -23,7 +23,7 @@ that returns an available server. """ # Standard library imports -from SimpleXMLRPCServer import SimpleXMLRPCServer +from __future__ import unicode_literals import json from multiprocessing import Process, Queue import os @@ -36,6 +36,12 @@ import subprocess import sys try: + from SimpleXMLRPCServer import SimpleXMLRPCServer +except ImportError: + # The above import will not work on Python-3.x. + from xmlrpc.server import SimpleXMLRPCServer + +try: from urllib import unquote except ImportError: # The above import will not work on Python-3.x. @@ -45,9 +51,9 @@ except ImportError: from tornado.ioloop import IOLoop from tornado.web import Application, RequestHandler -# Local imports. -from settings import SERVER_PORTS, SERVER_POOL_PORT -from language_registry import create_evaluator_instance, unpack_json +# Local imports +from .settings import SERVER_PORTS, SERVER_POOL_PORT +from .language_registry import create_evaluator_instance, unpack_json MY_DIR = abspath(dirname(__file__)) diff --git a/yaksh/cpp_code_evaluator.py b/yaksh/cpp_code_evaluator.py index c65242d..5380dea 100644 --- a/yaksh/cpp_code_evaluator.py +++ b/yaksh/cpp_code_evaluator.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import traceback import pwd import os @@ -6,9 +7,9 @@ from os.path import join, isfile import subprocess import importlib -# local imports -from code_evaluator import CodeEvaluator -from file_utils import copy_files, delete_files +# Local imports +from .code_evaluator import CodeEvaluator +from .file_utils import copy_files, delete_files class CppCodeEvaluator(CodeEvaluator): @@ -18,9 +19,10 @@ class CppCodeEvaluator(CodeEvaluator): self.submit_code_path = self.create_submit_code_file('submit.c') self.compiled_user_answer = None self.compiled_test_code = None + self.user_output_path = "" + self.ref_output_path = "" def teardown(self): - super(CppCodeEvaluator, self).teardown() # Delete the created file. os.remove(self.submit_code_path) if os.path.exists(self.ref_output_path): @@ -29,9 +31,11 @@ class CppCodeEvaluator(CodeEvaluator): os.remove(self.user_output_path) if self.files: delete_files(self.files) + super(CppCodeEvaluator, self).teardown() + def set_file_paths(self): - user_output_path = os.getcwd() + '/output' + user_output_path = os.getcwd() + '/output_file' ref_output_path = os.getcwd() + '/executable' return user_output_path, ref_output_path @@ -104,7 +108,6 @@ class CppCodeEvaluator(CodeEvaluator): Returns (False, error_msg): If mandatory arguments are not files or if the required permissions are not given to the file(s). """ - success = False proc, stdnt_out, stdnt_stderr = self.compiled_user_answer stdnt_stderr = self._remove_null_substitute_char(stdnt_stderr) @@ -125,28 +128,28 @@ class CppCodeEvaluator(CodeEvaluator): if proc.returncode == 0: success, err = True, "Correct answer" else: - err = stdout + "\n" + stderr + err = "{0} \n {1}".format(stdout, stderr) else: err = "Error:" try: error_lines = main_err.splitlines() for e in error_lines: if ':' in e: - err = err + "\n" + e.split(":", 1)[1] + err = "{0} \n {1}".format(err, e.split(":", 1)[1]) else: - err = err + "\n" + e + err = "{0} \n {1}".format(err, e) except: - err = err + "\n" + main_err + err = "{0} \n {1}".format(err, main_err) else: err = "Compilation Error:" try: error_lines = stdnt_stderr.splitlines() for e in error_lines: if ':' in e: - err = err + "\n" + e.split(":", 1)[1] + err = "{0} \n {1}".format(err, e.split(":", 1)[1]) else: - err = err + "\n" + e + err = "{0} \n {1}".format(err, e) except: - err = err + "\n" + stdnt_stderr + err = "{0} \n {1}".format(err, stdnt_stderr) return success, err diff --git a/yaksh/cpp_stdio_evaluator.py b/yaksh/cpp_stdio_evaluator.py index 720ed0f..9d2b969 100644 --- a/yaksh/cpp_stdio_evaluator.py +++ b/yaksh/cpp_stdio_evaluator.py @@ -1,12 +1,12 @@ #!/usr/bin/env python +from __future__ import unicode_literals import subprocess import os from os.path import isfile -#local imports - -from stdio_evaluator import StdIOEvaluator -from file_utils import copy_files, delete_files +#Local imports +from .stdio_evaluator import StdIOEvaluator +from .file_utils import copy_files, delete_files class CppStdioEvaluator(StdIOEvaluator): @@ -17,13 +17,13 @@ class CppStdioEvaluator(StdIOEvaluator): self.submit_code_path = self.create_submit_code_file('main.c') def teardown(self): - super(CppStdioEvaluator, self).teardown() os.remove(self.submit_code_path) if self.files: delete_files(self.files) + super(CppStdioEvaluator, self).teardown() def set_file_paths(self): - user_output_path = os.getcwd() + '/output' + user_output_path = os.getcwd() + '/output_file' ref_output_path = os.getcwd() + '/executable' return user_output_path, ref_output_path diff --git a/yaksh/evaluator_tests/test_bash_evaluation.py b/yaksh/evaluator_tests/test_bash_evaluation.py index 084e5e4..66ade19 100755..100644 --- a/yaksh/evaluator_tests/test_bash_evaluation.py +++ b/yaksh/evaluator_tests/test_bash_evaluation.py @@ -1,5 +1,8 @@ +from __future__ import unicode_literals import unittest import os +import shutil +import tempfile from yaksh.bash_code_evaluator import BashCodeEvaluator from yaksh.bash_stdio_evaluator import BashStdioEvaluator from yaksh.settings import SERVER_TIMEOUT @@ -8,15 +11,23 @@ from textwrap import dedent class BashAssertionEvaluationTestCases(unittest.TestCase): def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + tmp_in_dir_path = tempfile.mkdtemp() self.test_case_data = [ {"test_case": "bash_files/sample.sh,bash_files/sample.args"} ] - self.in_dir = os.getcwd() + tmp_in_dir_path = tempfile.mkdtemp() + self.in_dir = tmp_in_dir_path self.timeout_msg = ("Code took more than {0} seconds to run. " "You probably have an infinite loop in your" " code.").format(SERVER_TIMEOUT) self.file_paths = None + def tearDown(self): + os.remove('/tmp/test.txt') + shutil.rmtree(self.in_dir) + def test_correct_answer(self): user_answer = ("#!/bin/bash\n[[ $# -eq 2 ]]" " && echo $(( $1 + $2 )) && exit $(( $1 + $2 ))" @@ -28,7 +39,7 @@ class BashAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertTrue(result.get('success')) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") def test_error(self): user_answer = ("#!/bin/bash\n[[ $# -eq 2 ]] " @@ -52,10 +63,10 @@ class BashAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_file_based_assert(self): - self.file_paths = [(os.getcwd()+"/yaksh/test.txt", False)] + self.file_paths = [('/tmp/test.txt', False)] self.test_case_data = [ {"test_case": "bash_files/sample1.sh,bash_files/sample1.args"} ] @@ -67,7 +78,7 @@ class BashAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertTrue(result.get("success")) - self.assertEquals(result.get("error"), "Correct answer") + self.assertEqual(result.get("error"), "Correct answer") class BashStdioEvaluationTestCases(unittest.TestCase): def setUp(self): @@ -88,7 +99,7 @@ class BashStdioEvaluationTestCases(unittest.TestCase): "test_case_data": test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_array_input(self): @@ -108,7 +119,7 @@ class BashStdioEvaluationTestCases(unittest.TestCase): "test_case_data": test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_incorrect_answer(self): @@ -142,7 +153,7 @@ class BashStdioEvaluationTestCases(unittest.TestCase): "test_case_data": test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) if __name__ == '__main__': diff --git a/yaksh/evaluator_tests/test_c_cpp_evaluation.py b/yaksh/evaluator_tests/test_c_cpp_evaluation.py index c6994f6..c990436 100755..100644 --- a/yaksh/evaluator_tests/test_c_cpp_evaluation.py +++ b/yaksh/evaluator_tests/test_c_cpp_evaluation.py @@ -1,5 +1,8 @@ +from __future__ import absolute_import import unittest import os +import shutil +import tempfile from yaksh.cpp_code_evaluator import CppCodeEvaluator from yaksh.cpp_stdio_evaluator import CppStdioEvaluator from yaksh.settings import SERVER_TIMEOUT @@ -8,13 +11,20 @@ from textwrap import dedent class CAssertionEvaluationTestCases(unittest.TestCase): def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + tmp_in_dir_path = tempfile.mkdtemp() self.test_case_data = [{"test_case": "c_cpp_files/main.cpp"}] - self.in_dir = os.getcwd() + self.in_dir = tmp_in_dir_path self.timeout_msg = ("Code took more than {0} seconds to run. " "You probably have an infinite loop in your" " code.").format(SERVER_TIMEOUT) self.file_paths = None + def tearDown(self): + os.remove('/tmp/test.txt') + shutil.rmtree(self.in_dir) + def test_correct_answer(self): user_answer = "int add(int a, int b)\n{return a+b;}" get_class = CppCodeEvaluator(self.in_dir) @@ -24,7 +34,7 @@ class CAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertTrue(result.get('success')) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") def test_incorrect_answer(self): user_answer = "int add(int a, int b)\n{return a-b;}" @@ -34,9 +44,10 @@ class CAssertionEvaluationTestCases(unittest.TestCase): 'file_paths': self.file_paths } result = get_class.evaluate(**kwargs) + lines_of_error = len(result.get('error').splitlines()) self.assertFalse(result.get('success')) self.assertIn("Incorrect:", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + self.assertTrue(lines_of_error > 1) def test_compilation_error(self): user_answer = "int add(int a, int b)\n{return a+b}" @@ -58,10 +69,10 @@ class CAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_file_based_assert(self): - self.file_paths = [(os.getcwd()+"/yaksh/test.txt", False)] + self.file_paths = [('/tmp/test.txt', False)] self.test_case_data = [{"test_case": "c_cpp_files/file_data.c"}] user_answer = dedent(""" #include<stdio.h> @@ -82,7 +93,7 @@ class CAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertTrue(result.get('success')) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") class CppStdioEvaluationTestCases(unittest.TestCase): @@ -106,7 +117,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_array_input(self): @@ -126,7 +137,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_string_input(self): @@ -144,7 +155,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_incorrect_answer(self): @@ -159,9 +170,10 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) + lines_of_error = len(result.get('error').splitlines()) self.assertFalse(result.get('success')) self.assertIn("Incorrect", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + self.assertTrue(lines_of_error > 1) def test_error(self): user_answer = dedent(""" @@ -191,7 +203,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_only_stdout(self): self.test_case_data = [{'expected_output': '11', @@ -207,7 +219,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_cpp_correct_answer(self): @@ -224,7 +236,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_cpp_array_input(self): @@ -245,7 +257,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_cpp_string_input(self): @@ -264,7 +276,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_cpp_incorrect_answer(self): @@ -280,9 +292,10 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) + lines_of_error = len(result.get('error').splitlines()) self.assertFalse(result.get('success')) self.assertIn("Incorrect", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + self.assertTrue(lines_of_error > 1) def test_cpp_error(self): user_answer = dedent(""" @@ -314,7 +327,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_cpp_only_stdout(self): self.test_case_data = [{'expected_output': '11', @@ -331,7 +344,7 @@ class CppStdioEvaluationTestCases(unittest.TestCase): 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) if __name__ == '__main__': diff --git a/yaksh/evaluator_tests/test_code_evaluation.py b/yaksh/evaluator_tests/test_code_evaluation.py index cbca32d..88e0253 100644 --- a/yaksh/evaluator_tests/test_code_evaluation.py +++ b/yaksh/evaluator_tests/test_code_evaluation.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import unittest import os from yaksh import python_assertion_evaluator @@ -38,7 +39,7 @@ class RegistryTestCase(unittest.TestCase): "stdiobasedtestcase": stdout_evaluator_path } ) - self.assertEquals(evaluator_class, class_name) + self.assertEqual(evaluator_class, class_name) def tearDown(self): self.registry_object = None diff --git a/yaksh/evaluator_tests/test_java_evaluation.py b/yaksh/evaluator_tests/test_java_evaluation.py index 60afb3b..e375bdb 100755..100644 --- a/yaksh/evaluator_tests/test_java_evaluation.py +++ b/yaksh/evaluator_tests/test_java_evaluation.py @@ -1,5 +1,8 @@ +from __future__ import unicode_literals import unittest import os +import shutil +import tempfile from yaksh import code_evaluator as evaluator from yaksh.java_code_evaluator import JavaCodeEvaluator from yaksh.java_stdio_evaluator import JavaStdioEvaluator @@ -9,10 +12,13 @@ from textwrap import dedent class JavaAssertionEvaluationTestCases(unittest.TestCase): def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + tmp_in_dir_path = tempfile.mkdtemp() self.test_case_data = [ {"test_case": "java_files/main_square.java"} ] - self.in_dir = os.getcwd() + self.in_dir = tmp_in_dir_path evaluator.SERVER_TIMEOUT = 9 self.timeout_msg = ("Code took more than {0} seconds to run. " "You probably have an infinite loop in" @@ -20,7 +26,8 @@ class JavaAssertionEvaluationTestCases(unittest.TestCase): self.file_paths = None def tearDown(self): - evaluator.SERVER_TIMEOUT = 2 + os.remove('/tmp/test.txt') + shutil.rmtree(self.in_dir) def test_correct_answer(self): user_answer = "class Test {\n\tint square_num(int a) {\n\treturn a*a;\n\t}\n}" @@ -30,7 +37,7 @@ class JavaAssertionEvaluationTestCases(unittest.TestCase): 'file_paths': self.file_paths } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_incorrect_answer(self): @@ -42,8 +49,10 @@ class JavaAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get('success')) - self.assertIn("Incorrect:", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + lines_of_error = len(result.get('error').splitlines()) + self.assertFalse(result.get('success')) + self.assertIn("Incorrect", result.get('error')) + self.assertTrue(lines_of_error > 1) def test_error(self): user_answer = "class Test {\n\tint square_num(int a) {\n\treturn a*a" @@ -65,10 +74,10 @@ class JavaAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_file_based_assert(self): - self.file_paths = [(os.getcwd()+"/yaksh/test.txt", False)] + self.file_paths = [("/tmp/test.txt", False)] self.test_case_data = [ {"test_case": "java_files/read_file.java"} ] @@ -97,11 +106,15 @@ class JavaAssertionEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertTrue(result.get("success")) - self.assertEquals(result.get("error"), "Correct answer") + self.assertEqual(result.get("error"), "Correct answer") class JavaStdioEvaluationTestCases(unittest.TestCase): def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + tmp_in_dir_path = tempfile.mkdtemp() + self.in_dir = tmp_in_dir_path self.test_case_data = [{'expected_output': '11', 'expected_input': '5\n6'}] evaluator.SERVER_TIMEOUT = 4 @@ -109,8 +122,10 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): "You probably have an infinite loop in" " your code.").format(evaluator.SERVER_TIMEOUT) - def teardown(self): + def tearDown(self): evaluator.SERVER_TIMEOUT = 4 + os.remove('/tmp/test.txt') + shutil.rmtree(self.in_dir) def test_correct_answer(self): user_answer = dedent(""" @@ -122,12 +137,12 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): int b = s.nextInt(); System.out.print(a+b); }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_array_input(self): @@ -144,12 +159,12 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): a[i] = s.nextInt(); System.out.print(a[i]);} }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_incorrect_answer(self): @@ -163,14 +178,15 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): int b = s.nextInt(); System.out.print(a); }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) + lines_of_error = len(result.get('error').splitlines()) self.assertFalse(result.get('success')) self.assertIn("Incorrect", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + self.assertTrue(lines_of_error > 1) def test_error(self): @@ -179,7 +195,7 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): { System.out.print("a"); }""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } @@ -196,13 +212,13 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): { System.out.print("a");} }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) def test_only_stdout(self): self.test_case_data = [{'expected_output': '11', @@ -214,12 +230,12 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): int b = 6; System.out.print(a+b); }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_string_input(self): @@ -234,13 +250,45 @@ class JavaStdioEvaluationTestCases(unittest.TestCase): String b = s.nextLine(); System.out.print(a+b); }}""") - get_class = JavaStdioEvaluator() + get_class = JavaStdioEvaluator(self.in_dir) kwargs = {'user_answer': user_answer, 'test_case_data': self.test_case_data } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) + def test_file_based_stdout(self): + self.file_paths = [("/tmp/test.txt", False)] + self.test_case_data = [{'expected_output': '2', + 'expected_input': ''}] + user_answer = dedent(""" + import java.io.BufferedReader; + import java.io.FileReader; + import java.io.IOException; + class Test{ + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new FileReader("test.txt")); + try { + StringBuilder sb = new StringBuilder(); + String line = br.readLine(); + while (line != null) { + sb.append(line); + line = br.readLine();} + System.out.print(sb.toString()); + } finally { + br.close(); + }}} + """) + get_class = JavaStdioEvaluator(self.in_dir) + kwargs = {'user_answer': user_answer, + 'test_case_data': self.test_case_data, + 'file_paths': self.file_paths + } + result = get_class.evaluate(**kwargs) + self.assertTrue(result.get("success")) + self.assertEqual(result.get("error"), "Correct answer") + + if __name__ == '__main__': unittest.main() diff --git a/yaksh/evaluator_tests/test_python_evaluation.py b/yaksh/evaluator_tests/test_python_evaluation.py index b72d26b..45cc40d 100755..100644 --- a/yaksh/evaluator_tests/test_python_evaluation.py +++ b/yaksh/evaluator_tests/test_python_evaluation.py @@ -1,13 +1,22 @@ +from __future__ import unicode_literals import unittest import os +import tempfile +import shutil +from textwrap import dedent + +# Local import from yaksh.python_assertion_evaluator import PythonAssertionEvaluator from yaksh.python_stdio_evaluator import PythonStdioEvaluator from yaksh.settings import SERVER_TIMEOUT -from textwrap import dedent class PythonAssertionEvaluationTestCases(unittest.TestCase): def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + tmp_in_dir_path = tempfile.mkdtemp() + self.in_dir = tmp_in_dir_path self.test_case_data = [{"test_case": 'assert(add(1,2)==3)'}, {"test_case": 'assert(add(-1,2)==1)'}, {"test_case": 'assert(add(-1,-2)==-3)'}, @@ -17,6 +26,10 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): " your code.").format(SERVER_TIMEOUT) self.file_paths = None + def tearDown(self): + os.remove('/tmp/test.txt') + shutil.rmtree(self.in_dir) + def test_correct_answer(self): # Given user_answer = "def add(a,b):\n\treturn a + b" @@ -159,7 +172,6 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): """) recursion_error_msg = ["Traceback", "call", - "RuntimeError", "maximum recursion depth exceeded" ] kwargs = {'user_answer': user_answer, @@ -174,7 +186,6 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): # Then self.assertFalse(result.get("success")) - self.assertEqual(969, len(err)) for msg in recursion_error_msg: self.assertIn(msg, result.get("error")) @@ -187,7 +198,6 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): type_error_msg = ["Traceback", "call", "TypeError", - "exactly", "argument" ] kwargs = {'user_answer': user_answer, @@ -238,7 +248,7 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): def test_file_based_assert(self): # Given self.test_case_data = [{"test_case": "assert(ans()=='2')"}] - self.file_paths = [(os.getcwd()+"/yaksh/test.txt", False)] + self.file_paths = [('/tmp/test.txt', False)] user_answer = dedent(""" def ans(): with open("test.txt") as f: @@ -322,65 +332,10 @@ class PythonAssertionEvaluationTestCases(unittest.TestCase): self.assertIn(msg, result.get("error")) -class PythonStdoutEvaluationTestCases(unittest.TestCase): - def setUp(self): - self.test_case_data = [{"expected_input": None, - "expected_output": "0 1 1 2 3" - }] - - self.timeout_msg = ("Code took more than {0} seconds to run. " - "You probably have an infinite loop" - " in your code.").format(SERVER_TIMEOUT) - - def test_correct_answer(self): - # Given - user_answer = "a,b=0,1\nfor i in range(5):\n\tprint a,\n\ta,b=b,a+b" - kwargs = {'user_answer': user_answer, - 'test_case_data': self.test_case_data, - } - - # When - evaluator = PythonStdioEvaluator() - result = evaluator.evaluate(**kwargs) - - # Then - self.assertEqual(result.get('error'), "Correct answer") - self.assertTrue(result.get('success')) - - def test_incorrect_answer(self): - # Given - user_answer = "a,b=0,1\nfor i in range(5):\n\tprint b,\n\ta,b=b,a+b" - kwargs = {'user_answer': user_answer, - 'test_case_data': self.test_case_data, - } - - # When - evaluator = PythonStdioEvaluator() - result = evaluator.evaluate(**kwargs) - - # Then - self.assertFalse(result.get('success')) - self.assertIn("Incorrect answer", result.get('error')) - - def test_infinite_loop(self): - # Given - user_answer = "def add(a, b):\n\twhile True:\n\t\tpass\nadd(1,2)" - kwargs = {'user_answer': user_answer, - 'test_case_data': self.test_case_data - } - - # When - evaluator = PythonStdioEvaluator() - result = evaluator.evaluate(**kwargs) - - # Then - self.assertEqual(result.get('error'), self.timeout_msg) - self.assertFalse(result.get('success')) - - class PythonStdIOEvaluationTestCases(unittest.TestCase): - def setUp(self): + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) self.file_paths = None def test_correct_answer_integer(self): @@ -389,9 +344,9 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): "expected_output": "3" }] user_answer = dedent(""" - a = input() - b = input() - print a+b + a = int(input()) + b = int(input()) + print(a+b) """ ) kwargs = {'user_answer': user_answer, @@ -408,13 +363,16 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): def test_correct_answer_list(self): # Given - self.test_case_data = [{"expected_input": "[1,2,3]\n[5,6,7]", + self.test_case_data = [{"expected_input": "1,2,3\n5,6,7", "expected_output": "[1, 2, 3, 5, 6, 7]" }] user_answer = dedent(""" - a = input() - b = input() - print a+b + from six.moves import input + input_a = input() + input_b = input() + a = [int(i) for i in input_a.split(',')] + b = [int(i) for i in input_b.split(',')] + print(a+b) """ ) kwargs = {'user_answer': user_answer, @@ -431,14 +389,14 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): def test_correct_answer_string(self): # Given - self.test_case_data = [{"expected_input": """the quick brown fox jumps\ - over the lazy dog\nthe""", + self.test_case_data = [{"expected_input": ("the quick brown fox jumps over the lazy dog\nthe"), "expected_output": "2" }] user_answer = dedent(""" - a = raw_input() - b = raw_input() - print (a.count(b)) + from six.moves import input + a = str(input()) + b = str(input()) + print(a.count(b)) """ ) kwargs = {'user_answer': user_answer, @@ -459,9 +417,9 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): "expected_output": "3" }] user_answer = dedent(""" - a = input() - b = input() - print a-b + a = int(input()) + b = int(input()) + print(a-b) """ ) kwargs = {'user_answer': user_answer, @@ -479,12 +437,12 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): def test_file_based_answer(self): # Given self.test_case_data = [{"expected_input": "", "expected_output": "2"}] - self.file_paths = [(os.getcwd()+"/yaksh/test.txt", False)] + self.file_paths = [('/tmp/test.txt', False)] user_answer = dedent(""" with open("test.txt") as f: a = f.read() - print a[0] + print(a[0]) """ ) kwargs = {'user_answer': user_answer, @@ -500,5 +458,26 @@ class PythonStdIOEvaluationTestCases(unittest.TestCase): self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) + def test_infinite_loop(self): + # Given + test_case_data = [{"expected_input": "1\n2", + "expected_output": "3" + }] + timeout_msg = ("Code took more than {0} seconds to run. " + "You probably have an infinite loop in" + " your code.").format(SERVER_TIMEOUT) + user_answer = "while True:\n\tpass" + kwargs = {'user_answer': user_answer, + 'test_case_data': test_case_data + } + + # When + evaluator = PythonStdioEvaluator() + result = evaluator.evaluate(**kwargs) + + # Then + self.assertEqual(result.get('error'), timeout_msg) + self.assertFalse(result.get('success')) + if __name__ == '__main__': unittest.main() diff --git a/yaksh/evaluator_tests/test_scilab_evaluation.py b/yaksh/evaluator_tests/test_scilab_evaluation.py index f5e3767..b366480 100644 --- a/yaksh/evaluator_tests/test_scilab_evaluation.py +++ b/yaksh/evaluator_tests/test_scilab_evaluation.py @@ -1,18 +1,26 @@ +from __future__ import unicode_literals import unittest import os +import shutil +import tempfile + from yaksh import code_evaluator as evaluator from yaksh.scilab_code_evaluator import ScilabCodeEvaluator from yaksh.settings import SERVER_TIMEOUT class ScilabEvaluationTestCases(unittest.TestCase): def setUp(self): + tmp_in_dir_path = tempfile.mkdtemp() self.test_case_data = [{"test_case": "scilab_files/test_add.sce"}] - self.in_dir = os.getcwd() + self.in_dir = tmp_in_dir_path self.timeout_msg = ("Code took more than {0} seconds to run. " "You probably have an infinite loop" " in your code.").format(SERVER_TIMEOUT) self.file_paths = None + def tearDown(self): + shutil.rmtree(self.in_dir) + def test_correct_answer(self): user_answer = ("funcprot(0)\nfunction[c]=add(a,b)" "\n\tc=a+b;\nendfunction") @@ -22,7 +30,7 @@ class ScilabEvaluationTestCases(unittest.TestCase): 'file_paths': self.file_paths } result = get_class.evaluate(**kwargs) - self.assertEquals(result.get('error'), "Correct answer") + self.assertEqual(result.get('error'), "Correct answer") self.assertTrue(result.get('success')) def test_error(self): @@ -35,7 +43,7 @@ class ScilabEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertTrue("error" in result.get("error")) + self.assertTrue('error' in result.get("error")) def test_incorrect_answer(self): @@ -47,9 +55,10 @@ class ScilabEvaluationTestCases(unittest.TestCase): 'file_paths': self.file_paths } result = get_class.evaluate(**kwargs) + lines_of_error = len(result.get('error').splitlines()) self.assertFalse(result.get('success')) self.assertIn("Message", result.get('error')) - self.assertTrue(result.get('error').splitlines > 1) + self.assertTrue(lines_of_error > 1) def test_infinite_loop(self): user_answer = ("funcprot(0)\nfunction[c]=add(a,b)" @@ -61,7 +70,7 @@ class ScilabEvaluationTestCases(unittest.TestCase): } result = get_class.evaluate(**kwargs) self.assertFalse(result.get("success")) - self.assertEquals(result.get("error"), self.timeout_msg) + self.assertEqual(result.get("error"), self.timeout_msg) if __name__ == '__main__': unittest.main() diff --git a/yaksh/forms.py b/yaksh/forms.py index 23131b7..a12ce9a 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -9,7 +9,11 @@ from taggit.managers import TaggableManager from taggit.forms import TagField from django.forms.models import inlineformset_factory from django.db.models import Q -from string import letters, punctuation, digits +try: + from string import letters +except ImportError: + from string import ascii_letters as letters +from string import punctuation, digits import datetime import pytz diff --git a/yaksh/java_code_evaluator.py b/yaksh/java_code_evaluator.py index ff76317..1ce1c0e 100644 --- a/yaksh/java_code_evaluator.py +++ b/yaksh/java_code_evaluator.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import traceback import pwd import os @@ -6,9 +7,9 @@ from os.path import join, isfile import subprocess import importlib -# local imports -from code_evaluator import CodeEvaluator -from file_utils import copy_files, delete_files +# Local imports +from .code_evaluator import CodeEvaluator +from .file_utils import copy_files, delete_files class JavaCodeEvaluator(CodeEvaluator): @@ -18,9 +19,10 @@ class JavaCodeEvaluator(CodeEvaluator): self.submit_code_path = self.create_submit_code_file('Test.java') self.compiled_user_answer = None self.compiled_test_code = None + self.user_output_path = "" + self.ref_output_path = "" def teardown(self): - super(JavaCodeEvaluator, self).teardown() # Delete the created file. os.remove(self.submit_code_path) if os.path.exists(self.user_output_path): @@ -29,6 +31,8 @@ class JavaCodeEvaluator(CodeEvaluator): os.remove(self.ref_output_path) if self.files: delete_files(self.files) + super(JavaCodeEvaluator, self).teardown() + def get_commands(self, clean_ref_code_path, user_code_directory): compile_command = 'javac {0}'.format(self.submit_code_path), diff --git a/yaksh/java_stdio_evaluator.py b/yaksh/java_stdio_evaluator.py index f4b8773..bc9cf80 100644 --- a/yaksh/java_stdio_evaluator.py +++ b/yaksh/java_stdio_evaluator.py @@ -1,11 +1,12 @@ #!/usr/bin/env python +from __future__ import unicode_literals import subprocess import os from os.path import isfile -#local imports -from stdio_evaluator import StdIOEvaluator -from file_utils import copy_files, delete_files +#Local imports +from .stdio_evaluator import StdIOEvaluator +from .file_utils import copy_files, delete_files class JavaStdioEvaluator(StdIOEvaluator): @@ -16,10 +17,10 @@ class JavaStdioEvaluator(StdIOEvaluator): self.submit_code_path = self.create_submit_code_file('Test.java') def teardown(self): - super(JavaStdioEvaluator, self).teardown() os.remove(self.submit_code_path) if self.files: delete_files(self.files) + super(JavaStdioEvaluator, self).teardown() def set_file_paths(self, directory, file_name): output_path = "{0}{1}.class".format(directory, file_name) diff --git a/yaksh/language_registry.py b/yaksh/language_registry.py index 398e1aa..0e0140b 100644 --- a/yaksh/language_registry.py +++ b/yaksh/language_registry.py @@ -1,6 +1,10 @@ -from settings import code_evaluators +from __future__ import unicode_literals import importlib import json +import six + +# Local imports +from .settings import code_evaluators registry = None @@ -24,7 +28,7 @@ def create_evaluator_instance(language, test_case_type, json_data, in_dir): class _LanguageRegistry(object): def __init__(self): self._register = {} - for language, module in code_evaluators.iteritems(): + for language, module in six.iteritems(code_evaluators): self._register[language] = None # Public Protocol ########## diff --git a/yaksh/models.py b/yaksh/models.py index 69dff6d..444df4a 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -11,7 +11,10 @@ from django.contrib.contenttypes.models import ContentType from taggit.managers import TaggableManager from django.utils import timezone from django.core.files import File -from StringIO import StringIO +try: + from StringIO import StringIO as string_io +except ImportError: + from io import BytesIO as string_io import pytz import os import stat @@ -19,7 +22,7 @@ from os.path import join, abspath, dirname, exists import shutil import zipfile import tempfile -from file_utils import extract_files +from .file_utils import extract_files from yaksh.xmlrpc_clients import code_server from django.conf import settings @@ -177,7 +180,7 @@ class Course(models.Model): success = False return success - def __unicode__(self): + def __str__(self): return self.name ############################################################################### @@ -270,7 +273,7 @@ class Question(models.Model): def dump_questions(self, question_ids, user): questions = Question.objects.filter(id__in=question_ids, user_id=user.id) questions_dict = [] - zip_file_name = StringIO() + zip_file_name = string_io() zip_file = zipfile.ZipFile(zip_file_name, "a") for question in questions: test_case = question.get_test_cases() @@ -364,7 +367,7 @@ class Question(models.Model): self.read_json("questions_dump.json", user) - def __unicode__(self): + def __str__(self): return self.summary @@ -418,7 +421,7 @@ class Answer(models.Model): else: self.marks = marks - def __unicode__(self): + def __str__(self): return self.answer @@ -540,7 +543,7 @@ class Quiz(models.Model): course=course) return demo_quiz - def __unicode__(self): + def __str__(self): desc = self.description or 'Quiz' return '%s: on %s for %d minutes' % (desc, self.start_date_time, self.duration) @@ -682,7 +685,7 @@ class QuestionPaper(models.Model): for question in questions: question_paper.fixed_questions.add(question) - def __unicode__(self): + def __str__(self): return "Question Paper for " + self.quiz.description ############################################################################### @@ -702,7 +705,7 @@ class QuestionSet(models.Model): def get_random_questions(self): """ Returns random questions from set of questions""" - return sample(self.questions.all(), self.num_questions) + return sample(list(self.questions.all()), self.num_questions) ############################################################################### @@ -1075,7 +1078,7 @@ class AnswerPaper(models.Model): self.update_marks('complete') return True, msg - def __unicode__(self): + def __str__(self): u = self.user q = self.question_paper.quiz return u'AnswerPaper paper of {0} {1} for quiz {2}'\ @@ -1099,7 +1102,7 @@ class StandardTestCase(TestCase): def get_field_value(self): return {"test_case": self.test_case} - def __unicode__(self): + def __str__(self): return u'Question: {0} | Test Case: {1}'.format(self.question, self.test_case ) @@ -1113,7 +1116,7 @@ class StdioBasedTestCase(TestCase): return {"expected_output": self.expected_output, "expected_input": self.expected_input} - def __unicode__(self): + def __str__(self): return u'Question: {0} | Exp. Output: {1} | Exp. Input: {2}'.format(self.question, self.expected_output, self.expected_input ) @@ -1126,7 +1129,7 @@ class McqTestCase(TestCase): def get_field_value(self): return {"options": self.options, "correct": self.correct} - def __unicode__(self): + def __str__(self): return u'Question: {0} | Correct: {1}'.format(self.question, self.correct ) diff --git a/yaksh/python_assertion_evaluator.py b/yaksh/python_assertion_evaluator.py index 1b66fd2..dd1c041 100644 --- a/yaksh/python_assertion_evaluator.py +++ b/yaksh/python_assertion_evaluator.py @@ -1,13 +1,14 @@ #!/usr/bin/env python +from __future__ import unicode_literals import sys import traceback import os from os.path import join import importlib -# local imports -from code_evaluator import CodeEvaluator, TimeoutException -from file_utils import copy_files, delete_files +# Local imports +from .code_evaluator import CodeEvaluator, TimeoutException +from .file_utils import copy_files, delete_files class PythonAssertionEvaluator(CodeEvaluator): @@ -18,10 +19,10 @@ class PythonAssertionEvaluator(CodeEvaluator): self.exec_scope = None def teardown(self): - super(PythonAssertionEvaluator, self).teardown() # Delete the created file. if self.files: delete_files(self.files) + super(PythonAssertionEvaluator, self).teardown() def compile_code(self, user_answer, file_paths, test_case): self.files = [] @@ -32,7 +33,7 @@ class PythonAssertionEvaluator(CodeEvaluator): else: submitted = compile(user_answer, '<string>', mode='exec') self.exec_scope = {} - exec submitted in self.exec_scope + exec(submitted, self.exec_scope) return self.exec_scope def check_code(self, user_answer, file_paths, test_case): @@ -40,7 +41,7 @@ class PythonAssertionEvaluator(CodeEvaluator): try: tb = None _tests = compile(test_case, '<string>', mode='exec') - exec _tests in self.exec_scope + exec(_tests, self.exec_scope) except AssertionError: type, value, tb = sys.exc_info() info = traceback.extract_tb(tb) diff --git a/yaksh/python_stdio_evaluator.py b/yaksh/python_stdio_evaluator.py index 2cfd9c8..cbbbfd6 100644 --- a/yaksh/python_stdio_evaluator.py +++ b/yaksh/python_stdio_evaluator.py @@ -1,16 +1,23 @@ #!/usr/bin/env python +from __future__ import unicode_literals import sys import traceback import os from os.path import join import importlib from contextlib import contextmanager -from ast import literal_eval -# local imports -from code_evaluator import CodeEvaluator -from StringIO import StringIO -from file_utils import copy_files, delete_files from textwrap import dedent + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +# Local imports +from .code_evaluator import CodeEvaluator +from .file_utils import copy_files, delete_files + + @contextmanager def redirect_stdout(): new_target = StringIO() @@ -25,10 +32,10 @@ class PythonStdioEvaluator(CodeEvaluator): """Tests the Python code obtained from Code Server""" def teardown(self): - super(PythonStdioEvaluator, self).teardown() # Delete the created file. if self.files: delete_files(self.files) + super(PythonStdioEvaluator, self).teardown() def compile_code(self, user_answer, file_paths, expected_input, expected_output): @@ -43,7 +50,7 @@ class PythonStdioEvaluator(CodeEvaluator): sys.stdin = input_buffer with redirect_stdout() as output_buffer: exec_scope = {} - exec submitted in exec_scope + exec(submitted, exec_scope) self.output_value = output_buffer.getvalue().rstrip("\n") return self.output_value diff --git a/yaksh/scilab_code_evaluator.py b/yaksh/scilab_code_evaluator.py index 53fa343..915491c 100644 --- a/yaksh/scilab_code_evaluator.py +++ b/yaksh/scilab_code_evaluator.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals import traceback import os from os.path import join, isfile @@ -6,9 +7,9 @@ import subprocess import re import importlib -# local imports -from code_evaluator import CodeEvaluator -from file_utils import copy_files, delete_files +# Local imports +from .code_evaluator import CodeEvaluator +from .file_utils import copy_files, delete_files class ScilabCodeEvaluator(CodeEvaluator): @@ -19,11 +20,11 @@ class ScilabCodeEvaluator(CodeEvaluator): self.create_submit_code_file('function.sci') def teardown(self): - super(ScilabCodeEvaluator, self).teardown() # Delete the created file. os.remove(self.submit_code_path) if self.files: delete_files(self.files) + super(ScilabCodeEvaluator, self).teardown() def check_code(self, user_answer, file_paths, test_case): self.files = [] diff --git a/yaksh/settings.py b/yaksh/settings.py index b1336f4..6383999 100644 --- a/yaksh/settings.py +++ b/yaksh/settings.py @@ -20,21 +20,21 @@ SERVER_TIMEOUT = 4 URL_ROOT = '' code_evaluators = { - "python": {"standardtestcase": "python_assertion_evaluator.PythonAssertionEvaluator", - "stdiobasedtestcase": "python_stdio_evaluator.PythonStdioEvaluator" + "python": {"standardtestcase": "yaksh.python_assertion_evaluator.PythonAssertionEvaluator", + "stdiobasedtestcase": "yaksh.python_stdio_evaluator.PythonStdioEvaluator" }, - "c": {"standardtestcase": "cpp_code_evaluator.CppCodeEvaluator", - "stdiobasedtestcase": "cpp_stdio_evaluator.CppStdioEvaluator" + "c": {"standardtestcase": "yaksh.cpp_code_evaluator.CppCodeEvaluator", + "stdiobasedtestcase": "yaksh.cpp_stdio_evaluator.CppStdioEvaluator" }, - "cpp": {"standardtestcase": "cpp_code_evaluator.CppCodeEvaluator", - "stdiobasedtestcase": "cpp_stdio_evaluator.CppStdioEvaluator" + "cpp": {"standardtestcase": "yaksh.cpp_code_evaluator.CppCodeEvaluator", + "stdiobasedtestcase": "yaksh.cpp_stdio_evaluator.CppStdioEvaluator" }, - "java": {"standardtestcase": "java_code_evaluator.JavaCodeEvaluator", - "stdiobasedtestcase": "java_stdio_evaluator.JavaStdioEvaluator"}, + "java": {"standardtestcase": "yaksh.java_code_evaluator.JavaCodeEvaluator", + "stdiobasedtestcase": "yaksh.java_stdio_evaluator.JavaStdioEvaluator"}, - "bash": {"standardtestcase": "bash_code_evaluator.BashCodeEvaluator", - "stdiobasedtestcase": "bash_stdio_evaluator.BashStdioEvaluator" + "bash": {"standardtestcase": "yaksh.bash_code_evaluator.BashCodeEvaluator", + "stdiobasedtestcase": "yaksh.bash_stdio_evaluator.BashStdioEvaluator" }, - "scilab": {"standardtestcase": "scilab_code_evaluator.ScilabCodeEvaluator"}, + "scilab": {"standardtestcase": "yaksh.scilab_code_evaluator.ScilabCodeEvaluator"}, } diff --git a/yaksh/stdio_evaluator.py b/yaksh/stdio_evaluator.py index efb2ae5..7530b96 100644 --- a/yaksh/stdio_evaluator.py +++ b/yaksh/stdio_evaluator.py @@ -1,9 +1,10 @@ +from __future__ import unicode_literals + # Local imports -from code_evaluator import CodeEvaluator +from .code_evaluator import CodeEvaluator class StdIOEvaluator(CodeEvaluator): - def setup(self): super(StdIOEvaluator, self).setup() pass @@ -15,7 +16,10 @@ class StdIOEvaluator(CodeEvaluator): def evaluate_stdio(self, user_answer, proc, expected_input, expected_output): success = False ip = expected_input.replace(",", " ") - user_output, output_err = proc.communicate(input='{0}\n'.format(ip)) + encoded_input = '{0}\n'.format(ip).encode('utf-8') + user_output_bytes, output_err_bytes = proc.communicate(encoded_input) + user_output = user_output_bytes.decode('utf-8') + output_err = output_err_bytes.decode('utf-8') expected_output = expected_output.replace("\r", "") if not expected_input: error_msg = "Expected Output is {0} ".\ @@ -30,5 +34,5 @@ class StdIOEvaluator(CodeEvaluator): err = " Incorrect answer\n" + error_msg +\ "\n Your output is {0}".format(repr(user_output)) else: - err = "Error:"+"\n"+output_err + err = "Error:\n {0}".format(output_err) return success, err diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index 5baa977..9d7b939 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -6,6 +6,7 @@ register = template.Library() @stringfilter @register.filter(name='escape_quotes') def escape_quotes(value): + value = value.decode("utf-8") escape_single_quotes = value.replace("'", "\\'") escape_single_and_double_quotes = escape_single_quotes.replace('"', '\\"') diff --git a/yaksh/test.txt b/yaksh/test.txt deleted file mode 100644 index 0cfbf08..0000000 --- a/yaksh/test.txt +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/yaksh/test_models.py b/yaksh/test_models.py index 50ead1d..019a339 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -58,6 +58,9 @@ def setUpModule(): language='Python', prerequisite=quiz, course=course) + with open('/tmp/test.txt', 'wb') as f: + f.write('2'.encode('ascii')) + def tearDownModule(): User.objects.all().delete() Question.objects.all().delete() @@ -66,7 +69,8 @@ def tearDownModule(): que_id_list = ["25", "22", "24", "27"] for que_id in que_id_list: dir_path = os.path.join(os.getcwd(), "yaksh", "data","question_{0}".format(que_id)) - shutil.rmtree(dir_path) + if os.path.exists(dir_path): + shutil.rmtree(dir_path) ############################################################################### class ProfileTestCases(unittest.TestCase): @@ -115,7 +119,7 @@ class QuestionTestCases(unittest.TestCase): self.question2.save() # create a temp directory and add files for loading questions test - file_path = os.path.join(os.getcwd(), "yaksh", "test.txt") + file_path = "/tmp/test.txt" self.load_tmp_path = tempfile.mkdtemp() shutil.copy(file_path, self.load_tmp_path) file1 = os.path.join(self.load_tmp_path, "test.txt") @@ -164,7 +168,8 @@ class QuestionTestCases(unittest.TestCase): tag_list = [] for tag in self.question1.tags.all(): tag_list.append(tag.name) - self.assertEqual(tag_list, ['python', 'function']) + for tag in tag_list: + self.assertIn(tag, ['python', 'function']) def test_dump_questions(self): """ Test dump questions into json """ @@ -714,7 +719,7 @@ class AnswerPaperTestCases(unittest.TestCase): def test_get_question_answer(self): """ Test get_question_answer() method of Answer Paper""" answered = self.answerpaper.get_question_answers() - first_answer = answered.values()[0][0] + first_answer = list(answered.values())[0][0] self.assertEqual(first_answer.answer, 'Demo answer') self.assertTrue(first_answer.correct) self.assertEqual(len(answered), 2) @@ -895,4 +900,7 @@ class TestCaseTestCases(unittest.TestCase): result = self.question1.consolidate_answer_data( user_answer="demo_answer" ) - self.assertEqual(result, self.answer_data_json) + actual_data = json.loads(result) + exp_data = json.loads(self.answer_data_json) + self.assertEqual(actual_data['user_answer'], exp_data['user_answer']) + self.assertEqual(actual_data['test_case_data'], exp_data['test_case_data']) diff --git a/yaksh/tests/test_code_server.py b/yaksh/tests/test_code_server.py index a73f073..8835110 100644 --- a/yaksh/tests/test_code_server.py +++ b/yaksh/tests/test_code_server.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals import json try: from Queue import Queue @@ -5,7 +6,7 @@ except ImportError: from queue import Queue from threading import Thread import unittest -import urllib +from six.moves import urllib from yaksh.code_server import ServerPool, SERVER_POOL_PORT from yaksh import settings @@ -18,7 +19,7 @@ class TestCodeServer(unittest.TestCase): def setUpClass(cls): settings.code_evaluators['python']['standardtestcase'] = \ "yaksh.python_assertion_evaluator.PythonAssertionEvaluator" - ports = range(8001, 8006) + ports = range(8001, 8006) server_pool = ServerPool(ports=ports, pool_port=SERVER_POOL_PORT) cls.server_pool = server_pool cls.server_thread = t = Thread(target=server_pool.run) @@ -117,7 +118,8 @@ class TestCodeServer(unittest.TestCase): url = "http://localhost:%s/status"%SERVER_POOL_PORT # When - data = urllib.urlopen(url).read() + response = urllib.request.urlopen(url) + data = response.read().decode('utf-8') # Then expect = 'out of 5 are free' diff --git a/yaksh/views.py b/yaksh/views.py index 4c5b9b8..0ed5f5a 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -21,6 +21,7 @@ from taggit.models import Tag from itertools import chain import json import zipfile +import six # Local imports. from yaksh.models import get_model_class, Quiz, Question, QuestionPaper, QuestionSet, Course from yaksh.models import Profile, Answer, AnswerPaper, User, TestCase, FileUpload,\ @@ -29,9 +30,9 @@ from yaksh.forms import UserRegisterForm, UserLoginForm, QuizForm,\ QuestionForm, RandomQuestionForm,\ QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm,\ get_object_form, FileForm -from settings import URL_ROOT +from .settings import URL_ROOT from yaksh.models import AssignmentUpload -from file_utils import extract_files +from .file_utils import extract_files @@ -982,7 +983,7 @@ def grade_user(request, quiz_id=None, user_id=None, attempt_number=None): if request.method == "POST": papers = data['papers'] for paper in papers: - for question, answers in paper.get_question_answers().iteritems(): + for question, answers in six.iteritems(paper.get_question_answers()): marks = float(request.POST.get('q%d_marks' % question.id, 0)) answers = answers[-1] answers.set_marks(marks) diff --git a/yaksh/xmlrpc_clients.py b/yaksh/xmlrpc_clients.py index 6bfe0d6..4da70dd 100644 --- a/yaksh/xmlrpc_clients.py +++ b/yaksh/xmlrpc_clients.py @@ -1,11 +1,19 @@ -from xmlrpclib import ServerProxy +from __future__ import unicode_literals import time import random import socket import json import urllib +from six.moves import urllib -from settings import SERVER_PORTS, SERVER_POOL_PORT +try: + from xmlrpclib import ServerProxy +except ImportError: + # The above import will not work on Python-3.x. + from xmlrpc.client import ServerProxy + +# Local imports +from .settings import SERVER_PORTS, SERVER_POOL_PORT class ConnectionError(Exception): @@ -58,7 +66,8 @@ class CodeServerProxy(object): return result def _get_server(self): - port = json.loads(urllib.urlopen(self.pool_url).read()) + response = urllib.request.urlopen(self.pool_url) + port = json.loads(response.read().decode('utf-8')) proxy = ServerProxy('http://localhost:%d' % port) return proxy |