Пример #1
0
    def test_current_line_rest(self):
        args = {
            'template': 'first line\nsecond line\n {{ foo } bar',
            'data': {'foo': 'xx'}
        }

        # self.assertRaisesRegex does not exist in python2.6
        for _ in range(10):
            try:
                chevron.render(**args)
            except chevron.ChevronError as error:
                self.assertEqual(error.msg, 'unclosed tag at line 3')
Пример #2
0
    def test_no_opening_tag(self):
        args = {
            'template': 'oops, no opening tag {{/ closing_tag }}',
            'data': {'foo': 'xx'}
        }

        try:
            chevron.render(**args)
        except chevron.ChevronError as error:
            self.assertEqual(error.msg, 'Trying to close tag "closing_tag"\n'
                                        'Looks like it was not opened.\n'
                                        'line 2')
Пример #3
0
    def test_callable_1(self):
        args_passed = {}

        def first(content, render):
            args_passed['content'] = content
            args_passed['render'] = render

            return "not implemented"

        args = {
            'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} '
                        '|| {{{village}}} || {{{state}}} {{/first}}',
            'data': {
                "postcode": "1234",
                "city": "Mustache City",
                "state": "Nowhere",
                "first": first,
            }

        }

        result = chevron.render(**args)
        expected = '1234 not implemented'
        template_content = " {{& city }} || {{& town }} || {{& village }} "\
                           "|| {{& state }} "

        self.assertEqual(result, expected)
        self.assertEqual(args_passed['content'], template_content)
def render(element_html, data):
    element = lxml.html.fragment_fromstring(element_html)
    script_name = pl.get_string_attrib(element, 'script-name', None)

    with open(os.path.join(data['options']['question_path'], script_name)) as f:
        script = f.read()

    width = pl.get_string_attrib(element, 'width', '500')
    height = pl.get_string_attrib(element, 'height', '300')

    params_names = pl.get_string_attrib(element, 'param-names', None)
    if params_names is None:
        client_params = {}
    else:
        params_names = params_names.split(sep=',')
        client_params = {key: data['params'][key] for key in params_names}

    html_params = {
        'script': script,
        'width': width,
        'height': height,
        'client_params': client_params,
        'uuid': pl.get_uuid(),
    }

    with open('pl-prairiedraw-figure.mustache') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #5
0
def render(element_html, data):
    if data['panel'] != 'question':
        return ''

    element = lxml.html.fragment_fromstring(element_html)
    uuid = pl.get_uuid()
    raw_file_names = pl.get_string_attrib(element, 'file-names', '')
    file_names = get_file_names_as_array(raw_file_names)
    file_names_json = json.dumps(file_names, allow_nan=False)
    answer_name = get_answer_name(raw_file_names)

    html_params = {'name': answer_name, 'file_names': file_names_json, 'uuid': uuid}

    files = data['submitted_answers'].get('_files', None)
    if files is not None:
        # Filter out any files not part of this element's file_names
        filtered_files = [x for x in files if x.get('name', '') in file_names]
        html_params['has_files'] = True
        html_params['files'] = json.dumps(filtered_files, allow_nan=False)
    else:
        html_params['has_files'] = False

    with open('pl-file-upload.mustache', 'r', encoding='utf-8') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #6
0
 def build_dockerfile(self, arch_data):
     if_build = ".build" if self.data["STAGE"] else ""
     dockerfile_tmpl_path = f'Dockerfile{if_build}.tmpl'
     dockerfile_path = f'build/{arch_data["ARCH"]["name"]}/Dockerfile{if_build}'
     with open(dockerfile_tmpl_path, 'r') as f:
         dockerfile = chevron.render(f, arch_data)
     with open(dockerfile_path, 'w') as f:
         f.write(str(dockerfile))
def render(element_html, data):

    element = lxml.html.fragment_fromstring(element_html)
    file_name = pl.get_string_attrib(element, 'file-name', '')
    answer_name = get_answer_name(file_name)
    quill_theme = pl.get_string_attrib(element, 'quill-theme', QUILL_THEME_DEFAULT)
    placeholder = pl.get_string_attrib(element, 'placeholder', PLACEHOLDER_DEFAULT)
    uuid = pl.get_uuid()
    source_file_name = pl.get_string_attrib(element, 'source-file-name', SOURCE_FILE_NAME_DEFAULT)
    directory = pl.get_string_attrib(element, 'directory', DIRECTORY_DEFAULT)
    element_text = element_inner_html(element)

    if data['panel'] == 'question' or data['panel'] == 'submission':

        html_params = {
            'name': answer_name,
            'file_name': file_name,
            'quill_theme': quill_theme,
            'placeholder': placeholder,
            'editor_uuid': uuid,
            'question': data['panel'] == 'question',
            'submission': data['panel'] == 'submission',
            'read_only': 'true' if data['panel'] == 'submission' else 'false'
        }

        if source_file_name is not None:
            if directory == 'serverFilesCourse':
                directory = data['options']['server_files_course_path']
            elif directory == 'clientFilesCourse':
                directory = data['options']['client_files_course_path']
            else:
                directory = os.path.join(data['options']['question_path'], directory)
            file_path = os.path.join(directory, source_file_name)
            text_display = open(file_path).read()
        else:
            if element_text is not None:
                text_display = str(element_text)
            else:
                text_display = ''

        html_params['original_file_contents'] = base64.b64encode(text_display.encode('UTF-8').strip()).decode()

        submitted_file_contents = data['submitted_answers'].get(answer_name, None)
        if submitted_file_contents:
            html_params['current_file_contents'] = submitted_file_contents
        else:
            html_params['current_file_contents'] = html_params['original_file_contents']

        html_params['question'] = data['panel'] == 'question'
        with open('pl-rich-text-editor.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()

    elif data['panel'] == 'answer':
        html = ''
    else:
        raise Exception('Invalid panel type: ' + data['panel'])

    return html
Пример #8
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("json")
    parser.add_argument("cpp_output")
    parser.add_argument("h_output")
    args = parser.parse_args()

    css_properties = json.load(open(args.json))

    properties = []
    keywords = []
    for name in css_properties:
        css_property = css_properties[name]

        properties.append({
            'property_name':
            name,
            'property_enum':
            css_property_type(name),
            'property_default':
            css_property_default(css_property),
            'property_inherited':
            css_property_inherited(css_property),
            'property_value_type':
            css_property_value_type(css_property),
            'keywords':
            css_property_keywords(name, css_property)
        })

        valid_keywords = css_property.get('valid-keywords', [])
        for keyword in valid_keywords:
            keywords.append({'keyword': format_keyword_enum(name, keyword)})

    d = {'properties': properties, 'keywords': keywords}

    cpp_template_path = os.path.join(
        os.path.dirname(os.path.abspath(__file__)),
        'css_property.cpp.mustache')
    cpp_template_str = open(cpp_template_path).read()
    open(args.cpp_output, 'w').write(chevron.render(cpp_template_str, d))

    h_template_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                   'css_property.h.mustache')
    h_template_str = open(h_template_path).read()
    open(args.h_output, 'w').write(chevron.render(h_template_str, d))
Пример #9
0
def get_format_string(is_complex=False, allow_fractions=False, message=None):
    params = {
        'complex': is_complex,
        'format_error': True,
        'allow_fractions': allow_fractions,
        'format_error_message': message
    }
    with open('pl-number-input.mustache', 'r', encoding='utf-8') as f:
        return chevron.render(f, params).strip()
Пример #10
0
    def chevron_vars_for(
        self,
        version=None,
        spec_path=None,
        paths_relative_to=PathRelativeTo.VERSION_OUTPUT_DIR,
    ):
        chevron_vars = {
            "github_repo_name": self.github_repo,
            "github_repo_org": self.github_org,
            "language_name": self.language,
            "library_version": self.library_version,
            "user_agent_client_name": self.user_agent_client_name,
        }
        chevron_vars["github_repo_url"] = chevron.render(
            constants.GITHUB_REPO_URL_TEMPLATE, chevron_vars)
        if version:
            spec_repo_relpath = "."
            top_level_relpath = os.path.join(constants.SPEC_REPO_GENERATED_DIR,
                                             self.github_repo)
            if paths_relative_to == PathRelativeTo.VERSION_OUTPUT_DIR:
                version_output_dir = self.generated_lang_version_dir_for(
                    version)
                # where is the spec repo relative to version_output_dir
                version_output_dir_nesting_level = len(
                    version_output_dir.strip("/").split("/"))
                spec_repo_relpath = "../" * version_output_dir_nesting_level
                top_level_relpath = ("../" *
                                     (version_output_dir_nesting_level - 2)
                                     or ".")
            templates_dir = os.path.join(
                spec_repo_relpath,
                constants.SPEC_REPO_TEMPLATES_DIR,
                self.language,
                version,
            )
            language_oapi_config_path = os.path.join(
                constants.SPEC_REPO_CONFIG_DIR,
                constants.SPEC_REPO_LANGUAGES_CONFIG_DIR,
                "{lang}_{v}.json".format(lang=self.language, v=version),
            )
            language_config_path = os.path.join(spec_repo_relpath,
                                                language_oapi_config_path)
            config_dir = os.path.join(spec_repo_relpath,
                                      constants.SPEC_REPO_CONFIG_DIR)

            chevron_vars.update({
                "config_dir": config_dir,
                "language_config": language_config_path,
                "spec_version": version,
                "templates_dir": templates_dir,
                "top_level_dir": top_level_relpath,
                "version_output_dir": ".",
            })
            if spec_path:
                full_spec_path = os.path.join(spec_repo_relpath, spec_path)
                chevron_vars["full_spec_path"] = full_spec_path
        return chevron_vars
Пример #11
0
    def test_unicode_basic(self):
        args = {
            'template': '(╯°□°)╯︵ ┻━┻'
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
Пример #12
0
    def test_unicode_basic(self):
        args = {
            'template': '(╯°□°)╯︵ ┻━┻'
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
def render(element_html, element_index, data):
    if data['panel'] == 'submission':
        html_params = {'submission': True, 'graded': True, 'uuid': pl.get_uuid()}

        feedback = data['feedback']
        html_params['graded'] = bool(feedback)
        grading_succeeded = bool(feedback.get('succeeded', None))
        html_params['grading_succeeded'] = grading_succeeded
        if not grading_succeeded:
            html_params['message'] = feedback.get('message', None)
        else:
            results = feedback.get('results', None)
            if grading_succeeded and results:
                html_params['succeeded'] = bool(results.get('succeeded', None))
                html_params['score'] = format(results.get('score', 0) * 100, '.2f').rstrip('0').rstrip('.')
                html_params['achieved_max_points'] = (results.get('score', 0) >= 1.0)
                html_params['results_color'] = '#4CAF50' if (results.get('score', 0) >= 1.0) else '#F44336'
                html_params['has_message'] = bool(results.get('message', False))
                html_params['message'] = results.get('message', None)
                html_params['has_output'] = bool(results.get('output', False))
                html_params['output'] = results.get('output', None)
                html_params['has_message_or_output'] = bool(html_params['has_message'] or html_params['has_output'])

                results_tests = results.get('tests', None)
                html_params['has_tests'] = bool(results.get('tests', None))
                if results_tests:
                    html_params['points'] = sum(test['points'] for test in results_tests)
                    html_params['max_points'] = sum(test['max_points'] for test in results_tests)

                    # We need to build a new tests array to massage data a bit
                    tests = []
                    for index, results_test in enumerate(results_tests):
                        test = {}
                        test['index'] = index
                        test['name'] = results_test.get('name', '')
                        test['has_message'] = bool(results_test.get('message', None))
                        test['message'] = results_test.get('message', None)
                        test['has_output'] = bool(results_test.get('output', None))
                        test['output'] = results_test.get('output', None)
                        test['max_points'] = results_test.get('max_points')
                        test['points'] = results_test.get('points')
                        correct = test['max_points'] == test['points']
                        test['results_color'] = '#4CAF50' if correct else '#F44336'
                        test['results_icon'] = 'glyphicon-ok' if correct else 'glyphicon-remove'
                        test['has_description'] = bool(results_test.get('description', None))
                        test['description'] = results_test.get('description', None)

                        tests.append(test)

                    html_params['tests'] = tests

        with open('pl_external_grader_results.mustache', 'r') as f:
            html = chevron.render(f, html_params).strip()
    else:
        html = ''

    return html
Пример #14
0
def render(element_html, data):
    html_params = {
        'input_nodes': data['params']['input_nodes'],
        'output_nodes': data['params']['output_nodes'],
        'logic_ops': data['params']['logic_ops'],
        'image_url': data['options']['client_files_element_url']
    }
    with open('logic-element.mustache', 'r') as f:
        return chevron.render(f, html_params).strip()
Пример #15
0
 def test_partials_via_file(self):
     args = {
         'template': 'Hello, {{> thing }}!',
         # defaults to .
         'partials_path': 'partials/',
         # defaults to mustache
         'partials_ext': 'txt',
     }
     # ./partials/thing.ms will be read and rendered
     print(chevron.render(**args))
Пример #16
0
def render_alias_typedef(type_collection: TypeCollection, type_name):
    context = {
        'template': "typedef {{ aliased }} {{ type_name }};",
        'data': {
            'type_name': type_name,
            'aliased': type_collection.resolve(type_name)
        }
    }

    return chevron.render(**context)
Пример #17
0
 def test_file_mustache(self):
     with open('test.mustache', 'r') as f:
         print(
             chevron.render(
                 f, {
                     'username': "******",
                     'password': "******",
                     'company': 'uxsino',
                     'adj': 'asshole'
                 }))
Пример #18
0
    def test_listed_data(self):
        args = {
            'template': '{{# . }}({{ . }}){{/ . }}',
            'data': [1, 2, 3, 4, 5]
        }

        result = chevron.render(**args)
        expected = '(1)(2)(3)(4)(5)'

        self.assertEqual(result, expected)
Пример #19
0
def get_sensor_json(obs_json):
    input_values = {}
    app_id = obs_json["app_id"]
    dev_id = obs_json["dev_id"]
    input_values["name"] = dev_id
    input_values[
        "description"] = f"sensemakersams app_id: {app_id}, dev_id: {dev_id}"
    input_values["metadata"] = "missing"
    with open("sta_templates/sensor.json.template") as template_file:
        return chevron.render(template_file, input_values)
Пример #20
0
    def test_unicode_inside_list(self):
        args = {
            'template': '{{#list}}{{.}}{{/list}}',
            'data': {'list': ['☠']}
        }

        result = chevron.render(**args)
        expected = '☠'

        self.assertEqual(result, expected)
Пример #21
0
    def test_nest_loops_with_same_key(self):
        args = {
            'template': 'A{{#x}}B{{#x}}{{.}}{{/x}}C{{/x}}D',
            'data': {'x': ['z', 'x']}
        }

        result = chevron.render(**args)
        expected = 'ABzxCBzxCD'

        self.assertEqual(result, expected)
Пример #22
0
    def test_unicode_variable(self):
        args = {
            'template': '{{ table_flip }}',
            'data': {'table_flip': '(╯°□°)╯︵ ┻━┻'}
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
Пример #23
0
    def test_recursion(self):
        args = {
            'template': '{{# 1.2 }}{{# data }}{{.}}{{/ data }}{{/ 1.2 }}',
            'data': {'1': {'2': [{'data': ["1", "2", "3"]}]}}
        }

        result = chevron.render(**args)
        expected = '123'

        self.assertEqual(result, expected)
Пример #24
0
    def test_unicode_inside_list(self):
        args = {
            'template': '{{#list}}{{.}}{{/list}}',
            'data': {'list': ['☠']}
        }

        result = chevron.render(**args)
        expected = '☠'

        self.assertEqual(result, expected)
Пример #25
0
    def test_unicode_partial(self):
        args = {
            'template': '{{> table_flip }}',
            'partials_dict': {'table_flip': '(╯°□°)╯︵ ┻━┻'}
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
Пример #26
0
    def test_unicode_variable(self):
        args = {
            'template': '{{ table_flip }}',
            'data': {'table_flip': '(╯°□°)╯︵ ┻━┻'}
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
Пример #27
0
    def test_unicode_partial(self):
        args = {
            'template': '{{> table_flip }}',
            'partials_dict': {'table_flip': '(╯°□°)╯︵ ┻━┻'}
        }

        result = chevron.render(**args)
        expected = '(╯°□°)╯︵ ┻━┻'

        self.assertEqual(result, expected)
Пример #28
0
    def test_nest_loops_with_same_key(self):
        args = {
            'template': 'A{{#x}}B{{#x}}{{.}}{{/x}}C{{/x}}D',
            'data': {'x': ['z', 'x']}
        }

        result = chevron.render(**args)
        expected = 'ABzxCBzxCD'

        self.assertEqual(result, expected)
Пример #29
0
def main():
    orgs = sorted(list(_orgs), key=lambda x: x.name.lower())
    # Ensure an even number of cells, leaving one to render blankly if necessary.
    if len(orgs) % 2 == 1:
        orgs.append(Org("", "", ""))
    org_pairs = tuple(
        OrgPair(orgs[i], orgs[i + 1]) for i in range(0, len(orgs), 2))
    buf = pkgutil.get_data("generate_user_list",
                           "user_list_templates/table.html.mustache")
    print(chevron.render(buf.decode(), context={"org_pairs": org_pairs}))
Пример #30
0
    def test_recursion(self):
        args = {
            'template': '{{# 1.2 }}{{# data }}{{.}}{{/ data }}{{/ 1.2 }}',
            'data': {'1': {'2': [{'data': ["1", "2", "3"]}]}}
        }

        result = chevron.render(**args)
        expected = '123'

        self.assertEqual(result, expected)
Пример #31
0
 def replace_macro(m):
     arg_values = [
         a.strip(' ') for a in m.group(1).split('|') if a.strip(' ')
     ]
     if len(macro['args']) != len(arg_values):
         raise RuntimeError(f'invalid macro call "{m.group()}"')
     else:
         return chevron.render(macro['body'],
                               data=dict(zip(macro['args'],
                                             arg_values)))
Пример #32
0
    def test_listed_data(self):
        args = {
            'template': '{{# . }}({{ . }}){{/ . }}',
            'data': [1, 2, 3, 4, 5]
        }

        result = chevron.render(**args)
        expected = '(1)(2)(3)(4)(5)'

        self.assertEqual(result, expected)
Пример #33
0
def generate(data):
    data["params"]["names_for_user"] = []

    data["params"]["names_from_user"] = [
        {"name": "getFoolingSetElement", "type": "function"},
        {"name": "getDistinguishingSuffix", "type": "function"}
    ]

    with open(data["options"]["server_files_course_path"] + "/fooling_sets/question_base.html") as f:
        data["params"]["html"] = chevron.render(f, data).strip()
Пример #34
0
def use_template(templates_dir, template_name):
    cur_template_dir = os.path.join(templates_dir, template_name)
    if not os.path.exists(cur_template_dir):
        raise Exception('the specified template "' + template_name 
                + '" does not exist')

    config = default_config
    config_file = os.path.join(cur_template_dir, 'config.json')
    if os.path.isfile(config_file):
        with open(config_file, 'r') as infile:
            config = json.load(infile)
    
    options = {}
    for option in config['options']:
        name = option['option']
        datatype = option['type']
        if datatype == 'text':
            options[name] = input(name + ':')
        elif datatype == 'bool':
            answer = ''
            while answer not in ['y', 'n']:
                answer = input(name + '? (y/n):')
            options[name] = True if answer == 'y' else False 

    for target in config['targets']:
        target_filename = chevron.render(target['out'], options)
        if not target_filename:
            continue
        target_path = os.path.join(os.getcwd(), target_filename)
        os.makedirs(os.path.dirname(target_path), exist_ok=True)

        source_path = os.path.join(cur_template_dir, target['source'])
        with open(source_path, 'r') as infile:
            with open(target_path, 'w') as outfile:
                translation_args = {
                    'template': infile.read(),
                    'partials_path': cur_template_dir,
                    'partials_ext': 'partial.html',
                    'data': options,
                }
                translated = chevron.render(**translation_args)
                outfile.write(translated)
Пример #35
0
def __render_template(index_patterns: str, number_of_shards: int):
    with open("template/index_template.mustache", "r") as f:
        result = chevron.render(
            f,
            {
                "index_patterns": index_patterns,
                "number_of_shards": number_of_shards
            },
        )
        logger.info("Result of the template rendering from file: %s", result)
        return result
Пример #36
0
def update_environment_vars(files: List[FilePath], environment: Dict[str,
                                                                     str]):
    update_instances_environment_vars(environment=environment)
    set_os_environment_vars(environment=environment)
    os.makedirs(RENDER_DIR, exist_ok=True)
    for file in files:
        copyfile(file, f'{RENDER_DIR}/{file.name}')
        with open(file, 'r') as org_file, open(f'{RENDER_DIR}/{file.name}',
                                               'w') as rendered_file:
            content_to_be_rendered = chevron.render(org_file, environment)
            rendered_file.write(content_to_be_rendered)
Пример #37
0
    def set_alert_field_using_field_data(self, source, field_name):
        '''
        Sets the content of a field using the chevron format
        '''

        field_value = self.config[field_name]
        if '{{source}}' in field_value:
            field_value = field_value.replace(
                '{{source}}', json.dumps(source, sort_keys=True, indent=4))
        field_value = str(chevron.render(field_value, source))
        return field_value
Пример #38
0
    def render_state_file_text(self):
        status = TrainingStatus.NEW
        if self.model_to_load is not None:
            status = TrainingStatus.NEW_LOAD_MODEL

        with open(resource_path('templates/state.yml.mustache'), 'r') as f:
            return (chevron.render(f, {
                'status': status,
                'iterations_run': 0,
                'latest_model_saved': ''
            }))
Пример #39
0
def generate_vmargs(node_name, cookie):
    script_dir = os.path.dirname(__file__) #<-- absolute dir the script is in
    rel_path = "templates/vm.args.mustache"
    template_path = os.path.join(script_dir, rel_path)
    vmargs_path = "/release-config/vm.args"

    with open(template_path, "r", encoding='utf8') as f:
        template = f.read()
        vmargs = chevron.render(template, {"MY_NODE_NAME": node_name, "MY_COOKIE": cookie})
        with open(vmargs_path, "w", encoding='utf8') as g:
            g.write(vmargs)
Пример #40
0
def render(element_html, data):
    # Get workspace url
    # TODO: Improve UX if key undefined (https://github.com/PrairieLearn/PrairieLearn/pull/2665#discussion_r449319839)
    workspace_url = data['options']['workspace_url']

    # Create and return html
    html_params = {'workspace_url': workspace_url}
    with open('pl-workspace.mustache', 'r', encoding='utf-8') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #41
0
def render(element_html, data):
    element = lxml.html.fragment_fromstring(element_html)
    language = pl.get_string_attrib(element, 'language', None)
    no_highlight = pl.get_boolean_attrib(element, 'no-highlight', False)
    specify_language = (language is not None) and (not no_highlight)
    source_file_name = pl.get_string_attrib(element, 'source-file-name', None)
    prevent_select = pl.get_boolean_attrib(element, 'prevent-select', False)
    highlight_lines = pl.get_string_attrib(element, 'highlight-lines', None)
    highlight_lines_color = pl.get_string_attrib(element, 'highlight-lines-color', '#b3d7ff')

    if source_file_name is not None:
        base_path = data['options']['question_path']
        file_path = os.path.join(base_path, source_file_name)
        if not os.path.exists(file_path):
            raise Exception(f'Unknown file path: "{file_path}".')
        f = open(file_path, 'r')
        code = ''
        for line in f.readlines():
            code += line
        code = code[:-1]
        f.close()
        # Automatically escape code in file source (important for: html/xml).
        code = escape(code)
    else:
        # Strip a single leading newline from the code, if present. This
        # avoids having spurious newlines because of HTML like:
        #
        # <pl-code>
        # some_code
        # </pl-code>
        #
        # which technically starts with a newline, but we probably
        # don't want a blank line at the start of the code block.
        code = pl.inner_html(element)
        if len(code) > 1 and code[0] == '\r' and code[1] == '\n':
            code = code[2:]
        elif len(code) > 0 and (code[0] == '\n' or code[0] == '\r'):
            code = code[1:]

    if highlight_lines is not None:
        code = highlight_lines_in_code(code, highlight_lines, highlight_lines_color)

    html_params = {
        'specify_language': specify_language,
        'language': language,
        'no_highlight': no_highlight,
        'code': code,
        'prevent_select': prevent_select,
    }

    with open('pl-code.mustache', 'r', encoding='utf-8') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #42
0
    def test_namedtuple_data(self):
        NT = collections.namedtuple('NT', ['foo', 'bar'])
        args = {
            'template': '{{foo}} {{bar}}',
            'data': NT('hello', 'world')
        }

        result = chevron.render(**args)
        expected = 'hello world'

        self.assertEqual(result, expected)
Пример #43
0
    def test_inverted_coercion(self):
        args = {
            'template': '{{#object}}{{^child}}{{.}}{{/child}}{{/object}}',
            'data': {'object': [
                'foo', 'bar', {'child': True}, 'baz'
            ]}
        }

        result = chevron.render(**args)
        expected = 'foobarbaz'

        self.assertEqual(result, expected)
Пример #44
0
    def test_falsy(self):
        args = {
            'template': '{{null}}{{false}}{{list}}{{dict}}{{zero}}',
            'data': {'null': None,
                     'false': False,
                     'list': [],
                     'dict': {},
                     'zero': 0
                     }
        }

        result = chevron.render(**args)
        expected = 'False0'

        self.assertEqual(result, expected)
Пример #45
0
    def test_complex(self):
        class Complex:
            def __init__(self):
                self.attr = 42

        args = {
            'template': '{{comp.attr}} {{int.attr}}',
            'data': {'comp': Complex(),
                     'int': 1
                     }
        }

        result = chevron.render(**args)
        expected = '42 '

        self.assertEqual(result, expected)
Пример #46
0
def render(element_html, data):
    if data['panel'] != 'question':
        return ''

    element = lxml.html.fragment_fromstring(element_html)
    file_name = pl.get_string_attrib(element, 'file-name', '')
    answer_name = get_answer_name(file_name)
    editor_config_function = pl.get_string_attrib(element, 'editor-config-function', None)
    ace_mode = pl.get_string_attrib(element, 'ace-mode', None)
    ace_theme = pl.get_string_attrib(element, 'ace-theme', None)
    uuid = pl.get_uuid()
    source_file_name = pl.get_string_attrib(element, 'source-file-name', None)

    html_params = {
        'name': answer_name,
        'file_name': file_name,
        'ace_mode': ace_mode,
        'ace_theme': ace_theme,
        'editor_config_function': editor_config_function,
        'uuid': uuid
    }

    if source_file_name is not None:
        file_path = os.path.join(data['options']['question_path'], source_file_name)
        text_display = open(file_path).read()
    else:
        if element.text is not None:
            text_display = str(element.text)
        else:
            text_display = ''

    html_params['original_file_contents'] = base64.b64encode(text_display.encode('UTF-8').strip()).decode()

    submitted_file_contents = data['submitted_answers'].get(answer_name, None)
    if submitted_file_contents:
        html_params['current_file_contents'] = submitted_file_contents
    else:
        html_params['current_file_contents'] = html_params['original_file_contents']

    if data['panel'] == 'question':
        html_params['question'] = True
        with open('pl-file-editor.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()
    else:
        html = ''

    return html
def run_benchmark():
    parser = argparse.ArgumentParser()
    parser.add_argument("-e", "--executable", help="path to the benchmark executable")
    parser.add_argument("-c", "--configuration", help="path to the benchmark configuration")
    args = parser.parse_args()

    configuration = json.load(open(args.configuration))

    os.makedirs("data", exist_ok=True)

    results = []
    for index, experiment in enumerate(configuration["experiments"]):
        results += [run_experiment(args.executable, configuration["algorithms"], experiment, index)]

    template = open("charts.mustache").read()
    html = chevron.render(template, {"chart": results})
    open("charts.html", "w").write(html)
Пример #48
0
def render(element_html, data):
    element = lxml.html.fragment_fromstring(element_html)
    engine = pl.get_string_attrib(element, 'engine', 'dot')

    # Read the contents of this element as the data to render
    # we dump the string to json to ensure that newlines are
    # properly encoded
    graphviz_data = json.dumps(str(element.text))

    html_params = {
        'uuid': pl.get_uuid(),
        'workerURL': '/node_modules/viz.js/full.render.js',
        'data': graphviz_data,
        'engine': engine,
    }

    with open('pl-graphviz-render.mustache') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #49
0
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
Пример #50
0
    def test_callable_2(self):

        def first(content, render):
            result = render(content)
            result = [x.strip() for x in result.split(" || ") if x.strip()]
            return result[0]

        args = {
            'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} '
                        '|| {{{village}}} || {{{state}}} {{/first}}',
            'data': {
                "postcode": "1234",
                "town": "Mustache Town",
                "state": "Nowhere",
                "first": first,
            }
        }

        result = chevron.render(**args)
        expected = '1234 Mustache Town'

        self.assertEqual(result, expected)
Пример #51
0
def render(element_html, data):
    if data['panel'] != 'submission':
        return ''

    html_params = {'uuid': pl.get_uuid()}

    # Fetch the list of required files for this question
    required_file_names = data['params'].get('_required_file_names', [])
    html_params['required_files'] = required_file_names

    # Fetch any submitted files
    submitted_files = data['submitted_answers'].get('_files', [])

    # Pass through format errors from the file input elements
    html_params['errors'] = data['format_errors'].get('_files', [])

    # Decode and reshape files into a useful form
    if len(submitted_files) > 0:
        files = []
        for idx, file in enumerate(submitted_files):
            try:
                contents = base64.b64decode(file['contents'] or '').decode()
            except UnicodeDecodeError:
                contents = 'Unable to decode file.'
            files.append({
                'name': file['name'],
                'contents': contents,
                'index': idx
            })
        html_params['has_files'] = True
        html_params['files'] = files
    else:
        html_params['has_files'] = False

    with open('pl-file-preview.mustache', 'r', encoding='utf-8') as f:
        html = chevron.render(f, html_params).strip()

    return html
Пример #52
0
    def test_callable_3(self):
        '''Test generating some data within the function
        '''

        def first(content, render):
            result = render(content, {'city': "Injected City"})
            result = [x.strip() for x in result.split(" || ") if x.strip()]
            return result[0]

        args = {
            'template': '{{{postcode}}} {{#first}} {{{city}}} || {{{town}}} '
                        '|| {{{village}}} || {{{state}}} {{/first}}',
            'data': {
                "postcode": "1234",
                "town": "Mustache Town",
                "state": "Nowhere",
                "first": first,
            }
        }

        result = chevron.render(**args)
        expected = '1234 Injected City'

        self.assertEqual(result, expected)
Пример #53
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)
    variables_string = pl.get_string_attrib(element, 'variables', None)
    variables = get_variables_list(variables_string)
    display = pl.get_string_attrib(element, 'display', 'inline')
    allow_complex = pl.get_boolean_attrib(element, 'allow-complex', False)
    imaginary_unit = pl.get_string_attrib(element, 'imaginary-unit-for-display', 'i')

    if data['panel'] == 'question':
        editable = data['editable']
        raw_submitted_answer = data['raw_submitted_answers'].get(name, None)

        operators = ', '.join(['cos', 'sin', 'tan', 'exp', 'log', 'sqrt', '( )', '+', '-', '*', '/', '^', '**'])
        constants = ', '.join(['pi, e'])

        info_params = {
            'format': True,
            'variables': variables_string,
            '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,
            'uuid': pl.get_uuid(),
            'allow_complex': allow_complex,
        }

        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:
            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)
        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)

        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)

        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
Пример #54
0
 def test():
     result = chevron.render(template, data)
     if result != expected:
         error = 'Test failed:\n-- got --\n{}\n-- expected --\n{}'
         raise Exception(error.format(result, expected))
Пример #55
0
def render(element_html, data):
    html_params = {
        'number': data['params']['random_number']
    }
    with open('course-element.mustache', 'r') as f:
        return chevron.render(f, html_params).strip()
Пример #56
0
def render(element_html, data):
    element = lxml.html.fragment_fromstring(element_html)
    answer_name = pl.get_string_attrib(element, 'answer-name')

    uuid = pl.get_uuid()

    body_position = get_position(element, 'body-position', default=[0, 0, 0])
    body_orientation = get_orientation(element, 'body-orientation', 'body-pose-format')
    camera_position = get_position(element, 'camera-position', default=[5, 2, 2], must_be_nonzero=True)
    body_cantranslate = pl.get_boolean_attrib(element, 'body-cantranslate', True)
    body_canrotate = pl.get_boolean_attrib(element, 'body-canrotate', True)
    camera_canmove = pl.get_boolean_attrib(element, 'camera-canmove', True)
    text_pose_format = pl.get_string_attrib(element, 'text-pose-format', 'matrix')
    if text_pose_format not in ['matrix', 'quaternion', 'homogeneous']:
        raise Exception('attribute "text-pose-format" must be either "matrix", "quaternion", or homogeneous')
    objects = get_objects(element, data)

    if data['panel'] == 'question':
        will_be_graded = pl.get_boolean_attrib(element, 'grade', True)
        show_pose = pl.get_boolean_attrib(element, 'show-pose-in-question', True)

        # Restore pose of body and camera, if available - otherwise use values
        # from attributes (note that restored pose will also have camera_orientation,
        # which we currently ignore because the camera is always z up and looking
        # at the origin of the space frame).
        #
        # Be careful. It's possible that data['submitted_answers'][answer_name]
        # exists but is None (due to some other error). So we need to use None
        # as the default and to check if the result - either from the existing
        # value or the default value - is None.
        pose_default = {
            'body_quaternion': body_orientation,
            'body_position': body_position,
            'camera_position': camera_position
        }
        pose = data['submitted_answers'].get(answer_name, None)
        if pose is None:
            pose = pose_default

        # These are passed as arguments to PLThreeJS constructor in client code
        options = {
            'uuid': uuid,
            'pose': dict_to_b64(pose),
            'pose_default': dict_to_b64(pose_default),
            'body_cantranslate': body_cantranslate,
            'body_canrotate': body_canrotate,
            'camera_canmove': camera_canmove,
            'text_pose_format': text_pose_format,
            'objects': objects
        }

        # These are used for templating
        html_params = {
            'question': True,
            'uuid': uuid,
            'answer_name': answer_name,
            'show_bodybuttons': body_cantranslate or body_canrotate,
            'show_toggle': body_cantranslate and body_canrotate,
            'show_reset': body_cantranslate or body_canrotate or camera_canmove,
            'show_pose': show_pose,
            'show_instructions': will_be_graded,
            'tol_translation': '{:.2f}'.format(pl.get_float_attrib(element, 'tol-translation', 0.5)),
            'tol_rotation': '{:.1f}'.format(pl.get_float_attrib(element, 'tol-rotation', 5)),
            'default_is_python': True,
            'options': json.dumps(options, allow_nan=False)
        }

        with open('pl-threejs.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()
    elif data['panel'] == 'submission':
        will_be_graded = pl.get_boolean_attrib(element, 'grade', True)
        if not will_be_graded:
            return ''

        show_pose = pl.get_boolean_attrib(element, 'show-pose-in-submitted-answer', True)

        # Get submitted answer
        pose = data['submitted_answers'].get(answer_name)

        # These are passed as arguments to PLThreeJS constructor in client code
        options = {
            'uuid': uuid,
            'pose': dict_to_b64(pose),
            'body_cantranslate': False,
            'body_canrotate': False,
            'camera_canmove': False,
            'text_pose_format': text_pose_format,
            'objects': objects
        }

        # These are used for templating
        html_params = {
            'submission': True,
            'uuid': uuid,
            'answer_name': answer_name,
            'show_bodybuttons': False,
            'show_toggle': False,
            'show_pose': show_pose,
            'default_is_python': True,
            'options': json.dumps(options, allow_nan=False)
        }

        partial_score = data['partial_scores'].get(answer_name, None)
        if partial_score is not None:
            html_params['error_in_translation'] = str(np.abs(np.round(partial_score['feedback']['error_in_translation'], 2)))
            html_params['error_in_rotation'] = str(np.abs(np.round(partial_score['feedback']['error_in_rotation'], 1)))
            html_params['show_feedback'] = True
            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-threejs.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()
    elif data['panel'] == 'answer':
        will_be_graded = pl.get_boolean_attrib(element, 'grade', True)
        if not will_be_graded:
            return ''

        show_pose = pl.get_boolean_attrib(element, 'show-pose-in-correct-answer', True)

        # Get submitted answer
        pose = data['submitted_answers'].get(answer_name, None)
        if pose is None:
            # If we are here, an error has occurred. Replace pose with its default.
            # (Only pose['camera_position'] is actually used.)
            pose = {
                'body_quaternion': body_orientation,
                'body_position': body_position,
                'camera_position': camera_position
            }

        # Get correct answer
        a = data['correct_answers'].get(answer_name, None)
        if a is None:
            return ''

        # Convert correct answer to Quaternion, then to [x, y, z, w]
        f = pl.get_string_attrib(element, 'answer-pose-format', 'rpy')
        p, q = parse_correct_answer(f, a)
        p = p.tolist()
        q = np.roll(q.elements, -1).tolist()

        # Replace body pose with correct answer
        pose['body_position'] = p
        pose['body_quaternion'] = q

        # These are passed as arguments to PLThreeJS constructor in client code
        options = {
            'uuid': uuid,
            'pose': dict_to_b64(pose),
            'body_cantranslate': False,
            'body_canrotate': False,
            'camera_canmove': False,
            'text_pose_format': text_pose_format,
            'objects': objects
        }

        # These are used for templating
        html_params = {
            'answer': True,
            'uuid': uuid,
            'answer_name': answer_name,
            'show_bodybuttons': False,
            'show_toggle': False,
            'show_pose': show_pose,
            'default_is_python': True,
            'options': json.dumps(options, allow_nan=False)
        }

        with open('pl-threejs.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()
    else:
        raise Exception('Invalid panel type: %s' % data['panel'])

    return html
Пример #57
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)

    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', 'relabs')
        if comparison == 'relabs':
            rtol = pl.get_float_attrib(element, 'rtol', 1e-2)
            atol = pl.get_float_attrib(element, 'atol', 1e-8)
            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', 2)
            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', 2)
            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', False)
        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,
            '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'] = escape(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:
            # 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')
        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-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', '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
                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', 2)
                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', 2)
                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
Пример #58
0
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
def render(element_html, data):
    if data['panel'] == 'submission':
        html_params = {'submission': True, 'graded': True, 'uuid': pl.get_uuid()}

        feedback = data['feedback']
        html_params['graded'] = bool(feedback)
        grading_succeeded = bool(feedback.get('succeeded', None))
        html_params['grading_succeeded'] = grading_succeeded
        if not grading_succeeded:
            html_params['message'] = feedback.get('message', None)
        else:
            results = feedback.get('results', None)
            if grading_succeeded and results:
                html_params['succeeded'] = bool(results.get('succeeded', None))
                html_params['score'] = format(results.get('score', 0) * 100, '.2f').rstrip('0').rstrip('.')
                html_params['achieved_max_points'] = (results.get('score', 0) >= 1.0)
                html_params['results_color'] = '#4CAF50' if (results.get('score', 0) >= 1.0) else '#F44336'
                html_params['has_message'] = bool(results.get('message', False))
                html_params['message'] = results.get('message', None)
                html_params['has_output'] = bool(results.get('output', False))
                html_params['output'] = results.get('output', None)
                html_params['has_message_or_output'] = bool(html_params['has_message'] or html_params['has_output'])

                results_tests = results.get('tests', None)
                html_params['has_tests'] = bool(results.get('tests', None))
                if results_tests:
                    # Let's not assume that people give us a valid array of tests
                    # If any test is missing either points or max_points, we'll
                    # disable detailed scores for all questions
                    tests_missing_points = False
                    for test in results_tests:
                        if test.get('points', None) is None:
                            tests_missing_points = True
                        if test.get('max_points', None) is None:
                            tests_missing_points = True
                    html_params['tests_missing_points'] = tests_missing_points

                    if not tests_missing_points:
                        html_params['points'] = sum(test['points'] for test in results_tests)
                        html_params['max_points'] = sum(test['max_points'] for test in results_tests)

                    # We need to build a new tests array to massage data a bit
                    tests = []
                    for index, results_test in enumerate(results_tests):
                        test = {}
                        test['index'] = index
                        test['name'] = results_test.get('name', '')
                        test['has_message'] = bool(results_test.get('message', None))
                        test['message'] = results_test.get('message', None)
                        test['has_output'] = bool(results_test.get('output', None))
                        test['output'] = results_test.get('output', None)
                        test['has_description'] = bool(results_test.get('description', None))
                        test['description'] = results_test.get('description', None)
                        if not tests_missing_points:
                            test['max_points'] = results_test.get('max_points')
                            test['points'] = results_test.get('points')
                            correct = test['max_points'] == test['points']
                            test['results_color'] = '#4CAF50' if correct else '#F44336'
                            test['results_icon'] = 'fa-check' if correct else 'fa-times'
                        tests.append(test)

                    html_params['tests'] = tests

        with open('pl-external-grader-results.mustache', 'r', encoding='utf-8') as f:
            html = chevron.render(f, html_params).strip()
    else:
        html = ''

    return html
Пример #60
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', 'inline')

    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,
            '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-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:
            # 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)
        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-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