Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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 = '&nbsp;<span class="badge badge-success"><i class="fa fa-check" aria-hidden="true"></i> 100%</span>'
            elif score > 0:
                score_message = '&nbsp;<span class="badge badge-warning"><i class="far fa-circle" aria-hidden="true"></i>' + str(
                    math.floor(score * 100)) + '%</span>'
            else:
                score_message = '&nbsp;<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 + '&nbsp;</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 = '&nbsp;<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 = '&nbsp;<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">&nbsp;' + 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 = '&nbsp;<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 = '&nbsp;<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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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