def test(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') weight = pl.get_integer_attrib(element, 'weight', 1) result = random.choices(['correct', 'incorrect', 'invalid'], [5, 5, 1])[0] if result == 'correct': data['raw_submitted_answers'][name] = str(pl.from_json(data['correct_answers'][name])) data['partial_scores'][name] = {'score': 1, 'weight': weight} elif result == 'incorrect': data['raw_submitted_answers'][name] = str(pl.from_json(data['correct_answers'][name])) + ' + {:d}'.format(random.randint(1, 100)) data['partial_scores'][name] = {'score': 0, 'weight': weight} elif result == 'invalid': invalid_type = random.choice(['float', 'complex', 'expression', 'function', 'variable', 'syntax', 'escape', 'comment']) if invalid_type == 'float': data['raw_submitted_answers'][name] = 'x + 1.234' s = 'Your answer contains the floating-point number ' + str(1.234) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error('x + 1.234', 4) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'complex': data['raw_submitted_answers'][name] = 'x + (1+2j)' s = 'Your answer contains the complex number ' + str(2j) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error('x + (1+2j)', 7) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'expression': data['raw_submitted_answers'][name] = '1 and 0' s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error('1 and 0', 0) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'function': data['raw_submitted_answers'][name] = 'atan(x)' s = 'Your answer calls an invalid function "' + 'atan' + '". ' s += '<br><br><pre>' + phs.point_to_error('atan(x)', 0) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'variable': data['raw_submitted_answers'][name] = 'x + y' s = 'Your answer refers to an invalid variable "' + 'y' + '". ' s += '<br><br><pre>' + phs.point_to_error('x + y', 4) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'syntax': data['raw_submitted_answers'][name] = 'x +* 1' s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error('x +* 1', 4) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'escape': data['raw_submitted_answers'][name] = 'x + 1\\n' s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error('x + 1\\n', 5) + '</pre>' data['format_errors'][name] = s elif invalid_type == 'comment': data['raw_submitted_answers'][name] = 'x # some text' s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error('x # some text', 2) + '</pre>' data['format_errors'][name] = s else: raise Exception('invalid invalid_type: %s' % invalid_type) else: raise Exception('invalid result: %s' % result)
def parse(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list(pl.get_string_attrib(element, 'variables', None)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i') # Get submitted answer or return parse_error if it does not exist a_sub = data['submitted_answers'].get(name, None) if not a_sub: data['format_errors'][name] = 'No submitted answer.' data['submitted_answers'][name] = None return # Parse the submitted answer and put the result in a string try: # Replace '^' with '**' wherever it appears. In MATLAB, either can be used # for exponentiation. In python, only the latter can be used. a_sub = a_sub.replace('^', '**') # Strip whitespace a_sub = a_sub.strip() # Convert safely to sympy a_sub_parsed = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) # If complex numbers are not allowed, raise error if expression has the imaginary unit if (not allow_complex) and (a_sub_parsed.has(sympy.I)): a_sub_parsed = a_sub_parsed.subs(sympy.I, sympy.Symbol(imaginary_unit)) s = 'Your answer was simplified to this, which contains a complex number (denoted ${:s}$): $${:s}$$'.format(imaginary_unit, sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None return # Store result as json. a_sub_json = phs.sympy_to_json(a_sub_parsed, allow_complex=allow_complex) except phs.HasFloatError as err: s = 'Your answer contains the floating-point number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasComplexError as err: s = 'Your answer contains the complex number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' if allow_complex: s += 'To include a complex number in your expression, write it as the product of an integer with the imaginary unit <code>i</code> or <code>j</code>. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidExpressionError as err: s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidFunctionError as err: s = 'Your answer calls an invalid function "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidVariableError as err: s = 'Your answer refers to an invalid variable "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasParseError as err: s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasEscapeError as err: s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasCommentError as err: s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except Exception as err: data['format_errors'][name] = 'Invalid format.' data['submitted_answers'][name] = None return # Make sure we can parse the json again try: # Convert safely to sympy phs.json_to_sympy(a_sub_json, allow_complex=allow_complex) # Finally, store the result data['submitted_answers'][name] = a_sub_json except Exception as err: s = 'Your answer was simplified to this, which contains an invalid expression: $${:s}$$'.format(sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None
def parse(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') variables = get_variables_list(pl.get_string_attrib(element, 'variables', None)) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i') # Get submitted answer or return parse_error if it does not exist a_sub = data['submitted_answers'].get(name, None) if not a_sub: data['format_errors'][name] = 'No submitted answer.' data['submitted_answers'][name] = None return # Parse the submitted answer and put the result in a string try: # Replace '^' with '**' wherever it appears. In MATLAB, either can be used # for exponentiation. In python, only the latter can be used. a_sub = a_sub.replace('^', '**') # Strip whitespace a_sub = a_sub.strip() # Convert safely to sympy a_sub_parsed = phs.convert_string_to_sympy(a_sub, variables, allow_complex=allow_complex) # If complex numbers are not allowed, raise error if expression has the imaginary unit if (not allow_complex) and (a_sub_parsed.has(sympy.I)): a_sub_parsed = a_sub_parsed.subs(sympy.I, sympy.Symbol(imaginary_unit)) s = 'Your answer was simplified to this, which contains a complex number (denoted ${:s}$): $${:s}$$'.format(imaginary_unit, sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None return # Store result as json. a_sub_json = phs.sympy_to_json(a_sub_parsed, allow_complex=allow_complex) except phs.HasFloatError as err: s = 'Your answer contains the floating-point number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasComplexError as err: s = 'Your answer contains the complex number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' if allow_complex: s += 'To include a complex number in your expression, write it as the product of an integer with the imaginary unit <code>i</code> or <code>j</code>. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidExpressionError as err: s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidFunctionError as err: s = 'Your answer calls an invalid function "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasInvalidVariableError as err: s = 'Your answer refers to an invalid variable "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasParseError as err: s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasEscapeError as err: s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except phs.HasCommentError as err: s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None return except Exception: data['format_errors'][name] = 'Invalid format.' data['submitted_answers'][name] = None return # Make sure we can parse the json again try: # Convert safely to sympy phs.json_to_sympy(a_sub_json, allow_complex=allow_complex) # Finally, store the result data['submitted_answers'][name] = a_sub_json except Exception: s = 'Your answer was simplified to this, which contains an invalid expression: $${:s}$$'.format(sympy.latex(a_sub_parsed)) data['format_errors'][name] = s data['submitted_answers'][name] = None
def parse(element_html, element_index, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers_name') variables = get_variables_list( pl.get_string_attrib(element, 'variables', None)) # Get submitted answer or return parse_error if it does not exist a_sub = data['submitted_answers'].get(name, None) if not a_sub: data['format_errors'][name] = 'No submitted answer.' data['submitted_answers'][name] = None return try: # Replace '^' with '**' wherever it appears. In MATLAB, either can be used # for exponentiation. In python, only the latter can be used. a_sub = a_sub.replace('^', '**') # Strip whitespace a_sub = a_sub.strip() # Convert safely to sympy a_sub = phs.convert_string_to_sympy(a_sub, variables) # Store result as a string. data['submitted_answers'][name] = str(a_sub) except phs.HasFloatError as err: s = 'Your answer contains the floating-point number ' + str( err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasComplexError as err: s = 'Your answer contains the complex number ' + str(err.n) + '. ' s += 'All numbers must be expressed as integers (or ratios of integers). ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasInvalidExpressionError as err: s = 'Your answer has an invalid expression. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasInvalidFunctionError as err: s = 'Your answer calls an invalid function "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasInvalidVariableError as err: s = 'Your answer refers to an invalid variable "' + err.text + '". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasParseError as err: s = 'Your answer has a syntax error. ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasEscapeError as err: s = 'Your answer must not contain the character "\\". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except phs.HasCommentError as err: s = 'Your answer must not contain the character "#". ' s += '<br><br><pre>' + phs.point_to_error(a_sub, err.offset) + '</pre>' data['format_errors'][name] = s data['submitted_answers'][name] = None except Exception as err: data['format_errors'][name] = 'Invalid format.' data['submitted_answers'][name] = None