def _get_max_options_to_select(element, default_val): """ Given an HTML fragment containing a pl-checkbox element, returns the maximum number of options that can be selected in the checkbox element for a submission to be valid. In order of descending priority, the returned value equals: 1. The value of the "max-select" attribute, if specified. 2. The value of the "max-correct" attribute, if the "detailed-help-text" attribute is set to True. 3. default_val otherwise. Note: this function should only be called from within this file. """ detailed_help_text = pl.get_boolean_attrib(element, 'detailed-help-text', DETAILED_HELP_TEXT_DEFAULT) if pl.has_attrib(element, 'max-select'): max_options_to_select = pl.get_integer_attrib(element, 'max-select') elif pl.has_attrib(element, 'max-correct') and detailed_help_text: max_options_to_select = pl.get_integer_attrib(element, 'max-correct') else: max_options_to_select = default_val return max_options_to_select
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) # Get file name or raise exception if one does not exist file_name = pl.get_string_attrib(element, 'file-name') # Get type (default is static) file_type = pl.get_string_attrib(element, 'type', 'static') # Get directory (default is clientFilesQuestion) file_directory = pl.get_string_attrib(element, 'directory', 'clientFilesQuestion') # Get label (default is file_name) file_label = pl.get_string_attrib(element, 'label', file_name) # Get whether to force a download or open in-browser force_download = pl.get_boolean_attrib(element, 'force-download', True) # Get base url, which depends on the type and directory if file_type == 'static': if file_directory == 'clientFilesQuestion': base_url = data['options']['client_files_question_url'] elif file_directory == 'clientFilesCourse': base_url = data['options']['client_files_course_url'] else: raise ValueError( 'directory "{}" is not valid for type "{}" (must be "clientFilesQuestion" or "clientFilesCourse")' .format(file_directory, file_type)) elif file_type == 'dynamic': if pl.has_attrib(element, 'directory'): raise ValueError( 'no directory ("{}") can be provided for type "{}"'.format( file_directory, file_type)) else: base_url = data['options']['client_files_question_dynamic_url'] else: raise ValueError( 'type "{}" is not valid (must be "static" or "dynamic")'.format( file_type)) # Get full url file_url = os.path.join(base_url, file_name) # Create and return html if force_download: return '<a href="' + file_url + '" download>' + file_label + '</a>' else: return '<a href="' + file_url + '" target="_blank">' + file_label + '</a>'
def render(element_html, element_index, data): element = lxml.html.fragment_fromstring(element_html) # Get file name or raise exception if one does not exist file_name = pl.get_string_attrib(element, 'file_name') # Get type (default is static) file_type = pl.get_string_attrib(element, 'type', 'static') # Get directory (default is clientFilesQuestion) file_directory = pl.get_string_attrib(element, 'directory', 'clientFilesQuestion') # Get base url, which depends on the type and directory if file_type == 'static': if file_directory == 'clientFilesQuestion': base_url = data['options']['client_files_question_url'] elif file_directory == 'clientFilesCourse': base_url = data['options']['client_files_course_url'] else: raise ValueError( 'directory "{}" is not valid for type "{}" (must be "clientFilesQuestion" or "clientFilesCourse")' .format(file_directory, file_type)) elif file_type == 'dynamic': if pl.has_attrib(element, 'directory'): raise ValueError( 'no directory ("{}") can be provided for type "{}"'.format( file_directory, file_type)) else: base_url = data['options']['client_files_question_dynamic_url'] else: raise ValueError( 'type "{}" is not valid (must be "static" or "dynamic")'.format( file_type)) # Get full url file_url = os.path.join(base_url, file_name) # Get width (optional) width = pl.get_string_attrib(element, 'width', None) # Create and return html html_params = {'src': file_url, 'width': width} with open('pl_figure.mustache', 'r') as f: html = chevron.render(f, html_params).strip() return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) # Get file name or raise exception if one does not exist file_name = pl.get_string_attrib(element, 'file-name') # Get type (default is static) file_type = pl.get_string_attrib(element, 'type', TYPE_DEFAULT) # Get directory (default is clientFilesQuestion) file_directory = pl.get_string_attrib(element, 'directory', DIRECTORY_DEFAULT) # Get inline (default is false) inline = pl.get_boolean_attrib(element, 'inline', INLINE_DEFAULT) # Get alternate-text text (default is PrairieLearn Image) alt_text = pl.get_string_attrib(element, 'alt', ALT_TEXT_DEFAULT) # Get base url, which depends on the type and directory if file_type == 'static': if file_directory == 'clientFilesQuestion': base_url = data['options']['client_files_question_url'] elif file_directory == 'clientFilesCourse': base_url = data['options']['client_files_course_url'] else: raise ValueError('directory "{}" is not valid for type "{}" (must be "clientFilesQuestion" or "clientFilesCourse")'.format(file_directory, file_type)) elif file_type == 'dynamic': if pl.has_attrib(element, 'directory'): raise ValueError('no directory ("{}") can be provided for type "{}"'.format(file_directory, file_type)) else: base_url = data['options']['client_files_question_dynamic_url'] else: raise ValueError('type "{}" is not valid (must be "static" or "dynamic")'.format(file_type)) # Get full url file_url = os.path.join(base_url, file_name) # Get width (optional) width = pl.get_string_attrib(element, 'width', WIDTH_DEFAULT) # Create and return html html_params = {'src': file_url, 'width': width, 'inline': inline, 'alt': alt_text} with open('pl-figure.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) # Get file name or raise exception if one does not exist file_name = pl.get_string_attrib(element, 'file-name') # Get type (default is static) file_type = pl.get_string_attrib(element, 'type', 'static') # Get directory (default is clientFilesQuestion) file_directory = pl.get_string_attrib(element, 'directory', 'clientFilesQuestion') # Get label (default is file_name) file_label = pl.get_string_attrib(element, 'label', file_name) # Get whether to force a download or open in-browser force_download = pl.get_boolean_attrib(element, 'force-download', True) # Get base url, which depends on the type and directory if file_type == 'static': if file_directory == 'clientFilesQuestion': base_url = data['options']['client_files_question_url'] elif file_directory == 'clientFilesCourse': base_url = data['options']['client_files_course_url'] else: raise ValueError('directory "{}" is not valid for type "{}" (must be "clientFilesQuestion" or "clientFilesCourse")'.format(file_directory, file_type)) elif file_type == 'dynamic': if pl.has_attrib(element, 'directory'): raise ValueError('no directory ("{}") can be provided for type "{}"'.format(file_directory, file_type)) else: base_url = data['options']['client_files_question_dynamic_url'] else: raise ValueError('type "{}" is not valid (must be "static" or "dynamic")'.format(file_type)) # Get full url file_url = os.path.join(base_url, file_name) # Create and return html if force_download: return '<a href="' + file_url + '" download>' + file_label + '</a>' else: return '<a href="' + file_url + '" target="_blank">' + file_label + '</a>'
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) # Get file name or raise exception if one does not exist file_name = pl.get_string_attrib(element, 'file-name') # Get type (default is static) file_type = pl.get_string_attrib(element, 'type', 'static') # Get directory (default is clientFilesQuestion) file_directory = pl.get_string_attrib(element, 'directory', 'clientFilesQuestion') # Get base url, which depends on the type and directory if file_type == 'static': if file_directory == 'clientFilesQuestion': base_url = data['options']['client_files_question_url'] elif file_directory == 'clientFilesCourse': base_url = data['options']['client_files_course_url'] else: raise ValueError('directory "{}" is not valid for type "{}" (must be "clientFilesQuestion" or "clientFilesCourse")'.format(file_directory, file_type)) elif file_type == 'dynamic': if pl.has_attrib(element, 'directory'): raise ValueError('no directory ("{}") can be provided for type "{}"'.format(file_directory, file_type)) else: base_url = data['options']['client_files_question_dynamic_url'] else: raise ValueError('type "{}" is not valid (must be "static" or "dynamic")'.format(file_type)) # Get full url file_url = os.path.join(base_url, file_name) # Get width (optional) width = pl.get_string_attrib(element, 'width', None) # Create and return html html_params = {'src': file_url, 'width': width} with open('pl-figure.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) name = pl.get_string_attrib(element, 'answers-name') partial_credit = pl.get_boolean_attrib(element, 'partial-credit', PARTIAL_CREDIT_DEFAULT) partial_credit_method = pl.get_string_attrib(element, 'partial-credit-method', PARTIAL_CREDIT_METHOD_DEFAULT) hide_score_badge = pl.get_boolean_attrib(element, 'hide-score-badge', HIDE_SCORE_BADGE_DEFAULT) editable = data['editable'] # answer feedback is not displayed when partial credit is True # (unless the question is disabled) show_answer_feedback = True if (partial_credit and editable) or hide_score_badge: show_answer_feedback = False display_answers = data['params'].get(name, []) inline = pl.get_boolean_attrib(element, 'inline', INLINE_DEFAULT) submitted_keys = data['submitted_answers'].get(name, []) # if there is only one key then it is passed as a string, # not as a length-one list, so we fix that next if isinstance(submitted_keys, str): submitted_keys = [submitted_keys] correct_answer_list = data['correct_answers'].get(name, []) correct_keys = [answer['key'] for answer in correct_answer_list] if data['panel'] == 'question': partial_score = data['partial_scores'].get(name, {'score': None}) score = partial_score.get('score', None) feedback = partial_score.get('feedback', None) answerset = [] for answer in display_answers: answer_html = { 'key': answer['key'], 'checked': (answer['key'] in submitted_keys), 'html': answer['html'].strip(), 'display_score_badge': score is not None and show_answer_feedback and answer['key'] in submitted_keys, 'display_feedback': answer['key'] in submitted_keys and feedback and feedback.get(answer['key'], None) is not None, 'feedback': feedback.get(answer['key'], None) if feedback else None } if answer_html['display_score_badge']: answer_html['correct'] = (answer['key'] in correct_keys) answer_html['incorrect'] = (answer['key'] not in correct_keys) answerset.append(answer_html) info_params = {'format': True} # Adds decorative help text per bootstrap formatting guidelines: # http://getbootstrap.com/docs/4.0/components/forms/#help-text # Determine whether we should add a choice selection requirement hide_help_text = pl.get_boolean_attrib(element, 'hide-help-text', HIDE_HELP_TEXT_DEFAULT) if not hide_help_text: # Should we reveal the depth of the choice? detailed_help_text = pl.get_boolean_attrib(element, 'detailed-help-text', DETAILED_HELP_TEXT_DEFAULT) show_number_correct = pl.get_boolean_attrib(element, 'show-number-correct', SHOW_NUMBER_CORRECT_DEFAULT) if show_number_correct: if len(correct_answer_list) == 1: number_correct_text = ' There is exactly <b>1</b> correct option in the list above.' else: number_correct_text = f' There are exactly <b>{len(correct_answer_list)}</b> correct options in the list above.' else: number_correct_text = '' min_options_to_select = _get_min_options_to_select(element, MIN_SELECT_DEFAULT) max_options_to_select = _get_max_options_to_select(element, len(display_answers)) # Now we determine what the help text will be. # # If detailed_help_text is True, we reveal the values of min_options_to_select and max_options_to_select. # # If detailed_help_text is False, we reveal min_options_to_select if the following conditions are met (analogous # conditions are used for determining whether or not to reveal max_options_to_select): # 1. The "min-select" attribute is specified. # 2. min_options_to_select != MIN_SELECT_DEFAULT. show_min_select = pl.has_attrib(element, 'min-select') and min_options_to_select != MIN_SELECT_DEFAULT show_max_select = pl.has_attrib(element, 'max-select') and max_options_to_select != len(display_answers) if detailed_help_text or (show_min_select and show_max_select): # If we get here, we always reveal min_options_to_select and max_options_to_select. if min_options_to_select != max_options_to_select: insert_text = f' between <b>{min_options_to_select}</b> and <b>{max_options_to_select}</b> options.' else: insert_text = f' exactly <b>{min_options_to_select}</b> options.' else: # If we get here, at least one of min_options_to_select and max_options_to_select should *not* be revealed. if show_min_select: insert_text = f' at least <b>{min_options_to_select}</b> options.' elif show_max_select: insert_text = f' at most <b>{max_options_to_select}</b> options.' else: # This is the case where we reveal nothing about min_options_to_select and max_options_to_select. insert_text = ' at least 1 option.' insert_text += number_correct_text if detailed_help_text or show_min_select or show_max_select: helptext = '<small class="form-text text-muted">Select ' + insert_text + '</small>' else: # This is the case where we reveal nothing about min_options_to_select and max_options_to_select. helptext = '<small class="form-text text-muted">Select all possible options that apply.' + number_correct_text + '</small>' if partial_credit: if partial_credit_method == 'PC': gradingtext = 'You must select' + insert_text + ' You will receive a score of <code>100% * (t - f) / n</code>, ' \ + 'where <code>t</code> is the number of true options that you select, <code>f</code> ' \ + 'is the number of false options that you select, and <code>n</code> is the total number of true options. ' \ + 'At minimum, you will receive a score of 0%.' elif partial_credit_method == 'EDC': gradingtext = 'You must select' + insert_text + ' You will receive a score of <code>100% * (t + f) / ' + str(len(display_answers)) + '</code>, ' \ + 'where <code>t</code> is the number of true options that you select and <code>f</code> ' \ + 'is the number of false options that you do not select.' elif partial_credit_method == 'COV': gradingtext = 'You must select' + insert_text + ' You will receive a score of <code>100% * (t / c) * (t / n)</code>, ' \ + 'where <code>t</code> is the number of true options that you select, <code>c</code> is the total number of true options, ' \ + 'and <code>n</code> is the total number of options you select.' else: raise ValueError(f'Unknown value for partial_credit_method: {partial_credit_method}') else: gradingtext = 'You must select' + insert_text + ' You will receive a score of 100% ' \ + 'if you select all options that are true and no options that are false. ' \ + 'Otherwise, you will receive a score of 0%.' info_params.update({'gradingtext': gradingtext}) with open('pl-checkbox.mustache', 'r', encoding='utf-8') as f: info = chevron.render(f, info_params).strip() html_params = { 'question': True, 'name': name, 'editable': editable, 'uuid': pl.get_uuid(), 'info': info, 'answers': answerset, 'inline': inline, 'hide_letter_keys': pl.get_boolean_attrib(element, 'hide-letter-keys', HIDE_LETTER_KEYS_DEFAULT) } if not hide_help_text: html_params['helptext'] = helptext 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-checkbox.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) if parse_error is None: partial_score = data['partial_scores'].get(name, {'score': None}) feedback = partial_score.get('feedback', None) score = partial_score.get('score', None) answers = [] for submitted_key in submitted_keys: submitted_answer = next(filter(lambda a: a['key'] == submitted_key, display_answers), None) answer_item = { 'key': submitted_key, 'html': submitted_answer['html'], 'display_score_badge': score is not None and show_answer_feedback } if answer_item['display_score_badge']: answer_item['correct'] = (submitted_key in correct_keys) answer_item['incorrect'] = (submitted_key not in correct_keys) answer_item['display_feedback'] = feedback and feedback.get(submitted_key, None) is not None answer_item['feedback'] = feedback.get(submitted_key, None) if feedback else None answers.append(answer_item) html_params = { 'submission': True, 'display_score_badge': (score is not None), 'answers': answers, 'inline': inline, 'hide_letter_keys': pl.get_boolean_attrib(element, 'hide-letter-keys', HIDE_LETTER_KEYS_DEFAULT) } if html_params['display_score_badge']: 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-checkbox.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html_params = { 'submission': True, 'uuid': pl.get_uuid(), 'parse_error': parse_error, 'inline': inline, } with open('pl-checkbox.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() elif data['panel'] == 'answer': if not pl.get_boolean_attrib(element, 'hide-answer-panel', HIDE_ANSWER_PANEL_DEFAULT): correct_answer_list = data['correct_answers'].get(name, []) if len(correct_answer_list) == 0: raise ValueError('At least one option must be true.') else: html_params = { 'answer': True, 'inline': inline, 'answers': correct_answer_list, 'hide_letter_keys': pl.get_boolean_attrib(element, 'hide-letter-keys', HIDE_LETTER_KEYS_DEFAULT) } with open('pl-checkbox.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() else: html = '' else: raise ValueError('Invalid panel type: %s' % data['panel']) return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) digits = pl.get_integer_attrib(element, 'digits', DIGITS_DEFAULT) show_matlab = pl.get_boolean_attrib(element, 'show-matlab', SHOW_MATLAB_DEFAULT) show_mathematica = pl.get_boolean_attrib(element, 'show-mathematica', SHOW_MATHEMATICA_DEFAULT) show_python = pl.get_boolean_attrib(element, 'show-python', SHOW_PYTHON_DEFAULT) default_tab = pl.get_string_attrib(element, 'default-tab', DEFAULT_TAB_DEFAULT) tab_list = ['matlab', 'mathematica', 'python'] if default_tab not in tab_list: raise Exception(f'invalid default-tab: {default_tab}') # Setting the default tab displayed_tab = [show_matlab, show_mathematica, show_python] if not any(displayed_tab): raise Exception( 'All tabs have been hidden from display. At least one tab must be shown.' ) default_tab_index = tab_list.index(default_tab) # If not displayed, make first visible tab the default if not displayed_tab[default_tab_index]: first_display = displayed_tab.index(True) default_tab = tab_list[first_display] default_tab_index = tab_list.index(default_tab) # Active tab should be the default tab default_tab_list = [False, False, False] default_tab_list[default_tab_index] = True [active_tab_matlab, active_tab_mathematica, active_tab_python] = default_tab_list # Process parameter data matlab_data = '' mathematica_data = '' python_data = 'import numpy as np\n\n' for child in element: if child.tag == 'variable': # Raise exception if variable does not have a name pl.check_attribs(child, required_attribs=['params-name'], optional_attribs=['comment', 'digits']) # Get name of variable var_name = pl.get_string_attrib(child, 'params-name') # Get value of variable, raising exception if variable does not exist var_data = data['params'].get(var_name, None) if var_data is None: raise Exception( 'No value in data["params"] for variable %s in pl-variable-output element' % var_name) # If the variable is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) var_data = pl.from_json(var_data) # Get comment, if it exists var_matlab_comment = '' var_mathematica_comment = '' var_python_comment = '' if pl.has_attrib(child, 'comment'): var_comment = pl.get_string_attrib(child, 'comment') var_matlab_comment = f' % {var_comment}' var_mathematica_comment = f' (* {var_comment} *)' var_python_comment = f' # {var_comment}' # Get digit for child, if it exists if not pl.has_attrib(child, 'digits'): var_digits = digits else: var_digits = pl.get_string_attrib(child, 'digits') # Assembling Python array formatting if np.isscalar(var_data): prefix = '' suffix = '' else: # Wrap the variable in an ndarray (if it's already one, this does nothing) var_data = np.array(var_data) # Check shape of variable if var_data.ndim > 2: raise Exception( 'Value in data["params"] for variable %s in pl-variable-output element must be a scalar, a vector, or a 2D array' % var_name) # Create prefix/suffix so python string is np.array( ... ) prefix = 'np.array(' suffix = ')' # Mathematica reserved letters: C D E I K N O mathematica_reserved = ['C', 'D', 'E', 'I', 'K', 'N', 'O'] if pl.inner_html(child) in mathematica_reserved: mathematica_suffix = 'm' else: mathematica_suffix = '' # Create string for matlab and python format var_name_disp = pl.inner_html(child) var_matlab_data = pl.string_from_numpy(var_data, language='matlab', digits=var_digits) var_mathematica = pl.string_from_numpy(var_data, language='mathematica', digits=var_digits) var_python_data = pl.string_from_numpy(var_data, language='python', digits=var_digits) matlab_data += f'{var_name_disp} = {var_matlab_data};{var_matlab_comment}\n' mathematica_data += f'{var_name_disp}{mathematica_suffix} = {var_mathematica};{var_mathematica_comment}\n' python_data += f'{var_name_disp} = {prefix}{var_python_data}{suffix}{var_python_comment}\n' html_params = { 'active_tab_matlab': active_tab_matlab, 'active_tab_mathematica': active_tab_mathematica, 'active_tab_python': active_tab_python, 'show_matlab': show_matlab, 'show_mathematica': show_mathematica, 'show_python': show_python, 'matlab_data': matlab_data, 'mathematica_data': mathematica_data, 'python_data': python_data, 'uuid': pl.get_uuid() } with open('pl-variable-output.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() return html
def render(element_html, data): element = lxml.html.fragment_fromstring(element_html) digits = pl.get_integer_attrib(element, 'digits', 2) show_matlab = pl.get_boolean_attrib(element, 'show-matlab', True) show_mathematica = pl.get_boolean_attrib(element, 'show-mathematica', True) show_python = pl.get_boolean_attrib(element, 'show-python', True) default_tab = pl.get_string_attrib(element, 'default-tab', 'matlab') tab_list = ['matlab', 'mathematica', 'python'] if default_tab not in tab_list: raise Exception(f'invalid default-tab: {default_tab}') # Setting the default tab displayed_tab = [show_matlab, show_mathematica, show_python] if not any(displayed_tab): raise Exception('All tabs have been hidden from display. At least one tab must be shown.') default_tab_index = tab_list.index(default_tab) # If not displayed, make first visible tab the default if not displayed_tab[default_tab_index]: first_display = displayed_tab.index(True) default_tab = tab_list[first_display] default_tab_index = tab_list.index(default_tab) # Active tab should be the default tab default_tab_list = [False, False, False] default_tab_list[default_tab_index] = True [active_tab_matlab, active_tab_mathematica, active_tab_python] = default_tab_list # Process parameter data matlab_data = '' mathematica_data = '' python_data = 'import numpy as np\n\n' for child in element: if child.tag == 'variable': # Raise exception if variable does not have a name pl.check_attribs(child, required_attribs=['params-name'], optional_attribs=['comment', 'digits']) # Get name of variable var_name = pl.get_string_attrib(child, 'params-name') # Get value of variable, raising exception if variable does not exist var_data = data['params'].get(var_name, None) if var_data is None: raise Exception('No value in data["params"] for variable %s in pl-variable-output element' % var_name) # If the variable is in a format generated by pl.to_json, convert it # back to a standard type (otherwise, do nothing) var_data = pl.from_json(var_data) # Get comment, if it exists var_matlab_comment = '' var_mathematica_comment = '' var_python_comment = '' if pl.has_attrib(child, 'comment'): var_comment = pl.get_string_attrib(child, 'comment') var_matlab_comment = f' % {var_comment}' var_mathematica_comment = f' (* {var_comment} *)' var_python_comment = f' # {var_comment}' # Get digit for child, if it exists if not pl.has_attrib(child, 'digits'): var_digits = digits else: var_digits = pl.get_string_attrib(child, 'digits') # Assembling Python array formatting if np.isscalar(var_data): prefix = '' suffix = '' else: # Wrap the variable in an ndarray (if it's already one, this does nothing) var_data = np.array(var_data) # Check shape of variable if var_data.ndim > 2: raise Exception('Value in data["params"] for variable %s in pl-variable-output element must be a scalar, a vector, or a 2D array' % var_name) # Create prefix/suffix so python string is np.array( ... ) prefix = 'np.array(' suffix = ')' # Mathematica reserved letters: C D E I K N O mathematica_reserved = ['C', 'D', 'E', 'I', 'K', 'N', 'O'] if pl.inner_html(child) in mathematica_reserved: mathematica_suffix = 'm' else: mathematica_suffix = '' # Create string for matlab and python format var_name_disp = pl.inner_html(child) var_matlab_data = pl.string_from_numpy(var_data, language='matlab', digits=var_digits) var_mathematica = pl.string_from_numpy(var_data, language='mathematica', digits=var_digits) var_python_data = pl.string_from_numpy(var_data, language='python', digits=var_digits) matlab_data += f'{var_name_disp} = {var_matlab_data};{var_matlab_comment}\n' mathematica_data += f'{var_name_disp}{mathematica_suffix} = {var_mathematica};{var_mathematica_comment}\n' python_data += f'{var_name_disp} = {prefix}{var_python_data}{suffix}{var_python_comment}\n' html_params = { 'active_tab_matlab': active_tab_matlab, 'active_tab_mathematica': active_tab_mathematica, 'active_tab_python': active_tab_python, 'show_matlab': show_matlab, 'show_mathematica': show_mathematica, 'show_python': show_python, 'matlab_data': matlab_data, 'mathematica_data': mathematica_data, 'python_data': python_data, 'uuid': pl.get_uuid() } with open('pl-variable-output.mustache', 'r', encoding='utf-8') as f: html = chevron.render(f, html_params).strip() return html