diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 8ab716735c..a69c26572d 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -1072,13 +1072,11 @@ def sympy_check2(): correct = self.context['correct'] messages = self.context['messages'] overall_message = self.context['overall_message'] + except Exception as err: - print "oops in customresponse (code) error %s" % err - print "context = ", self.context - print traceback.format_exc() - # Notify student - raise StudentInputError( - "Error: Problem could not be evaluated with your input") + self._handle_exec_exception(err) + pass + else: # self.code is not a string; assume its a function @@ -1105,13 +1103,9 @@ def sympy_check2(): nargs, args, kwargs)) ret = fn(*args[:nargs], **kwargs) + except Exception as err: - log.error("oops in customresponse (cfn) error %s" % err) - # print "context = ",self.context - log.error(traceback.format_exc()) - raise Exception("oops in customresponse (cfn) error %s" % err) - log.debug( - "[courseware.capa.responsetypes.customresponse.get_score] ret = %s" % ret) + self._handle_exec_exception(err) if type(ret) == dict: @@ -1157,7 +1151,7 @@ def sympy_check2(): # Raise an exception else: log.error(traceback.format_exc()) - raise Exception( + raise LoncapaProblemError( "CustomResponse: check function returned an invalid dict") # The check function can return a boolean value, @@ -1227,6 +1221,23 @@ def sympy_check2(): return {self.answer_ids[0]: self.expect} return self.default_answer_map + def _handle_exec_exception(self, err): + ''' + Handle an exception raised during the execution of + custom Python code. + + Raises a StudentInputError + ''' + + # Log the error if we are debugging + msg = 'Error occurred while evaluating CustomResponse: %s' % str(err) + log.debug(msg) + log.debug(traceback.format_exc()) + + # Notify student + raise StudentInputError( + "Error: Problem could not be evaluated with your input") + #----------------------------------------------------------------------------- diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index 0c007f83b2..ac50e6defc 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -13,6 +13,7 @@ import textwrap from . import test_system import capa.capa_problem as lcp +from capa.responsetypes import LoncapaProblemError, StudentInputError from capa.correctmap import CorrectMap from capa.util import convert_files_to_filenames from capa.xqueue_interface import dateformat @@ -853,7 +854,7 @@ class CustomResponseTest(ResponseTest): # Message is interpreted as an "overall message" self.assertEqual(correct_map.get_overall_message(), 'Message text') - def test_script_exception(self): + def test_script_exception_function(self): # Construct a script that will raise an exception script = textwrap.dedent(""" @@ -864,7 +865,17 @@ class CustomResponseTest(ResponseTest): problem = self.build_problem(script=script, cfn="check_func") # Expect that an exception gets raised when we check the answer - with self.assertRaises(Exception): + with self.assertRaises(StudentInputError): + problem.grade_answers({'1_2_1': '42'}) + + def test_script_exception_inline(self): + + # Construct a script that will raise an exception + script = 'raise Exception("Test")' + problem = self.build_problem(answer=script) + + # Expect that an exception gets raised when we check the answer + with self.assertRaises(StudentInputError): problem.grade_answers({'1_2_1': '42'}) def test_invalid_dict_exception(self): @@ -878,7 +889,7 @@ class CustomResponseTest(ResponseTest): problem = self.build_problem(script=script, cfn="check_func") # Expect that an exception gets raised when we check the answer - with self.assertRaises(Exception): + with self.assertRaises(LoncapaProblemError): problem.grade_answers({'1_2_1': '42'})