コード例 #1
0
 def join_children(self, path, lang1, c1_list, lang2, c2_list):
     c_list = []
     for i,c1 in enumerate(
         self.require_identical_list_len(path, lang1, c1_list, lang2, c2_list)
     ):
         c2 = c2_list[i]
         c_path = path + [str(i + 1)]
         c = {}
         self.require_identical_dict_keys(c_path, lang1, c1, lang2, c2, ACCEPTED_CHILDREN_DEFAULT_KEYS)
         key = join_keys(lang1, c1.get('key', ''), lang2, c2.get('key', ''))
         for k,v in c1.items():
             if k == 'key':
                 c[k] = key
             elif k in ('name', 'title', 'static_content'):
                 c[k] = join_values(lang1, v, lang2, c2.get(k, v))
             elif k == 'config':
                 e1 = yaml_writer.read(yaml_writer.file_path(self.app.env, v))
                 e2 = yaml_writer.read(yaml_writer.file_path(self.app.env, c2.get(k, v)))
                 yaml_writer.write(
                     yaml_writer.file_path(self.app.env, key),
                     self.join_exercises(key, lang1, e1, lang2, e2)
                 )
                 c[k] = key + '.yaml'
             elif k == 'children':
                 c[k] = self.join_children(c_path, lang1, v, lang2, c2.get(k, []))
             elif deep_equals(v, c2.get(k, v)):
                 c[k] = v
             else:
                 self.raise_unequal(c_path, lang2, k)
         c_list.append(c)
     return c_list
コード例 #2
0
    def run(self):
        env = self.state.document.settings.env

        if not 'config' in self.options:
            raise SphinxError('Config option is required')
        import os
        path = os.path.join(env.app.srcdir, self.options['config'])
        if not os.path.exists(path):
            raise SphinxError('Missing config path {}'.format(self.options['config']))
        item_list = yaml_writer.read(path)

        itemnodes = []
        for item in item_list:
            title, info, img = [item.get(u"title", u""), item.get(u"info", u""), item.get(u"image_url", u"")]
            _, node, data = self.create_question(title_text=self.arguments[0].replace(u"$title", title), points=False)

            more = u""
            if img:
                e = aplus_nodes.html(u"p", {u"class": u"indent"})
                e.append(aplus_nodes.html(u"img", {u"src":img, u"alt": title, u"style": u"max-height:100px;"}))
                node.append(e)
                more += str(e)
            if info:
                e = aplus_nodes.html(u"p", {u"class": u"indent"})
                e.append(nodes.Text(info))
                node.append(e)
                more += str(e)

            data[u'options'] = self.generate_options(env, node)
            data[u'more'] = more
            itemnodes.append(node)

        return itemnodes
コード例 #3
0
    def run(self):
        env = self.state.document.settings.env

        if not 'config' in self.options:
            raise SphinxError('Config option is required')
        import os
        path = os.path.join(env.app.srcdir, self.options['config'])
        if not os.path.exists(path):
            raise SphinxError('Missing config path {}'.format(self.options['config']))
        item_list = yaml_writer.read(path)

        itemnodes = []
        for item in item_list:
            title, info, img = [item.get(u"title", u""), item.get(u"info", u""), item.get(u"image_url", u"")]
            _, node, data = self.create_question(title_text=self.arguments[0].replace(u"$title", title), points=False)

            more = u""
            if img:
                e = aplus_nodes.html(u"p", {u"class": u"indent"})
                e.append(aplus_nodes.html(u"img", {u"src":img, u"alt": title, u"style": u"max-height:100px;"}))
                node.append(e)
                more += str(e)
            if info:
                e = aplus_nodes.html(u"p", {u"class": u"indent"})
                e.append(nodes.Text(info))
                node.append(e)
                more += str(e)

            data[u'options'] = self.generate_options(env, node)
            data[u'more'] = more
            itemnodes.append(node)

        return itemnodes
コード例 #4
0
ファイル: toc_config.py プロジェクト: piehei/a-plus-rst-tools
def append_manual_content(app, index):
    def recursive_merge(config, append):
        if type(append) == dict:
            for key, val in append.items():
                if not key in config:
                    config[key] = val
                else:
                    recursive_merge(config[key], append[key])
        elif type(append) == list:
            for entry in append:
                add = True
                if 'key' in entry:
                    for old in config:
                        if 'key' in old and old['key'] == entry['key']:
                            recursive_merge(old, entry)
                            add = False
                if add:
                    config.append(entry)

    for path in app.config.append_content:
        recursive_merge(index, yaml_writer.read(path))
コード例 #5
0
ファイル: toc_config.py プロジェクト: piehei/a-plus-rst-tools
    def parse_chapter(docname, doc, parent):
        for config_file in [
                e.yaml_write for e in doc.traverse(aplus_nodes.html)
                if e.has_yaml(u'exercise')
        ]:
            config = yaml_writer.read(config_file)
            if config.get(u'_external', False):
                exercise = config.copy()
                del exercise[u'_external']
            else:
                exercise = {
                    u'key':
                    config[u'key'],
                    u'config':
                    config[u'key'] + u'.yaml',
                    u'max_submissions':
                    config.get(u'max_submissions', 0),
                    u'max_points':
                    config.get(u'max_points', 0),
                    u'difficulty':
                    config.get(u'difficulty', ''),
                    u'points_to_pass':
                    config.get(u'points_to_pass', 0),
                    u'category':
                    config[u'category'],
                    u'min_group_size':
                    config.get(u'min_group_size', 1),
                    u'max_group_size':
                    config.get(u'max_group_size', 1),
                    u'confirm_the_level':
                    config.get(u'confirm_the_level', False),
                    u'allow_assistant_grading':
                    config.get(u'allow_assistant_grading', False),
                }
            exercise.update({
                u'status': u'unlisted',
            })
            if u'scale_points' in config:
                exercise[u'max_points'] = config.pop(u'scale_points')
            parent.append(exercise)
            if not config[u'category'] in category_keys:
                category_keys.append(config[u'category'])

        category = u'chapter'
        for name, hidden, child in traverse_tocs(app, doc):
            meta = first_meta(child)
            status = u'hidden' if 'hidden' in meta else (
                u'unlisted' if hidden else u'ready')
            chapter = {
                u'key': name.split(u'/')[-1],  #name.replace('/', '_'),
                u'status': status,
                u'name': first_title(child),
                u'static_content': name + u'.html',
                u'category': category,
                u'use_wide_column': app.config.use_wide_column,
                u'children': [],
            }
            if meta:
                audience = meta.get('audience')
                if audience:
                    chapter[u'audience'] = yaml_writer.ensure_unicode(audience)
            if category in override:
                chapter.update(override[category])
            parent.append(chapter)
            if not u'chapter' in category_keys:
                category_keys.append(u'chapter')
            parse_chapter(name, child, chapter[u'children'])
コード例 #6
0
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        classes = [u'exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])

        # Add document nodes.
        args = {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
            u'data-aplus-active-element': u'out',
            u'data-inputs': u''+ self.options.get('inputs', ''),
        }

        if 'inputs' not in self.options:
            raise self.warning("The input list for output '{:s}' is empty.".format(key))

        if 'type' in self.options:
            args['data-type'] = self.options['type']
        else:
            args['data-type'] = 'text'

        if 'scale-size' in self.options:
            args['data-scale'] = ''

        if 'title' in self.options:
            args['data-title'] = self.options['title']

        if 'width' in self.options:
            args['style'] = 'width:'+ self.options['width'] + ';'

        if 'height' in self.options:
            if 'style' not in args:
                args['style'] = 'height:'+ self.options['height'] + ';'
            else:
                args['style'] = args['style'] + 'height:'+ self.options['height'] + ';'

        if 'clear' in self.options:
            args['style'] = args['style'] + 'clear:'+ self.options['clear'] + ';'

        node = aplus_nodes.html(u'div', args)
        paragraph = aplus_nodes.html(u'p', {})
        paragraph.append(nodes.Text(translations.get(env, 'submit_placeholder')))
        node.append(paragraph)

        key_title = u"{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get(u'title', None)
        else:
            data = { u'_external': True }
            if 'url' in self.options:
                data[u'url'] = ensure_unicode(self.options['url'])
            config_title = None

        config_title = self.options.get('title', config_title)

        category = u'submit'
        data.update({
            u'key': name,
            u'title': env.config.submit_title.format(
                key_title=key_title, config_title=config_title
            ),
            u'category': u'active elements',
            u'max_submissions': self.options.get('submissions', data.get('max_submissions', env.config.ae_default_submissions)),
        })

        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        node.write_yaml(env, name, data, 'exercise')

        return [node]
コード例 #7
0
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = "{}_{}".format(env.docname.replace('/', '_'), key)
        override = env.config.override

        classes = ['exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])
        if difficulty:
            classes.append('difficulty-' + difficulty)

        # Add document nodes.
        args = {
            'class': ' '.join(classes),
            'data-aplus-exercise': 'yes',
        }
        if 'quiz' in self.options:
            args['data-aplus-quiz'] = 'yes'
        if 'ajax' in self.options:
            args['data-aplus-ajax'] = 'yes'
        node = aplus_nodes.html('div', args)

        key_title = "{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(
                    self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get('title', '')
        else:
            data = {'_external': True}
            if 'url' in self.options:
                data['url'] = self.options['url']
            if 'lti' in self.options:
                data.update({
                    'lti':
                    self.options['lti'],
                    'lti_context_id':
                    self.options.get('lti_context_id', ''),
                    'lti_resource_link_id':
                    self.options.get('lti_resource_link_id', ''),
                })
                if 'lti_aplus_get_and_post' in self.options:
                    data.update({'lti_aplus_get_and_post': True})
                if 'lti_open_in_iframe' in self.options:
                    data.update({'lti_open_in_iframe': True})
            config_title = ''

        config_title = self.options.get('title', config_title)
        if "radar_tokenizer" in self.options or "radar_minimum_match_tokens" in self.options:
            data['radar_info'] = {
                'tokenizer':
                self.options.get("radar_tokenizer"),
                'minimum_match_tokens':
                self.options.get("radar_minimum_match_tokens"),
            }

        category = 'submit'
        data.update({
            'key':
            name,
            'category':
            'submit',
            'scale_points':
            points,
            'difficulty':
            difficulty or '',
            'max_submissions':
            self.options.get(
                'submissions',
                data.get('max_submissions',
                         env.config.program_default_submissions)),
            'min_group_size':
            data.get('min_group_size', env.config.default_min_group_size),
            'max_group_size':
            data.get('max_group_size', env.config.default_max_group_size),
            'points_to_pass':
            self.options.get('points-to-pass', data.get('points_to_pass', 0)),
            # The RST source file path is needed for fixing relative URLs
            # in the exercise description.
            # Replace the Windows path separator backslash \ with the Unix forward slash /.
            '_rst_srcpath':
            env.doc2path(env.docname, None).replace('\\', '/'),
        })
        self.set_assistant_permissions(data)

        if data.get('title|i18n'):
            # Exercise config.yaml defines title|i18n for multiple languages.
            # Do not write the field "title" to data in order to avoid conflicts.
            if config_title:
                # Overwrite the title for one language since the RST directive
                # has defined the title option (or alternatively, the yaml file
                # has "title" in addition to "title|i18n", but that does not make sense).
                # env.config.language may be incorrect if the language can not be detected.
                data['title|i18n'][
                    env.config.language] = env.config.submit_title.format(
                        key_title=key_title, config_title=config_title)
        else:
            formatted_title = env.config.submit_title.format(
                key_title=key_title, config_title=config_title)
            # If no title has been defined, use key_title as the default.
            data['title'] = formatted_title if formatted_title else key_title

        if self.content:
            self.assert_has_content()
            # Sphinx can not compile the nested RST into HTML at this stage, hence
            # the HTML instructions defined in this directive body are added to
            # the exercise YAML file only at the end of the build. Sphinx calls
            # the visit functions of the nodes in the last writing phase.
            # The instructions are added to the YAML file in the depart_html
            # function in aplus_nodes.py.
            exercise_description = aplus_nodes.html('div', {})
            exercise_description.store_html('exercise_description')
            nested_parse_with_titles(self.state, self.content,
                                     exercise_description)
            node.append(exercise_description)
            data['instructions'] = ('#!html', 'exercise_description')
        else:
            # The placeholder text is only used in the built HTML
            # (not in the YAML configurations).
            paragraph = aplus_nodes.html('p', {})
            paragraph.append(
                nodes.Text(translations.get(env, 'submit_placeholder')))
            node.append(paragraph)

        data.setdefault('status', self.options.get('status', 'unlisted'))

        source, line = self.state_machine.get_source_and_line(self.lineno)
        if 'reveal-submission-feedback' in self.options:
            data['reveal_submission_feedback'] = parse_reveal_rule(
                self.options['reveal-submission-feedback'],
                source,
                line,
                'reveal-submission-feedback',
            )
        if 'reveal-model-solutions' in self.options:
            data['reveal_model_solutions'] = parse_reveal_rule(
                self.options['reveal-model-solutions'],
                source,
                line,
                'reveal-model-solutions',
            )

        if 'grading-mode' in self.options:
            data['grading_mode'] = self.options['grading-mode']

        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        if 'category' in self.options:
            data['category'] = str(self.options['category'])

        node.write_yaml(env, name, data, 'exercise')

        return [node]
コード例 #8
0
ファイル: submit.py プロジェクト: roosapi/a-plus-rst-tools
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        classes = [u'exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])
        if difficulty:
            classes.append(u'difficulty-' + difficulty)

        # Add document nodes.
        args = {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
        }
        if 'quiz' in self.options:
            args[u'data-aplus-quiz'] = u'yes'
        if 'ajax' in self.options:
            args[u'data-aplus-ajax'] = u'yes'
        node = aplus_nodes.html(u'div', args)
        paragraph = aplus_nodes.html(u'p', {})
        paragraph.append(
            nodes.Text(translations.get(env, 'submit_placeholder')))
        node.append(paragraph)

        key_title = u"{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(
                    self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get(u'title', None)
        else:
            data = {u'_external': True}
            if 'url' in self.options:
                data[u'url'] = ensure_unicode(self.options['url'])
            if 'lti' in self.options:
                data.update({
                    u'lti':
                    ensure_unicode(self.options['lti']),
                    u'lti_context_id':
                    ensure_unicode(self.options.get('lti_context_id', u'')),
                    u'lti_resource_link_id':
                    ensure_unicode(
                        self.options.get('lti_resource_link_id', u'')),
                })
            config_title = None

        config_title = self.options.get('title', config_title)
        if "radar_tokenizer" in self.options or "radar_minimum_match_tokens" in self.options:
            data[u'radar_info'] = {
                u'tokenizer':
                self.options.get("radar_tokenizer"),
                u'minimum_match_tokens':
                self.options.get("radar_minimum_match_tokens"),
            }

        category = u'submit'
        data.update({
            u'key':
            name,
            u'title':
            env.config.submit_title.format(key_title=key_title,
                                           config_title=config_title),
            u'category':
            u'submit',
            u'scale_points':
            points,
            u'difficulty':
            difficulty or '',
            u'max_submissions':
            self.options.get(
                'submissions',
                data.get('max_submissions',
                         env.config.program_default_submissions)),
            u'min_group_size':
            data.get('min_group_size', env.config.default_min_group_size),
            u'max_group_size':
            data.get('max_group_size', env.config.default_max_group_size),
            u'points_to_pass':
            self.options.get('points-to-pass', data.get('points_to_pass', 0)),
        })
        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        if 'category' in self.options:
            data['category'] = str(self.options['category'])

        node.write_yaml(env, name, data, 'exercise')

        return [node]
コード例 #9
0
    def parse_chapter(docname, doc, parent, module_meta):
        for config_file in [e.yaml_write for e in doc.traverse(aplus_nodes.html) if e.has_yaml('exercise')]:
            config = yaml_writer.read(config_file)
            if config.get('_external', False):
                exercise = config.copy()
                del exercise['_external']
            else:
                exercise = {
                    'key': config['key'],
                    'config': config['key'] + '.yaml',
                    'max_submissions': config.get('max_submissions', 0),
                    'max_points': config.get('max_points', 0),
                    'difficulty': config.get('difficulty', ''),
                    'points_to_pass': config.get('points_to_pass', 0),
                    'category': config['category'],
                    'min_group_size': config.get('min_group_size', 1),
                    'max_group_size': config.get('max_group_size', 1),
                    'confirm_the_level': config.get('confirm_the_level', False),
                }
            allow_assistant_viewing = config.get('allow_assistant_viewing', app.config.allow_assistant_viewing)
            allow_assistant_grading = config.get('allow_assistant_grading', app.config.allow_assistant_grading)
            exercise.update({
                'status': config.get('status', 'unlisted'),
                'allow_assistant_viewing': allow_assistant_viewing,
                'allow_assistant_grading': allow_assistant_grading,
            })
            if 'scale_points' in config:
                exercise['max_points'] = config.pop('scale_points')

            # Reveal rules: try exercise config, then module meta, then course config.
            reveal_submission_feedback = config.get(
                'reveal_submission_feedback',
                module_meta.get(
                    'reveal-submission-feedback',
                    course_reveal_submission_feedback,
                )
            )
            if reveal_submission_feedback:
                exercise['reveal_submission_feedback'] = reveal_submission_feedback.copy()

            reveal_model_solutions = config.get(
                'reveal_model_solutions',
                module_meta.get(
                    'reveal-model-solutions',
                    course_reveal_model_solutions,
                )
            )
            if reveal_model_solutions:
                exercise['reveal_model_solutions'] = reveal_model_solutions.copy()

            if 'grading_mode' in config:
                exercise['grading_mode'] = config.pop('grading_mode')

            parent.append(exercise)
            if not config['category'] in category_keys:
                category_keys.append(config['category'])

        for config_file in [e.yaml_write for e in doc.traverse(aplus_nodes.html) if e.has_yaml('exercisecollection')]:
            config = yaml_writer.read(config_file)
            exercise = {
                'key': config['key'],
                'max_points': config.get('max_points', 0),
                'points_to_pass': config.get('points_to_pass', 0),
                'target_url': config['target_url'],
                'target_category': config['target_category'],
                'category': config['category'],
                'status': config.get('status', 'unlisted'),
                'title': config['title'],
            }
            parent.append(exercise)
            if not config['category'] in category_keys:
                category_keys.append(config['category'])


        category = 'chapter'
        for name,hidden,child in traverse_tocs(app, doc):
            meta = first_meta(child)
            status = 'hidden' if 'hidden' in meta else (
                'unlisted' if hidden else 'ready'
            )
            chapter = {
                'status': status,
                'name': first_title(child),
                'static_content': name + '.html',
                'category': category,
                'use_wide_column': app.config.use_wide_column,
                'children': [],
            }
            # If the chapter RST file is in a nested directory under the module
            # directory (e.g., module01/material/chapter.rst instead of
            # module01/chapter.rst), then the chapter key must contain parts of
            # the nested directory names in order to be unique within the module.
            # Different directories could contain files with the same names.
            key_parts = name.split('/')
            chapter['key'] = '_'.join(key_parts[1:])

            if meta:
                audience = meta.get('audience')
                if audience:
                    chapter['audience'] = audience
            if category in override:
                chapter.update(override[category])
            parent.append(chapter)
            if not 'chapter' in category_keys:
                category_keys.append('chapter')
            parse_chapter(name, child, chapter['children'], module_meta)
コード例 #10
0
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        classes = [u'exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])

        # Add document nodes.
        args = {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
            u'data-aplus-active-element': u'out',
            u'data-inputs': u''+ self.options.get('inputs', ''),
        }

        if 'inputs' not in self.options:
            raise self.warning("The input list for output '{:s}' is empty.".format(key))

        if 'type' in self.options:
            args['data-type'] = self.options['type']
        else:
            args['data-type'] = 'text'

        if 'scale-size' in self.options:
            args['data-scale'] = ''

        if 'title' in self.options:
            args['data-title'] = self.options['title']

        if 'width' in self.options:
            args['style'] = 'width:'+ self.options['width'] + ';'

        if 'height' in self.options:
            if 'style' not in args:
                args['style'] = 'height:'+ self.options['height'] + ';'
            else:
                args['style'] = args['style'] + 'height:'+ self.options['height'] + ';'

        if 'clear' in self.options:
            args['style'] = args['style'] + 'clear:'+ self.options['clear'] + ';'

        node = aplus_nodes.html(u'div', args)
        paragraph = aplus_nodes.html(u'p', {})
        paragraph.append(nodes.Text(translations.get(env, 'submit_placeholder')))
        node.append(paragraph)

        key_title = u"{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get(u'title', None)
        else:
            data = { u'_external': True }
            if 'url' in self.options:
                data[u'url'] = ensure_unicode(self.options['url'])
            config_title = None

        config_title = self.options.get('title', config_title)

        category = u'submit'
        data.update({
            u'key': name,
            u'title': env.config.submit_title.format(
                key_title=key_title, config_title=config_title
            ),
            u'category': u'active elements',
            u'max_submissions': self.options.get('submissions', data.get('max_submissions', env.config.ae_default_submissions)),
        })
        data.setdefault('status', self.options.get('status', 'unlisted'))
        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        node.write_yaml(env, name, data, 'exercise')

        return [node]
コード例 #11
0
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        classes = [u'exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])
        if difficulty:
            classes.append(u'difficulty-' + difficulty)

        # Add document nodes.
        args = {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
        }
        if 'quiz' in self.options:
            args[u'data-aplus-quiz'] = u'yes'
        if 'ajax' in self.options:
            args[u'data-aplus-ajax'] = u'yes'
        node = aplus_nodes.html(u'div', args)
        paragraph = aplus_nodes.html(u'p', {})
        paragraph.append(nodes.Text(translations.get(env, 'submit_placeholder')))
        node.append(paragraph)

        key_title = u"{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get(u'title', None)
        else:
            data = { u'_external': True }
            if 'url' in self.options:
                data[u'url'] = ensure_unicode(self.options['url'])
            if 'lti' in self.options:
                data.update({
                    u'lti': ensure_unicode(self.options['lti']),
                    u'lti_context_id': ensure_unicode(self.options.get('lti_context_id', u'')),
                    u'lti_resource_link_id': ensure_unicode(self.options.get('lti_resource_link_id', u'')),
                })
            config_title = None

        config_title = self.options.get('title', config_title)
        if "radar_tokenizer" in self.options or "radar_minimum_match_tokens" in self.options:
            data[u'radar_info'] = {
                u'tokenizer': self.options.get("radar_tokenizer"),
                u'minimum_match_tokens': self.options.get("radar_minimum_match_tokens"),
            }

        category = u'submit'
        data.update({
            u'key': name,
            u'title': env.config.submit_title.format(
                key_title=key_title, config_title=config_title
            ),
            u'category': u'submit',
            u'scale_points': points,
            u'difficulty': difficulty or '',
            u'max_submissions': self.options.get('submissions', data.get('max_submissions', env.config.program_default_submissions)),
            u'min_group_size': data.get('min_group_size', env.config.default_min_group_size),
            u'max_group_size': data.get('max_group_size', env.config.default_max_group_size),
            u'points_to_pass': self.options.get('points-to-pass', data.get('points_to_pass', 0)),
        })
        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        if 'category' in self.options:
            data['category'] = str(self.options['category'])

        node.write_yaml(env, name, data, 'exercise')

        return [node]
コード例 #12
0
    def parse_chapter(docname, doc, parent):
        for config_file in [e.yaml_write for e in doc.traverse(aplus_nodes.html) if e.has_yaml(u'exercise')]:
            config = yaml_writer.read(config_file)
            if config.get(u'_external', False):
                exercise = config.copy()
                del exercise[u'_external']
            else:
                exercise = {
                    u'key': config[u'key'],
                    u'config': config[u'key'] + u'.yaml',
                    u'max_submissions': config.get(u'max_submissions', 0),
                    u'max_points': config.get(u'max_points', 0),
                    u'difficulty': config.get(u'difficulty', ''),
                    u'points_to_pass': config.get(u'points_to_pass', 0),
                    u'category': config[u'category'],
                    u'min_group_size': config.get(u'min_group_size', 1),
                    u'max_group_size': config.get(u'max_group_size', 1),
                    u'confirm_the_level': config.get(u'confirm_the_level', False),
                }
            allow_assistant_viewing = config.get(u'allow_assistant_viewing', app.config.allow_assistant_viewing)
            allow_assistant_grading = config.get(u'allow_assistant_grading', app.config.allow_assistant_grading)
            exercise.update({
                u'status': config.get(u'status', u'unlisted'),
                u'allow_assistant_viewing': allow_assistant_viewing,
                u'allow_assistant_grading': allow_assistant_grading,
            })
            if u'scale_points' in config:
                exercise[u'max_points'] = config.pop(u'scale_points')
            parent.append(exercise)
            if not config[u'category'] in category_keys:
                category_keys.append(config[u'category'])

        for config_file in [e.yaml_write for e in doc.traverse(aplus_nodes.html) if e.has_yaml(u'exercisecollection')]:
            config = yaml_writer.read(config_file)
            exercise = {
                u'key': config[u'key'],
                u'max_points': config.get(u'max_points', 0),
                u'points_to_pass': config.get(u'points_to_pass', 0),
                u'target_url': config[u'target_url'],
                u'target_category': config[u'target_category'],
                u'category': config[u'category'],
                u'status': config.get(u'status', u'unlisted'),
                u'title': config[u'title'],
            }
            parent.append(exercise)
            if not config[u'category'] in category_keys:
                category_keys.append(config[u'category'])


        category = u'chapter'
        for name,hidden,child in traverse_tocs(app, doc):
            meta = first_meta(child)
            status = u'hidden' if 'hidden' in meta else (
                u'unlisted' if hidden else u'ready'
            )
            chapter = {
                u'status': status,
                u'name': first_title(child),
                u'static_content': name + u'.html',
                u'category': category,
                u'use_wide_column': app.config.use_wide_column,
                u'children': [],
            }
            # If the chapter RST file is in a nested directory under the module
            # directory (e.g., module01/material/chapter.rst instead of
            # module01/chapter.rst), then the chapter key must contain parts of
            # the nested directory names in order to be unique within the module.
            # Different directories could contain files with the same names.
            key_parts = name.split('/')
            chapter['key'] = '_'.join(key_parts[1:])

            if meta:
                audience = meta.get('audience')
                if audience:
                    chapter[u'audience'] = yaml_writer.ensure_unicode(audience)
            if category in override:
                chapter.update(override[category])
            parent.append(chapter)
            if not u'chapter' in category_keys:
                category_keys.append(u'chapter')
            parse_chapter(name, child, chapter[u'children'])
コード例 #13
0
    def run(self):
        key, difficulty, points = self.extract_exercise_arguments()

        env = self.state.document.settings.env
        name = u"{}_{}".format(env.docname.replace(u'/', u'_'), key)
        override = env.config.override

        classes = [u'exercise']
        if 'class' in self.options:
            classes.extend(self.options['class'])
        if difficulty:
            classes.append(u'difficulty-' + difficulty)

        # Add document nodes.
        args = {
            u'class': u' '.join(classes),
            u'data-aplus-exercise': u'yes',
        }
        if 'quiz' in self.options:
            args[u'data-aplus-quiz'] = u'yes'
        if 'ajax' in self.options:
            args[u'data-aplus-ajax'] = u'yes'
        node = aplus_nodes.html(u'div', args)

        key_title = u"{} {}".format(translations.get(env, 'exercise'), key)

        # Load or create exercise configuration.
        if 'config' in self.options:
            path = os.path.join(env.app.srcdir, self.options['config'])
            if not os.path.exists(path):
                raise SphinxError('Missing config path {}'.format(self.options['config']))
            data = yaml_writer.read(path)
            config_title = data.get(u'title', None)
        else:
            data = { u'_external': True }
            if 'url' in self.options:
                data[u'url'] = ensure_unicode(self.options['url'])
            if 'lti' in self.options:
                data.update({
                    u'lti': ensure_unicode(self.options['lti']),
                    u'lti_context_id': ensure_unicode(self.options.get('lti_context_id', u'')),
                    u'lti_resource_link_id': ensure_unicode(self.options.get('lti_resource_link_id', u'')),
                })
                if 'lti_aplus_get_and_post' in self.options:
                    data.update({u'lti_aplus_get_and_post': True})
                if 'lti_open_in_iframe' in self.options:
                    data.update({u'lti_open_in_iframe': True})
            config_title = None

        config_title = self.options.get('title', config_title)
        if "radar_tokenizer" in self.options or "radar_minimum_match_tokens" in self.options:
            data[u'radar_info'] = {
                u'tokenizer': self.options.get("radar_tokenizer"),
                u'minimum_match_tokens': self.options.get("radar_minimum_match_tokens"),
            }

        category = u'submit'
        data.update({
            u'key': name,
            u'title': env.config.submit_title.format(
                key_title=key_title, config_title=config_title
            ),
            u'category': u'submit',
            u'scale_points': points,
            u'difficulty': difficulty or '',
            u'max_submissions': self.options.get('submissions', data.get('max_submissions', env.config.program_default_submissions)),
            u'min_group_size': data.get('min_group_size', env.config.default_min_group_size),
            u'max_group_size': data.get('max_group_size', env.config.default_max_group_size),
            u'points_to_pass': self.options.get('points-to-pass', data.get('points_to_pass', 0)),
        })
        self.set_assistant_permissions(data)

        if self.content:
            self.assert_has_content()
            nested_parse_with_titles(self.state, self.content, node)
            # Sphinx can not compile the nested RST into HTML at this stage, hence
            # the HTML instructions defined in this directive body are added to
            # the exercise YAML file only at the end of the build. Sphinx calls
            # the visit functions of the nodes in the last writing phase.
            # The instructions are added to the YAML file in the depart_html
            # function in aplus_nodes.py.
        else:
            paragraph = aplus_nodes.html(u'p', {})
            paragraph.append(nodes.Text(translations.get(env, 'submit_placeholder')))
            node.append(paragraph)

        data.setdefault('status', self.options.get('status', 'unlisted'))

        if category in override:
            data.update(override[category])
            if 'url' in data:
                data['url'] = data['url'].format(key=name)

        if 'category' in self.options:
            data['category'] = str(self.options['category'])

        node.write_yaml(env, name, data, 'exercise')

        return [node]