Commit 47e47303 by Will Daly

Refactored CustomResponse to use the same private

func to handle all errors related to execution of
python code.

CustomResponse now returns subclasses of Exception
instead of general Exceptions

CustomResponse no longer includes tracebacks
in the exceptions it raises (and shows to students)
parent c370bb6a
......@@ -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")
#-----------------------------------------------------------------------------
......
......@@ -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'})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment