def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', LABEL_DEFAULT) suffix = pl.get_string_attrib(element, 'suffix', SUFFIX_DEFAULT) display = pl.get_string_attrib(element, 'display', DISPLAY_DEFAULT) remove_leading_trailing = pl.get_string_attrib( element, 'remove-leading-trailing', REMOVE_LEADING_TRAILING_DEFAULT) remove_spaces = pl.get_string_attrib(element, 'remove-spaces', REMOVE_SPACES_DEFAULT) placeholder = pl.get_string_attrib(element, 'placeholder', PLACEHOLDER_DEFAULT) if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) if remove_leading_trailing: if remove_spaces: space_hint = 'All spaces will be removed from your answer.' else: space_hint = 'Leading and trailing spaces will be removed from your answer.' else: if remove_spaces: space_hint = 'All spaces between text will be removed but leading and trailing spaces will be left as part of your answer.' else: space_hint = 'Leading and trailing spaces will be left as part of your answer.' # Get info strings info_params = {'format': True, 'space_hint': space_hint} with open('pl-string-input.mustache', 'r', encoding='utf-8') as f: template = f.read() info = chevron.render(template, info_params).strip() info_params.pop('format', None) html_params = { 'question': True, 'name': name, 'label': label, 'suffix': suffix, 'remove-leading-trailing': remove_leading_trailing, 'remove-spaces': remove_spaces, 'editable': editable, 'info': info, 'placeholder': placeholder, 'uuid': pl.get_uuid() } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-string-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: # Get submitted answer, raising an exception if it does not exist a_sub = data['submitted_answers'].get(name, None) if a_sub is None: raise Exception('submitted answer is None') # If answer is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) a_sub = pl.from_json(a_sub) a_sub = pl.escape_unicode_string(a_sub) html_params['suffix'] = suffix html_params['a_sub'] = a_sub elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: raw_submitted_answer = data['raw_submitted_answers'].get( name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-string-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': a_tru = pl.from_json(data['correct_answers'].get(name, None)) if a_tru is not None: html_params = { 'answer': True, 'label': label, 'a_tru': a_tru, 'suffix': suffix } with open('pl-string-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', LABEL_DEFAULT) variables_string = pl.get_string_attrib(element, 'variables', VARIABLES_DEFAULT) variables = get_variables_list(variables_string) display = pl.get_string_attrib(element, 'display', DISPLAY_DEFAULT) allow_complex = pl.get_boolean_attrib(element, 'allow-complex', ALLOW_COMPLEX_DEFAULT) imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', IMAGINARY_UNIT_FOR_DISPLAY_DEFAULT) size = pl.get_integer_attrib(element, 'size', SIZE_DEFAULT) operators = [ 'cos', 'sin', 'tan', 'exp', 'log', 'sqrt', '( )', '+', '-', '*', '/', '^', '**' ] constants = ['pi', 'e'] if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) info_params = { 'format': True, 'variables': variables, 'operators': operators, 'constants': constants, 'allow_complex': allow_complex, } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) info_params['shortformat'] = True shortinfo = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'label': label, 'editable': editable, 'info': info, 'shortinfo': shortinfo, 'size': size, 'show_info': pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT), 'uuid': pl.get_uuid(), 'allow_complex': allow_complex, 'show_placeholder': size >= PLACEHOLDER_TEXT_THRESHOLD } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: a_sub = data['submitted_answers'][name] if isinstance(a_sub, str): # this is for backward-compatibility a_sub = phs.convert_string_to_sympy( a_sub, variables, allow_complex=allow_complex) else: a_sub = phs.json_to_sympy(a_sub, allow_complex=allow_complex) a_sub = a_sub.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params['a_sub'] = sympy.latex(a_sub) elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: # Use the existing format text in the invalid popup. info_params = { 'format': True, 'variables': variables, 'operators': operators, 'constants': constants, 'allow_complex': allow_complex, } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() # Render invalid popup raw_submitted_answer = data['raw_submitted_answers'].get( name, None) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: parse_error += chevron.render(f, { 'format_error': True, 'format_string': info }).strip() html_params['parse_error'] = parse_error if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': a_tru = data['correct_answers'].get(name, None) if a_tru is not None: if isinstance(a_tru, str): # this is so instructors can specify the true answer simply as a string a_tru = phs.convert_string_to_sympy( a_tru, variables, allow_complex=allow_complex) else: a_tru = phs.json_to_sympy(a_tru, allow_complex=allow_complex) a_tru = a_tru.subs(sympy.I, sympy.Symbol(imaginary_unit)) html_params = { 'answer': True, 'label': label, 'a_tru': sympy.latex(a_tru) } with open('pl-symbolic-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', LABEL_DEFAULT) if '_pl_matrix_input_format' in data['submitted_answers']: format_type = data['submitted_answers']['_pl_matrix_input_format'].get( name, 'matlab') else: format_type = 'matlab' if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) # Get comparison parameters and info strings comparison = pl.get_string_attrib(element, 'comparison', COMPARISON_DEFAULT) if comparison == 'relabs': rtol = pl.get_float_attrib(element, 'rtol', RTOL_DEFAULT) atol = pl.get_float_attrib(element, 'atol', ATOL_DEFAULT) if (rtol < 0): raise ValueError( 'Attribute rtol = {:g} must be non-negative'.format(rtol)) if (atol < 0): raise ValueError( 'Attribute atol = {:g} must be non-negative'.format(atol)) info_params = { 'format': True, 'relabs': True, 'rtol': '{:g}'.format(rtol), 'atol': '{:g}'.format(atol) } elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) if (digits < 0): raise ValueError( 'Attribute digits = {:d} must be non-negative'.format( digits)) info_params = { 'format': True, 'sigfig': True, 'digits': '{:d}'.format(digits), 'comparison_eps': 0.51 * (10**-(digits - 1)) } elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) if (digits < 0): raise ValueError( 'Attribute digits = {:d} must be non-negative'.format( digits)) info_params = { 'format': True, 'decdig': True, 'digits': '{:d}'.format(digits), 'comparison_eps': 0.51 * (10**-(digits - 0)) } else: raise ValueError( 'method of comparison "%s" is not valid (must be "relabs", "sigfig", or "decdig")' % comparison) info_params['allow_complex'] = pl.get_boolean_attrib( element, 'allow-complex', ALLOW_COMPLEX_DEFAULT) with open('pl-matrix-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-matrix-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) info_params['shortformat'] = True shortinfo = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'label': label, 'editable': editable, 'info': info, 'shortinfo': shortinfo, 'show_info': pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT), 'uuid': pl.get_uuid() } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) with open('pl-matrix-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: # Get submitted answer, raising an exception if it does not exist a_sub = data['submitted_answers'].get(name, None) if a_sub is None: raise Exception('submitted answer is None') # If answer is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) a_sub = pl.from_json(a_sub) # Wrap answer in an ndarray (if it's already one, this does nothing) a_sub = np.array(a_sub) # Format answer as a string html_params['a_sub'] = pl.string_from_2darray( a_sub, language=format_type, digits=12, presentation_type='g') elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: raw_submitted_answer = data['raw_submitted_answers'].get( name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-matrix-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': # Get true answer - do nothing if it does not exist a_tru = pl.from_json(data['correct_answers'].get(name, None)) if a_tru is not None: a_tru = np.array(a_tru) # Get comparison parameters comparison = pl.get_string_attrib(element, 'comparison', COMPARISON_DEFAULT) if comparison == 'relabs': rtol = pl.get_float_attrib(element, 'rtol', RTOL_DEFAULT) atol = pl.get_float_attrib(element, 'atol', ATOL_DEFAULT) # FIXME: render correctly with respect to rtol and atol matlab_data = pl.string_from_2darray(a_tru, language='matlab', digits=12, presentation_type='g') python_data = pl.string_from_2darray(a_tru, language='python', digits=12, presentation_type='g') elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) matlab_data = pl.string_from_2darray( a_tru, language='matlab', digits=digits, presentation_type='sigfig') python_data = pl.string_from_2darray( a_tru, language='python', digits=digits, presentation_type='sigfig') elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) matlab_data = pl.string_from_2darray(a_tru, language='matlab', digits=digits, presentation_type='f') python_data = pl.string_from_2darray(a_tru, language='python', digits=digits, presentation_type='f') else: raise ValueError( 'method of comparison "%s" is not valid (must be "relabs", "sigfig", or "decdig")' % comparison) html_params = { 'answer': True, 'label': label, 'matlab_data': matlab_data, 'python_data': python_data, 'uuid': pl.get_uuid() } if format_type == 'matlab': html_params['default_is_matlab'] = True else: html_params['default_is_python'] = True with open('pl-matrix-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def createTableForHTMLDisplay(m, n, name, label, data, format): editable = data['editable'] if format == 'output-invalid': display_array = '<table>' display_array += '<tr>' display_array += '<td class="close-left" rowspan="' + str( m) + '"></td>' display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' # First row of array for j in range(n): each_entry_name = name + str(j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) format_errors = data['format_errors'].get(each_entry_name, None) if format_errors is None: display_array += '<td class="allborder"><code class="user-output">' else: display_array += '<td class="allborder"><code class="user-output-invalid">' display_array += escape( pl.escape_unicode_string(raw_submitted_answer)) display_array += '</code></td> ' display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' display_array += '<td class="close-right" rowspan="' + str( m) + '"></td>' # Add the other rows for i in range(1, m): display_array += ' <tr>' for j in range(n): each_entry_name = name + str(n * i + j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) format_errors = data['format_errors'].get( each_entry_name, None) if format_errors is None: display_array += '<td class="allborder"><code class="user-output">' else: display_array += '<td class="allborder"><code class="user-output-invalid">' display_array += escape( pl.escape_unicode_string(raw_submitted_answer)) display_array += '</code></td> ' display_array += '</tr>' display_array += '</table>' elif format == 'output-feedback': partial_score_feedback = data['partial_scores'].get( name, {'feedback': None}) feedback_each_entry = partial_score_feedback.get('feedback', None) score = partial_score_feedback.get('score', None) if score is not None: score = float(score) if score >= 1: score_message = ' <span class="badge badge-success"><i class="fa fa-check" aria-hidden="true"></i> 100%</span>' elif score > 0: score_message = ' <span class="badge badge-warning"><i class="far fa-circle" aria-hidden="true"></i>' + str( math.floor(score * 100)) + '%</span>' else: score_message = ' <span class="badge badge-danger"><i class="fa fa-times" aria-hidden="true"></i> 0%</span>' else: score_message = '' display_array = '<table>' display_array += '<tr>' # Add the prefix if label is not None: display_array += '<td rowspan="0">' + label + ' </td>' display_array += '<td class="close-left" rowspan="' + str( m) + '"></td>' display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' # First row of array for j in range(n): each_entry_name = name + str(j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) display_array += '<td class="allborder">' display_array += escape(raw_submitted_answer) if feedback_each_entry is not None: if feedback_each_entry[each_entry_name] == 'correct': feedback_message = ' <span class="badge badge-success"><i class="fa fa-check" aria-hidden="true"></i></span>' elif feedback_each_entry[each_entry_name] == 'incorrect': feedback_message = ' <span class="badge badge-danger"><i class="fa fa-times" aria-hidden="true"></i></span>' display_array += feedback_message display_array += '</td> ' # Add the suffix display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' display_array += '<td class="close-right" rowspan="' + str( m) + '"></td>' if score_message is not None: display_array += '<td rowspan="0"> ' + score_message + '</td>' display_array += '</tr>' # Add the other rows for i in range(1, m): display_array += ' <tr>' for j in range(n): each_entry_name = name + str(n * i + j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) display_array += ' <td class="allborder"> ' display_array += escape(raw_submitted_answer) if feedback_each_entry is not None: if feedback_each_entry[each_entry_name] == 'correct': feedback_message = ' <span class="badge badge-success"><i class="fa fa-check" aria-hidden="true"></i></span>' elif feedback_each_entry[each_entry_name] == 'incorrect': feedback_message = ' <span class="badge badge-danger"><i class="fa fa-times" aria-hidden="true"></i></span>' display_array += feedback_message display_array += ' </td> ' display_array += '</tr>' display_array += '</table>' elif format == 'input': display_array = '<table>' display_array += '<tr>' # Add first row display_array += '<td class="close-left" rowspan="' + str( m) + '"></td>' display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' for j in range(n): each_entry_name = name + str(j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) display_array += ' <td> <input name= "' + each_entry_name + '" type="text" size="8" ' if not editable: display_array += ' disabled ' if raw_submitted_answer is not None: display_array += ' value= "' display_array += escape(raw_submitted_answer) display_array += '" /> </td>' display_array += '<td style="width:4px" rowspan="' + str(m) + '"></td>' display_array += '<td class="close-right" rowspan="' + str( m) + '"></td>' # Add other rows for i in range(1, m): display_array += ' <tr>' for j in range(n): each_entry_name = name + str(n * i + j + 1) raw_submitted_answer = data['raw_submitted_answers'].get( each_entry_name, None) display_array += ' <td> <input name= "' + each_entry_name + '" type="text" size="8" ' if not editable: display_array += ' disabled ' if raw_submitted_answer is not None: display_array += ' value= "' display_array += escape(raw_submitted_answer) display_array += '" /> </td>' display_array += ' </td> ' display_array += '</tr>' display_array += '</table>' else: display_array = '' return display_array
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', LABEL_DEFAULT) suffix = pl.get_string_attrib(element, 'suffix', SUFFIX_DEFAULT) display = pl.get_string_attrib(element, 'display', DISPLAY_DEFAULT) size = pl.get_integer_attrib(element, 'size', SIZE_DEFAULT) if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) # Get info strings info_params = {'format': True} with open('pl-integer-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-integer-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) info_params['shortformat'] = True shortinfo = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'label': label, 'suffix': suffix, 'editable': editable, 'info': info, 'shortinfo': shortinfo, 'size': size, 'show_info': pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT), 'show_placeholder': size >= PLACEHOLDER_TEXT_THRESHOLD, 'uuid': pl.get_uuid() } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) html_params['display_append_span'] = html_params['show_info'] or suffix if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-integer-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: # Get submitted answer, raising an exception if it does not exist a_sub = data['submitted_answers'].get(name, None) if a_sub is None: raise Exception('submitted answer is None') # If answer is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) a_sub = pl.from_json(a_sub) html_params['suffix'] = suffix html_params['a_sub'] = '{:d}'.format(a_sub) elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: raw_submitted_answer = data['raw_submitted_answers'].get( name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-integer-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': a_tru = pl.from_json(data['correct_answers'].get(name, None)) if a_tru is not None: html_params = { 'answer': True, 'label': label, 'a_tru': '{:d}'.format(a_tru), 'suffix': suffix } with open('pl-integer-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') label = pl.get_string_attrib(element, 'label', None) suffix = pl.get_string_attrib(element, 'suffix', None) display = pl.get_string_attrib(element, 'display', DISPLAY_DEFAULT) allow_fractions = pl.get_boolean_attrib(element, 'allow-fractions', ALLOW_FRACTIONS_DEFAULT) if data['panel'] == 'question': editable = data['editable'] raw_submitted_answer = data['raw_submitted_answers'].get(name, None) html_params = { 'question': True, 'name': name, 'label': label, 'suffix': suffix, 'editable': editable, 'size': pl.get_integer_attrib(element, 'size', SIZE_DEFAULT), 'uuid': pl.get_uuid() } partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) # Get comparison parameters and info strings comparison = pl.get_string_attrib(element, 'comparison', COMPARISON_DEFAULT) if comparison == 'relabs': rtol = pl.get_float_attrib(element, 'rtol', RTOL_DEFAULT) atol = pl.get_float_attrib(element, 'atol', ATOL_DEFAULT) if (rtol < 0): raise ValueError( 'Attribute rtol = {:g} must be non-negative'.format(rtol)) if (atol < 0): raise ValueError( 'Attribute atol = {:g} must be non-negative'.format(atol)) info_params = { 'format': True, 'relabs': True, 'rtol': '{:g}'.format(rtol), 'atol': '{:g}'.format(atol) } elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) if (digits < 0): raise ValueError( 'Attribute digits = {:d} must be non-negative'.format( digits)) info_params = { 'format': True, 'sigfig': True, 'digits': '{:d}'.format(digits), 'comparison_eps': 0.51 * (10**-(digits - 1)) } elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) if (digits < 0): raise ValueError( 'Attribute digits = {:d} must be non-negative'.format( digits)) info_params = { 'format': True, 'decdig': True, 'digits': '{:d}'.format(digits), 'comparison_eps': 0.51 * (10**-(digits - 0)) } else: raise ValueError( 'method of comparison "%s" is not valid (must be "relabs", "sigfig", or "decdig")' % comparison) # Update parameters for the info popup show_correct = 'correct' in html_params and pl.get_boolean_attrib( element, 'show-correct-answer', SHOW_CORRECT_ANSWER_DEFAULT) info_params['allow_complex'] = pl.get_boolean_attrib( element, 'allow-complex', ALLOW_COMPLEX_DEFAULT) info_params['show_info'] = pl.get_boolean_attrib( element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT) info_params['show_correct'] = show_correct info_params['allow_fractions'] = allow_fractions # Find the true answer to be able to display it in the info popup ans_true = None if pl.get_boolean_attrib(element, 'show-correct-answer', SHOW_CORRECT_ANSWER_DEFAULT): ans_true = format_true_ans(element, data, name) if ans_true is not None: info_params['a_tru'] = ans_true with open('pl-number-input.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() with open('pl-number-input.mustache', 'r', encoding='utf-8') as f: info_params.pop('format', None) # Within mustache, the shortformat generates the shortinfo that is used as a placeholder inside of the numeric entry. # Here we opt to not generate the value, hence the placeholder is empty. info_params['shortformat'] = pl.get_boolean_attrib( element, 'show-placeholder', SHOW_PLACEHOLDER_DEFAULT) shortinfo = chevron.render(f, info_params).strip() html_params['info'] = info html_params['shortinfo'] = shortinfo # Determine the title of the popup based on what information is being shown if pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT): html_params['popup_title'] = 'Number' else: html_params['popup_title'] = 'Correct Answer' # Enable or disable the popup if pl.get_boolean_attrib(element, 'show-help-text', SHOW_HELP_TEXT_DEFAULT) or show_correct: html_params['show_info'] = True html_params[ 'display_append_span'] = 'show_info' in html_params or suffix if display == 'inline': html_params['inline'] = True elif display == 'block': html_params['block'] = True else: raise ValueError( 'method of display "%s" is not valid (must be "inline" or "block")' % display) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape(raw_submitted_answer) with open('pl-number-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'submission': parse_error = data['format_errors'].get(name, None) html_params = { 'submission': True, 'label': label, 'parse_error': parse_error, 'uuid': pl.get_uuid() } if parse_error is None and name in data['submitted_answers']: a_sub = data['submitted_answers'].get(name) # If answer is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) a_sub = pl.from_json(a_sub) html_params['suffix'] = suffix html_params['a_sub'] = '{:.12g}'.format(a_sub) elif name not in data['submitted_answers']: html_params['missing_input'] = True html_params['parse_error'] = None else: raw_submitted_answer = data['raw_submitted_answers'].get( name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = pl.escape_unicode_string( raw_submitted_answer) # Add true answer to be able to display it in the submitted answer panel ans_true = None if pl.get_boolean_attrib(element, 'show-correct-answer', SHOW_CORRECT_ANSWER_DEFAULT): ans_true = format_true_ans(element, data, name) if ans_true is not None: html_params['a_tru'] = ans_true partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) if score is not None: try: score = float(score) if score >= 1: html_params['correct'] = True elif score > 0: html_params['partial'] = math.floor(score * 100) else: html_params['incorrect'] = True except Exception: raise ValueError('invalid score' + score) html_params['error'] = html_params['parse_error'] or html_params.get( 'missing_input', False) with open('pl-number-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': ans_true = None if pl.get_boolean_attrib(element, 'show-correct-answer', SHOW_CORRECT_ANSWER_DEFAULT): ans_true = format_true_ans(element, data, name) if ans_true is not None: html_params = { 'answer': True, 'label': label, 'a_tru': ans_true, 'suffix': suffix } with open('pl-number-input.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise Exception('Invalid panel type: %s' % data['panel']) return html