def format_true_ans(element, data, name): a_tru = pl.from_json(data['correct_answers'].get(name, None)) if a_tru is not None: # Get comparison parameters comparison = pl.get_string_attrib(element, 'comparison', 'relabs') if comparison == 'relabs': # FIXME: render correctly with respect to rtol and atol a_tru = '{:.12g}'.format(a_tru) elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', 2) a_tru = pl.string_from_number_sigfig(a_tru, digits=digits) elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', 2) a_tru = '{:.{ndigits}f}'.format(a_tru, ndigits=digits) else: raise ValueError( 'method of comparison "%s" is not valid (must be "relabs", "sigfig", or "decdig")' % comparison) return a_tru
def render(element_html, element_index, 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', 'inline') 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', 'relabs') if comparison == 'relabs': rtol = pl.get_float_attrib(element, 'rtol', 1e-2) atol = pl.get_float_attrib(element, 'atol', 1e-8) info_params = { 'format': True, 'relabs': True, 'rtol': rtol, 'atol': atol } elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', 2) info_params = { 'format': True, 'sigfig': True, 'digits': digits, 'comparison_eps': 0.51 * (10**-(digits - 1)) } elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', 2) info_params = { 'format': True, 'decdig': True, 'digits': 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', False) 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) 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, '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_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: # 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'] = '{:.12g}'.format(a_sub) else: raw_submitted_answer = data['raw_submitted_answers'].get( name, None) if raw_submitted_answer is not None: html_params['raw_submitted_answer'] = escape( 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) with open('pl_number_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: # Get comparison parameters comparison = pl.get_string_attrib(element, 'comparison', 'relabs') if comparison == 'relabs': rtol = pl.get_float_attrib(element, 'rtol', 1e-2) atol = pl.get_float_attrib(element, 'atol', 1e-8) # FIXME: render correctly with respect to rtol and atol a_tru = '{:.12g}'.format(a_tru) elif comparison == 'sigfig': digits = pl.get_integer_attrib(element, 'digits', 2) a_tru = pl.string_from_number_sigfig(a_tru, digits=digits) elif comparison == 'decdig': digits = pl.get_integer_attrib(element, 'digits', 2) a_tru = '{:.{ndigits}f}'.format(a_tru, ndigits=digits) else: raise ValueError( 'method of comparison "%s" is not valid (must be "relabs", "sigfig", or "decdig")' % comparison) # FIXME: render correctly with respect to method of comparison html_params = { 'answer': True, 'label': label, 'a_tru': a_tru, '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