Skip to content
Snippets Groups Projects
Unverified Commit 204a0827 authored by Peter Pinch's avatar Peter Pinch Committed by GitHub
Browse files

Merge pull request #18158 from mitodl/pdpinch/undefined-var-error

More descriptive error messages for UndefinedVariable
parents 89963efd b43f2242
No related branches found
No related tags found
No related merge requests found
...@@ -458,11 +458,45 @@ class ParseAugmenter(object): ...@@ -458,11 +458,45 @@ class ParseAugmenter(object):
else: else:
casify = lambda x: x.lower() # Lowercase for case insens. casify = lambda x: x.lower() # Lowercase for case insens.
# Test if casify(X) is valid, but return the actual bad input (i.e. X)
bad_vars = set(var for var in self.variables_used bad_vars = set(var for var in self.variables_used
if casify(var) not in valid_variables) if casify(var) not in valid_variables)
bad_vars.update(func for func in self.functions_used
if casify(func) not in valid_functions)
if bad_vars: if bad_vars:
raise UndefinedVariable(' '.join(sorted(bad_vars))) varnames = ", ".join(sorted(bad_vars))
message = "Invalid Input: {} not permitted in answer as a variable".format(varnames)
# Check to see if there is a different case version of the variables
caselist = set()
if self.case_sensitive:
for var2 in bad_vars:
for var1 in valid_variables:
if var2.lower() == var1.lower():
caselist.add(var1)
if len(caselist) > 0:
betternames = ', '.join(sorted(caselist))
message += " (did you mean " + betternames + "?)"
raise UndefinedVariable(message)
bad_funcs = set(func for func in self.functions_used
if casify(func) not in valid_functions)
if bad_funcs:
funcnames = ', '.join(sorted(bad_funcs))
message = "Invalid Input: {} not permitted in answer as a function".format(funcnames)
# Check to see if there is a corresponding variable name
if any(casify(func) in valid_variables for func in bad_funcs):
message += " (did you forget to use * for multiplication?)"
# Check to see if there is a different case version of the function
caselist = set()
if self.case_sensitive:
for func2 in bad_funcs:
for func1 in valid_functions:
if func2.lower() == func1.lower():
caselist.add(func1)
if len(caselist) > 0:
betternames = ', '.join(sorted(caselist))
message += " (did you mean " + betternames + "?)"
raise UndefinedVariable(message)
...@@ -541,8 +541,10 @@ class EvaluatorTest(unittest.TestCase): ...@@ -541,8 +541,10 @@ class EvaluatorTest(unittest.TestCase):
calc.evaluator({}, {}, "5+7*QWSEKO") calc.evaluator({}, {}, "5+7*QWSEKO")
with self.assertRaisesRegexp(calc.UndefinedVariable, 'r2'): with self.assertRaisesRegexp(calc.UndefinedVariable, 'r2'):
calc.evaluator({'r1': 5}, {}, "r1+r2") calc.evaluator({'r1': 5}, {}, "r1+r2")
with self.assertRaisesRegexp(calc.UndefinedVariable, 'r1 r3'): with self.assertRaisesRegexp(calc.UndefinedVariable, 'r1, r3'):
calc.evaluator(variables, {}, "r1*r3", case_sensitive=True) calc.evaluator(variables, {}, "r1*r3", case_sensitive=True)
with self.assertRaisesRegexp(calc.UndefinedVariable, 'did you forget to use \*'):
calc.evaluator(variables, {}, "R1(R3 + 1)")
def test_mismatched_parens(self): def test_mismatched_parens(self):
""" """
......
...@@ -1598,11 +1598,9 @@ class NumericalResponse(LoncapaResponse): ...@@ -1598,11 +1598,9 @@ class NumericalResponse(LoncapaResponse):
# Catch a bunch of exceptions and give nicer messages to the student. # Catch a bunch of exceptions and give nicer messages to the student.
try: try:
student_float = evaluator({}, {}, student_answer) student_float = evaluator({}, {}, student_answer)
except UndefinedVariable as undef_var: except UndefinedVariable as err:
raise StudentInputError( raise StudentInputError(
_(u"You may not use variables ({bad_variables}) in numerical problems.").format( err.args[0]
bad_variables=text_type(undef_var),
)
) )
except UnmatchedParenthesis as err: except UnmatchedParenthesis as err:
raise StudentInputError( raise StudentInputError(
...@@ -3110,7 +3108,7 @@ class FormulaResponse(LoncapaResponse): ...@@ -3110,7 +3108,7 @@ class FormulaResponse(LoncapaResponse):
cgi.escape(answer) cgi.escape(answer)
) )
raise StudentInputError( raise StudentInputError(
_("Invalid input: {bad_input} not permitted in answer.").format(bad_input=text_type(err)) err.args[0]
) )
except UnmatchedParenthesis as err: except UnmatchedParenthesis as err:
log.debug( log.debug(
......
...@@ -1625,7 +1625,8 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-docstring ...@@ -1625,7 +1625,8 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-docstring
problem = self.build_problem(answer=4) problem = self.build_problem(answer=4)
errors = [ # (exception raised, message to student) errors = [ # (exception raised, message to student)
(calc.UndefinedVariable("x"), r"You may not use variables \(x\) in numerical problems"), (calc.UndefinedVariable("Invalid Input: x not permitted in answer as a variable"),
r"Invalid Input: x not permitted in answer as a variable"),
(ValueError("factorial() mess-up"), "Factorial function evaluated outside its domain"), (ValueError("factorial() mess-up"), "Factorial function evaluated outside its domain"),
(ValueError(), "Could not interpret '.*' as a number"), (ValueError(), "Could not interpret '.*' as a number"),
(pyparsing.ParseException("oopsie"), "Invalid math syntax"), (pyparsing.ParseException("oopsie"), "Invalid math syntax"),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment