Example #1
0
    def run(self):
        """ Restructured text extension for including inline JSAV content on module pages """
        self.options['exer_name'] = self.arguments[0]
        self.options['type'] = self.arguments[1]
        self.options['odsa_path'] = os.path.relpath(conf.odsa_path,conf.ebook_path)
 
        # Set defaults for any values that aren't configured
        if 'required' not in self.options:
          self.options['required'] = False
        
        if 'points' not in self.options:
          self.options['points'] = 0
        
        if 'threshold' not in self.options:
          self.options['threshold'] = 1.0
        
        if 'long_name' not in self.options:
          self.options['long_name'] = self.options['exer_name']
        
        if 'align' not in self.options:
          self.options['align'] = 'center'
 
        if 'output' in self.options and self.options['output'] == "show":
          self.options['output_code'] = '<p class="jsavoutput jsavline"></p>'
        else:
          self.options['output_code'] = ''
        
        if self.options['type'] == "dgm":
          avdgm_node = av_dgm()
          anchor_node = av_anchor()

          avdgm_node['exer_name'] = self.options['exer_name']
          anchor_node['ids'].append(self.options['exer_name'])
          avdgm_node += anchor_node
          if self.content:
            node = nodes.Element()          # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                caption['align']= self.options['align']
                avdgm_node += caption

          return [avdgm_node]
        elif self.options['type'] == "ss" and self.content:
          avss_node = av_ss()
          avss_node['res'] = SLIDESHOW % self.options
          node = nodes.Element()          # anonymous container for parsing
          self.state.nested_parse(self.content, self.content_offset, node)
          first_node = node[0]
          if isinstance(first_node, nodes.paragraph):
             caption = nodes.caption(first_node.rawsource, '',
                                     *first_node.children)
             caption['align']= self.options['align']
             avss_node += caption
          return [avss_node]
        else:
          res = SLIDESHOW % self.options
          return [nodes.raw('', res, format='html')] 
Example #2
0
    def run(self):
        env = self.state.document.settings.env
        repo = Repo(env.srcdir)
        commits = repo.iter_commits()
        l = nodes.bullet_list()
        for commit in list(commits)[:10]:
            date_str = datetime.fromtimestamp(commit.authored_date)
            if '\n' in commit.message:
                message, detailed_message = commit.message.split('\n', 1)
            else:
                message = commit.message
                detailed_message = None

            item = nodes.list_item()
            item += [
                nodes.strong(text=message),
                nodes.inline(text=" by "),
                nodes.emphasis(text=str(commit.author)),
                nodes.inline(text=" at "),
                nodes.emphasis(text=str(date_str))
            ]
            if detailed_message:
                item.append(nodes.caption(text=detailed_message.strip()))
            l.append(item)
        return [l]
Example #3
0
    def run(self):
        label = self.options.get('label', None)
        spec = self.options.get('spec', None)
        caption = self.options.get('caption', None)
        alt = self.options.get('alt', None)
        nofig = 'nofig' in self.options
        loc = self.options.get('loc', None)
        
        figtable_node = figtable('', ids=[label] if label is not None else [])
        figtable_node['nofig'] = nofig
        
        if spec is not None:
            table_spec_node = addnodes.tabular_col_spec()
            table_spec_node['spec'] = spec
            figtable_node.append(table_spec_node)
        
        node = nodes.Element()
        self.state.nested_parse(self.content, self.content_offset, node)
        tablenode = node[0]
        if alt is not None:
            tablenode['alt'] = alt
        figtable_node.append(tablenode)
        
        if caption is not None:
            caption_node = nodes.caption('', '', nodes.Text(caption))
            figtable_node.append(caption_node)
        
        if label is not None:
            targetnode = nodes.target('', '', ids=[label])
            figtable_node.append(targetnode)

        if loc is not None:
            figtable_node['loc'] = '[' + loc + ']'

        return [figtable_node]
Example #4
0
    def run(self):
        figclasses = self.options.pop('figclass', None)
        (image_node,) = Image.run(self)
        if isinstance(image_node, nodes.system_message):
            return [image_node]
        figure_node = nodes.figure('', image_node)
        if figclasses:
            figure_node['classes'] += figclasses
        figure_node['classes'] += ['m-figure']

        if self.content:
            node = nodes.Element()          # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                caption.source = first_node.source
                caption.line = first_node.line
                figure_node += caption
            elif not (isinstance(first_node, nodes.comment)
                      and len(first_node) == 0):
                error = self.state_machine.reporter.error(
                      'Figure caption must be a paragraph or empty comment.',
                      nodes.literal_block(self.block_text, self.block_text),
                      line=self.lineno)
                return [figure_node, error]
            if len(node) > 1:
                figure_node += nodes.legend('', *node[1:])
        return [figure_node]
Example #5
0
    def run(self):
        results = super(BlockdiagDirective, self).run()

        node = results[0]
        if not isinstance(node, self.node_class):
            return results

        try:
            diagram = self.node2diagram(node)
        except Exception as e:
            raise self.warning(e.message)

        if 'desctable' in node['options']:
            del node['options']['desctable']
            results += self.description_tables(diagram)

        results[0] = self.node2image(node, diagram)

        if 'caption' in node:
            fig = nodes.figure()
            fig += results[0]
            fig += nodes.caption(text=node['caption'])
            results[0] = fig

        return results
Example #6
0
    def run(self):
        required_arguments = 0 
        optional_arguments = 2

        align = self.options.pop('align', None)
        capalign = self.options.pop('capalign', None)
        odsatable_node = odsatable()
        odsatable_node['align'] = align
        odsatable_node['capalign'] = capalign
        if align:
            odsatable_node['align'] = align
        if self.content:
            node = nodes.Element()          # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                caption['align']= capalign
                odsatable_node += caption
            elif not (isinstance(first_node, nodes.comment)
                      and len(first_node) == 0):
                error = self.state_machine.reporter.error(
                      'Table caption must be a paragraph or empty comment.',
                      nodes.literal_block(self.block_text, self.block_text),
                      line=self.lineno)
                return [odsatable_node, error]
            if len(node) > 1:
                odsatable_node += nodes.legend('', *node[1:])
        return [odsatable_node]
    def run(self):
        label = self.options.get('label', None)
        width = self.options.get('width', None)
        alt = self.options.get('alt', None)

        node = subfigend('', ids=[label] if label is not None else [])

        if width is not None:
            node['width'] = width
        if alt is not None:
            node['alt'] = alt

        if self.content:
            anon = nodes.Element()
            self.state.nested_parse(self.content, self.content_offset, anon)
            first_node = anon[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                node += caption

        if label is not None:
            targetnode = nodes.target('', '', ids=[label])
            node.append(targetnode)

        return [node]
Example #8
0
    def run(self):
        env = self.state.document.settings.env
        config = env.config
        repodir = env.srcdir + '/' + config["git_repository_root"]

        doc_path = env.srcdir + '/' + env.docname + config["source_suffix"]

        if self.options.get('dir', False) == None:
            doc_path = '/'.join(doc_path.split('/')[:-1])

        repo = Repo(repodir)
        commits = repo.iter_commits(paths=doc_path)
        l = nodes.bullet_list()
        revisions_to_display = self.options.get('revisions', 10)

        for commit in list(commits)[:revisions_to_display]:
            date_str = datetime.fromtimestamp(commit.authored_date)
            if '\n' in commit.message:
                message, detailed_message = commit.message.split('\n', 1)
            else:
                message = commit.message
                detailed_message = None

            item = nodes.list_item()
            item += [
                nodes.strong(text=message),
                nodes.inline(text=" by "),
                nodes.emphasis(text=str(commit.author)),
                nodes.inline(text=" at "),
                nodes.emphasis(text=str(date_str))
            ]
            if detailed_message:
                item.append(nodes.caption(text=detailed_message.strip()))
            l.append(item)
        return [l]
Example #9
0
    def run(self):
        set_classes(self.options)

        text = '\n'.join(self.content)
        figure_node = nodes.figure(text, **self.options)
        figure_node['classes'] += self.style_classes

        self.state.nested_parse(self.content, self.content_offset,
                                figure_node)

        # Insert the title node, if any, right after the code / math / graph.
        # There could be things like the class directive before, so be sure to
        # find the right node.
        if len(self.arguments) == 1:
            title_text = self.arguments[0]
            title_nodes, _ = self.state.inline_text(title_text, self.lineno)
            title_node = nodes.caption('', '', *title_nodes)

            for i, child in enumerate(figure_node):
                if isinstance(child, nodes.raw) or isinstance(child, nodes.literal_block):
                    figure_node.insert(i + 1, title_node)
                    break
            else: assert False # pragma: no cover

        return [figure_node]
Example #10
0
    def run(self):
        figwidth = self.options.pop('figwidth', None)
        figclasses = self.options.pop('figclass', None)
        align = self.options.pop('align', None)
        (media_node,) = Media.run(self)
        if isinstance(media_node, nodes.system_message):
            return [media_node]
        figure_node = nodes.figure('', media_node)
        if figwidth == 'image':
            if PIL and self.state.document.settings.file_insertion_enabled:
                # PIL doesn't like Unicode paths:
                try:
                    i = PIL.open(str(media_node['uri']))
                except (IOError, UnicodeError):
                    pass
                else:
                    self.state.document.settings.record_dependencies.add(
                        media_node['uri'])
                    figure_node['width'] = i.size[0]
        elif figwidth is not None:
            figure_node['width'] = figwidth
        if figclasses:
            figure_node['classes'] += figclasses
        if align:
            figure_node['align'] = align
        if self.content:
            node = nodes.Element()          # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                    *first_node.children)
                figure_node += caption
            elif not (isinstance(first_node, nodes.comment)
                      and len(first_node) == 0):
                error = self.state_machine.reporter.error(
                    'Figure caption must be a paragraph or empty comment.',
                    nodes.literal_block(self.block_text, self.block_text),
                    line=self.lineno)
                return [figure_node, error]
            if len(node) > 1:
                figure_node += nodes.legend('', *node[1:])
        node = figure_node

        node['label'] = self.options.get('label', None)
        if not node['label']:
            node['label'] = self.options.get('uri')
        node['number'] = None
        ret = [node]
        if node['label']:
            key = node['label']
            tnode = nodes.target('', '', ids=['figure-' + node['label']])
            self.state.document.note_explicit_target(tnode)
            ret.insert(0, tnode)
        return ret
Example #11
0
    def run(self):
        figure = nodes.figure()

        # Figure out what the show for this demo
        
        py_path = Path(self.arguments[0])
        zip_path = py_path.parent / (py_path.stem + '_assets.zip')
        png_path = py_path.parent / (py_path.stem + '.png')

        # Error out if the given python script doesn't exist.
        if py_path.suffix != '.py':
            raise self.error(f"'{py_path}' must be a python script.")

        if not py_path.exists():
            raise self.error(f"'{py_path}' doesn't exist.")
        
        if self.content:

            # Make sure the content is present in the given file.  Complain if 
            # there are differences.

            from textwrap import dedent

            with open(py_path) as py_file:
                py_code = [l.strip() for l in py_file.readlines()]

                for py_line in self.content:
                    if py_line.strip() not in py_code:
                        raise self.error(f"""\
Error in \"demo\" directive: The following line isn't present in '{py_path}':
{py_line}""")

            # Add a node for the code snippet

            from sphinx.directives.code import CodeBlock
            figure += self.make_snippet(self.content, png_path.exists())

        # Add a node for the screenshot

        if png_path.exists():
            figure += self.make_screenshot(png_path)

        # Add a node for the download links.
        
        caption = nodes.caption()
        caption += self.make_download_link(py_path)

        if zip_path.exists():
            caption += linebreak()
            caption += self.make_download_link(zip_path)

        figure += caption
        
        return [figure]
Example #12
0
File: images.py Project: xcore/xdoc
    def run(self):
        figwidth = self.options.pop('figwidth', None)
        position = self.options.pop('position', None)
        figclasses = self.options.pop('figclass', None)
        align = self.options.pop('align', None)
        (image_node,) = Image.run(self)
        if isinstance(image_node, nodes.system_message):
            return [image_node]
        figure_node = nodes.figure('', image_node)
        if figwidth == 'image':
            if PIL and self.state.document.settings.file_insertion_enabled:
                # PIL doesn't like Unicode paths:
                try:
                    i = PIL.open(str(image_node['uri']))
                except (IOError, UnicodeError):
                    pass
                else:
                    self.state.document.settings.record_dependencies.add(
                        image_node['uri'])
                    figure_node['width'] = i.size[0]
        elif figwidth is not None:
            figure_node['width'] = figwidth            
        if figclasses:
            figure_node['classes'] += figclasses
        if align:
            figure_node['align'] = align
        if position:
            figure_node['position'] = position
        if self.content:
            node = nodes.Element()          # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]

            cap = first_node.astext().strip()
            if re.match('[Tt]he.*',cap):
                print >>sys.stderr, "WARNING: Style: Caption '%s' begins with 'The'" % cap

            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                figure_node += caption
            elif not (isinstance(first_node, nodes.comment)
                      and len(first_node) == 0):
                error = self.state_machine.reporter.error(
                      'Figure caption must be a paragraph or empty comment.',
                      nodes.literal_block(self.block_text, self.block_text),
                      line=self.lineno)
                return [figure_node, error]
            if len(node) > 1:
                figure_node += nodes.legend('', *node[1:])
        else:
            self.state.document.reporter.error('Figure without caption\n',
                                               line = self.lineno)
        return [figure_node]
Example #13
0
def container_wrapper(directive, literal_node, caption):
    container_node = nodes.container("", literal_block=True, classes=["literal-block-wrapper"])
    parsed = nodes.Element()
    directive.state.nested_parse(ViewList([caption], source=""), directive.content_offset, parsed)
    if isinstance(parsed[0], nodes.system_message):
        raise ValueError(parsed[0])
    caption_node = nodes.caption(parsed[0].rawsource, "", *parsed[0].children)
    caption_node.source = parsed[0].source
    caption_node.line = parsed[0].line
    container_node += caption_node
    container_node += literal_node
    return container_node
Example #14
0
def container_wrapper(directive, literal_node, caption):
    container_node = nodes.container('', literal_block=True)
    parsed = nodes.Element()
    directive.state.nested_parse(ViewList([caption], source=''),
                                 directive.content_offset, parsed)
    caption_node = nodes.caption(parsed[0].rawsource, '',
                                 *parsed[0].children)
    caption_node.source = parsed[0].source
    caption_node.line = parsed[0].line
    container_node += caption_node
    container_node += literal_node
    return container_node
Example #15
0
def figure_wrapper(directive, node, caption):
    # type: (Directive, graphviz, str) -> nodes.figure
    figure_node = nodes.figure('', node)
    if 'align' in node:
        figure_node['align'] = node.attributes.pop('align')

    inodes, messages = directive.state.inline_text(caption, directive.lineno)
    caption_node = nodes.caption(caption, '', *inodes)
    caption_node.extend(messages)
    set_source_info(directive, caption_node)
    figure_node += caption_node
    return figure_node
Example #16
0
def figure_wrapper(directive, node, caption):
    figure_node = nodes.figure('', node)

    parsed = nodes.Element()
    directive.state.nested_parse(ViewList([caption], source=''),
                                 directive.content_offset, parsed)
    caption_node = nodes.caption(parsed[0].rawsource, '',
                                 *parsed[0].children)
    caption_node.source = parsed[0].source
    caption_node.line = parsed[0].line
    figure_node += caption_node
    return figure_node
Example #17
0
    def run(self):
        figwidth = self.options.pop('figwidth', None)
        figclasses = self.options.pop('figclass', None)
        if self.options.get('caption'):
            align = self.options.pop('align', None)
        else:
            align = None

        results = super(BlockdiagDirective, self).run()

        node = results[0]
        if not isinstance(node, self.node_class):
            return results

        try:
            diagram = self.node2diagram(node)
        except Exception as e:
            raise self.warning(str(e))

        if 'desctable' in node['options']:
            results += self.description_tables(diagram)

        results[0] = self.node2image(node, diagram)
        self.add_name(results[0])

        if node.get('caption'):
            elem = nodes.Element()
            self.state.nested_parse(ViewList([node['caption']], source=''),
                                    self.content_offset, elem)
            caption_node = nodes.caption(elem[0].rawsource, '',
                                         *elem[0].children)
            caption_node.source = elem[0].source
            caption_node.line = elem[0].line

            fig = nodes.figure()
            fig += results[0]
            fig += caption_node

            if figwidth == 'image':
                width = self.get_actual_width(node, diagram)
                fig['width'] = str(width) + 'px'
            elif figwidth is not None:
                fig['width'] = figwidth
            if figclasses:
                fig['classes'] += figclasses
            if align:
                fig['align'] = align

            results[0] = fig

        return results
Example #18
0
 def run(self):
     figwidth = self.options.pop('figwidth', None)
     figclasses = self.options.pop('figclass', None)
     align = self.options.pop('align', None)
     (image_node,) = Image.run(self)
     if isinstance(image_node, nodes.system_message):
         return [image_node]
     figure_node = nodes.figure('', image_node)
     if figwidth == 'image':
         if PIL and self.state.document.settings.file_insertion_enabled:
             imagepath = urllib.url2pathname(image_node['uri'])
             try:
                 if isinstance(imagepath, str):
                     imagepath_str = imagepath
                 else:
                     imagepath_str = imagepath.encode(sys.getfilesystemencoding())
                 img = PIL.Image.open(imagepath_str)
             except (IOError, UnicodeEncodeError):
                 pass # TODO: warn?
             else:
                 self.state.document.settings.record_dependencies.add(
                     imagepath.replace('\\', '/'))
                 figure_node['width'] = '%dpx' % img.size[0]
                 del img
     elif figwidth is not None:
         figure_node['width'] = figwidth
     if figclasses:
         figure_node['classes'] += figclasses
     if align:
         figure_node['align'] = align
     if self.content:
         node = nodes.Element()          # anonymous container for parsing
         self.state.nested_parse(self.content, self.content_offset, node)
         first_node = node[0]
         if isinstance(first_node, nodes.paragraph):
             caption = nodes.caption(first_node.rawsource, '',
                                     *first_node.children)
             caption.source = first_node.source
             caption.line = first_node.line
             figure_node += caption
         elif not (isinstance(first_node, nodes.comment)
                   and len(first_node) == 0):
             error = self.state_machine.reporter.error(
                   'Figure caption must be a paragraph or empty comment.',
                   nodes.literal_block(self.block_text, self.block_text),
                   line=self.lineno)
             return [figure_node, error]
         if len(node) > 1:
             figure_node += nodes.legend('', *node[1:])
     return [figure_node]
Example #19
0
 def run(self):
     figwidth = self.options.get('figwidth')
     if figwidth:
         del self.options['figwidth']
     figclasses = self.options.get('figclass')
     if figclasses:
         del self.options['figclass']
     align = self.options.get('align')
     if align:
         del self.options['align']
     (image_node,) = Image.run(self)
     if isinstance(image_node, nodes.system_message):
         return [image_node]
     figure_node = nodes.figure('', image_node)
     if figwidth == 'image':
         if PIL and self.state.document.settings.file_insertion_enabled:
             # PIL doesn't like Unicode paths:
             try:
                 i = PIL.open(str(image_node['uri']))
             except (IOError, UnicodeError):
                 pass
             else:
                 self.state.document.settings.record_dependencies.add(
                     image_node['uri'])
                 figure_node['width'] = i.size[0]
     elif figwidth is not None:
         figure_node['width'] = figwidth
     if figclasses:
         figure_node['classes'] += figclasses
     if align:
         figure_node['align'] = align
     if self.content:
         node = nodes.Element()          # anonymous container for parsing
         self.state.nested_parse(self.content, self.content_offset, node)
         first_node = node[0]
         if isinstance(first_node, nodes.paragraph):
             caption = nodes.caption(first_node.rawsource, '',
                                     *first_node.children)
             figure_node += caption
         elif not (isinstance(first_node, nodes.comment)
                   and len(first_node) == 0):
             error = self.state_machine.reporter.error(
                   'Figure caption must be a paragraph or empty comment.',
                   nodes.literal_block(self.block_text, self.block_text),
                   line=self.lineno)
             return [figure_node, error]
         if len(node) > 1:
             figure_node += nodes.legend('', *node[1:])
     return [figure_node]
Example #20
0
    def run(self):
        node = plantuml(self.block_text, **self.options)
        node['uml'] = '\n'.join(self.content)

        # if a caption is defined, insert a 'figure' with this node and the caption
        if 'caption' in self.options:
            import docutils.statemachine
            cnode = nodes.Element()          # anonymous container for parsing
            sl = docutils.statemachine.StringList([self.options['caption']],source='')
            self.state.nested_parse(sl,self.content_offset, cnode)
            caption = nodes.caption(self.options['caption'], '', *cnode)
            fig = nodes.figure('',node)
            fig += caption
            node = fig
        return [node]
Example #21
0
def figure_wrapper(directive, node, caption):
    # type: (Directive, nodes.Node, unicode) -> nodes.figure
    figure_node = nodes.figure('', node)
    if 'align' in node:
        figure_node['align'] = node.attributes.pop('align')

    parsed = nodes.Element()
    directive.state.nested_parse(ViewList([caption], source=''),
                                 directive.content_offset, parsed)
    caption_node = nodes.caption(parsed[0].rawsource, '',
                                 *parsed[0].children)
    caption_node.source = parsed[0].source
    caption_node.line = parsed[0].line
    figure_node += caption_node
    return figure_node
Example #22
0
def sourcecode(
    name, arguments, options, content, lineno,
    content_offset, block_text, state, state_machine,
    ):
    filename = options.get('filename', None)
    if filename is None:
        code = u'\n'.join(content)
    else:
        source = state_machine.input_lines.source(
            lineno - state_machine.input_offset - 1)
        source_dir = os.path.dirname(os.path.abspath(source))
        filename = os.path.normpath(os.path.join(source_dir, filename))
        filename = utils.relative_path(None, filename)
        state.document.settings.record_dependencies.add(filename)
        op = state.document.settings.roast_operation
        inp = op.open_input(filename)
        code = inp.read().decode('utf-8')
        inp.close()

    if arguments:
        (syntax,) = arguments
    else:
        syntax = 'text'
    lexer = lexers.get_lexer_by_name(syntax)
    formatter = formatters.HtmlFormatter()
    html = highlight(
        code=code,
        lexer=lexer,
        formatter=formatter,
        )

    title_text = options.get('title')
    if title_text:
        text_nodes, messages = state.inline_text(title_text, lineno)
        title = nodes.caption('', '# ', *text_nodes)
    else:
        messages = []
        title = None

    fig = nodes.figure('')
    fig['classes'].append('py-listing')
    if title is not None:
        fig += title

    fig += nodes.raw('', html, format='html')

    return [fig] + messages
Example #23
0
    def run(self):
        """ Restructured text extension for including inline JSAV content on module pages """
        self.options["exer_name"] = self.arguments[0]
        self.options["type"] = self.arguments[1]
        self.options["odsa_path"] = os.path.relpath(conf.odsa_path, conf.ebook_path)

        if "required" not in self.options:
            self.options["required"] = False

        if "points" not in self.options:
            self.options["points"] = 0

        if "threshold" not in self.options:
            self.options["threshold"] = 1.0

        if "long_name" not in self.options:
            self.options["long_name"] = self.options["exer_name"]

        if "align" not in self.options:
            self.options["align"] = "center"

        if "output" in self.options and self.options["output"] == "show":
            self.options["output_code"] = '<p class="jsavoutput jsavline"></p>'
        else:
            self.options["output_code"] = ""

        if self.options["type"] == "dgm":
            avdgm_node = av_dgm()
            anchor_node = av_anchor()

            avdgm_node["exer_name"] = self.options["exer_name"]
            anchor_node["ids"].append(self.options["exer_name"])
            avdgm_node += anchor_node
            if self.content:
                node = nodes.Element()  # anonymous container for parsing
                self.state.nested_parse(self.content, self.content_offset, node)
                first_node = node[0]
                if isinstance(first_node, nodes.paragraph):
                    caption = nodes.caption(first_node.rawsource, "", *first_node.children)
                    caption["align"] = self.options["align"]
                    avdgm_node += caption

            return [avdgm_node]
        else:
            res = SLIDESHOW % self.options
            return [nodes.raw("", res, format="html")]
Example #24
0
File: code.py Project: LFYG/sphinx
def container_wrapper(directive, literal_node, caption):
    # type: (Directive, nodes.Node, unicode) -> nodes.container
    container_node = nodes.container('', literal_block=True,
                                     classes=['literal-block-wrapper'])
    parsed = nodes.Element()
    directive.state.nested_parse(ViewList([caption], source=''),
                                 directive.content_offset, parsed)
    if isinstance(parsed[0], nodes.system_message):
        msg = __('Invalid caption: %s' % parsed[0].astext())
        raise ValueError(msg)
    caption_node = nodes.caption(parsed[0].rawsource, '',
                                 *parsed[0].children)
    caption_node.source = literal_node.source
    caption_node.line = literal_node.line
    container_node += caption_node
    container_node += literal_node
    return container_node
Example #25
0
    def run(self):
        name, = self.content
        source_name, scenario = name.rsplit("-", 1)
        source = source_name + ".sam"

        image_reference = directives.uri("_images/" + name + ".png")
        self.options["uri"] = image_reference

        source_link = nodes.reference(self.content, source, refuri="examples/" + source)
        # text = nodes.text('', 'Output from ' + source)
        image_node = nodes.image("_images/" + name + ".png", **self.options)
        figure_node = nodes.figure("", image_node)
        msg = "Output from "
        if scenario != "baseline":
            msg += "'" + scenario + "' in "
        caption = nodes.caption("hi", msg, source_link)
        figure_node += caption
        return [figure_node]
Example #26
0
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine):
    figwidth = options.setdefault("figwidth")
    figclasses = options.setdefault("figclass")
    align = options.setdefault("align")
    del options["figwidth"]
    del options["figclass"]
    del options["align"]
    (image_node,) = image(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine)
    if isinstance(image_node, nodes.system_message):
        return [image_node]
    figure_node = nodes.figure("", image_node)
    if figwidth == "image":
        if Image and state.document.settings.file_insertion_enabled:
            # PIL doesn't like Unicode paths:
            try:
                i = Image.open(str(image_node["uri"]))
            except (IOError, UnicodeError):
                pass
            else:
                state.document.settings.record_dependencies.add(image_node["uri"])
                figure_node["width"] = i.size[0]
    elif figwidth is not None:
        figure_node["width"] = figwidth
    if figclasses:
        figure_node["classes"] += figclasses
    if align:
        figure_node["align"] = align
    if content:
        node = nodes.Element()  # anonymous container for parsing
        state.nested_parse(content, content_offset, node)
        first_node = node[0]
        if isinstance(first_node, nodes.paragraph):
            caption = nodes.caption(first_node.rawsource, "", *first_node.children)
            figure_node += caption
        elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0):
            error = state_machine.reporter.error(
                "Figure caption must be a paragraph or empty comment.",
                nodes.literal_block(block_text, block_text),
                line=lineno,
            )
            return [figure_node, error]
        if len(node) > 1:
            figure_node += nodes.legend("", *node[1:])
    return [figure_node]
Example #27
0
def process_toctree_list(navtree, bullet_list, caption, app,
                         collapse, maxdepth, shift_toc, root_links, level=1):

    for list_item in bullet_list.children:

        if len(list_item) == 1: # Just a link, no sublist
            continue
        if len(list_item) != 2:
            raise NavtreeError("Expected 'list_item' with exactly 2 child nodes, got '%s' with %d: %s"
                               % (list_item.__class__.__name__, len(list_item), list_item.children))

        title_node = list_item[0][0]  # list_item > paragraph > reference
        list_node = list_item[1]      # list_item > bullet_list
        if not root_links:
            # Use the `Text` node instead of the enclosing `reference` object.
            title_node = title_node[0]
        if caption:
            prune_depth = maxdepth.get(title_node.astext(),
                                       maxdepth.get(caption.astext(),
                                                    maxdepth['default']))
        else:
            prune_depth = maxdepth.get(title_node.astext(),
                                       maxdepth['default'])

        app.env._toctree_prune(node     = list_item,
                               depth    = level if shift_toc else level + 1,
                               maxdepth = prune_depth,
                               collapse = collapse)

        if shift_toc and level == 1:
            caption = nodes.caption(title_node.astext(), '', title_node)
            if root_links:
                caption['classes'].append('link')
            navtree += caption
            navtree += list_node

        if level < 2:
            process_toctree_list(navtree, list_node, None, app,
                                 collapse, maxdepth, shift_toc, root_links, level=level+1)

    if not shift_toc and level == 1:
        if caption:
            navtree += caption
        navtree += bullet_list
Example #28
0
    def run(self):
        figwidth = self.options.pop('figwidth', None)
        figclasses = self.options.pop('figclass', None)
        if self.options.get('caption'):
            align = self.options.pop('align', None)
        else:
            align = None

        results = super(BlockdiagDirective, self).run()

        node = results[0]
        if not isinstance(node, self.node_class):
            return results

        try:
            diagram = self.node2diagram(node)
        except Exception as e:
            raise self.warning(str(e))

        if 'desctable' in node['options']:
            results += self.description_tables(diagram)

        results[0] = self.node2image(node, diagram)
        self.add_name(results[0])

        if node.get('caption'):
            fig = nodes.figure()
            fig += results[0]
            fig += nodes.caption(text=node['caption'])

            if figwidth == 'image':
                width = self.get_actual_width(node, diagram)
                fig['width'] = str(width) + 'px'
            elif figwidth is not None:
                fig['width'] = figwidth
            if figclasses:
                fig['classes'] += figclasses
            if align:
                fig['align'] = align

            results[0] = fig

        return results
Example #29
0
def test_process_doc_handle_figure_caption():
    env = mock.Mock(domaindata={})
    figure_node = nodes.figure(
        '',
        nodes.caption('caption text', 'caption text'),
    )
    document = mock.Mock(
        nametypes={'testname': True},
        nameids={'testname': 'testid'},
        ids={'testid': figure_node},
    )

    domain = StandardDomain(env)
    if 'testname' in domain.data['labels']:
        del domain.data['labels']['testname']
    domain.process_doc(env, 'testdoc', document)
    assert 'testname' in domain.data['labels']
    assert domain.data['labels']['testname'] == (
        'testdoc', 'testid', 'caption text')
Example #30
0
    def run(self):
        fig = general_figure()
        self.state.nested_parse(self.content, self.content_offset, fig)
        if len(fig) < 1 or not isinstance(fig[0],nodes.paragraph):
            print >>sys.stderr, "ERROR: first paragraph of generalfigure should be present for the caption"
            return []

        first_para = fig[0]

        cap = nodes.caption()
        for c in first_para.children:
            cap.append(c.deepcopy())

        txt = cap.astext().strip()
        if re.match('[Tt]he.*',txt):
            print >>sys.stderr, "WARNING: Style: Caption '%s' begins with 'The'" % txt

        fig.remove(first_para)
        fig.append(cap)
        return [fig]
Example #31
0
def test_process_doc_handle_figure_caption():
    env = mock.Mock(domaindata={})
    figure_node = nodes.figure(
        '',
        nodes.caption('caption text', 'caption text'),
    )
    document = mock.Mock(
        nametypes={'testname': True},
        nameids={'testname': 'testid'},
        ids={'testid': figure_node},
        citation_refs={},
    )
    document.traverse.return_value = []

    domain = StandardDomain(env)
    if 'testname' in domain.data['labels']:
        del domain.data['labels']['testname']
    domain.process_doc(env, 'testdoc', document)
    assert 'testname' in domain.data['labels']
    assert domain.data['labels']['testname'] == (
        'testdoc', 'testid', 'caption text')
Example #32
0
def test_process_doc_handle_image_parent_figure_caption():
    env = mock.Mock(domaindata={})
    img_node = nodes.image('', alt='image alt')
    figure_node = nodes.figure(
        '',
        nodes.caption('caption text', 'caption text'),
        img_node,
    )
    document = mock.Mock(
        nametypes={'testname': True},
        nameids={'testname': 'testid'},
        ids={'testid': img_node},
    )

    domain = StandardDomain(env)
    if 'testname' in domain.data['labels']:
        del domain.data['labels']['testname']
    domain.process_doc(env, 'testdoc', document)
    assert 'testname' in domain.data['labels']
    assert domain.data['labels']['testname'] == ('testdoc', 'testid',
                                                 'caption text')
def container_wrapper(directive, literal_node, caption):
    # type: (SphinxDirective, nodes.Node, str) -> nodes.container
    container_node = nodes.container("",
                                     literal_block=True,
                                     classes=["literal-block-wrapper"])
    parsed = nodes.Element()
    directive.state.nested_parse(StringList([caption], source=""),
                                 directive.content_offset, parsed)
    if isinstance(parsed[0], nodes.system_message):
        msg = "Invalid caption: %s" % parsed[0].astext()
        raise ValueError(msg)
    elif isinstance(parsed[0], nodes.Element):
        caption_node = nodes.caption(parsed[0].rawsource, "",
                                     *parsed[0].children)
        caption_node.source = literal_node.source
        caption_node.line = literal_node.line
        container_node += caption_node
        container_node += literal_node
        return container_node
    else:
        raise RuntimeError  # never reached
Example #34
0
def container_wrapper(directive: SphinxDirective, literal_node: Node,
                      caption: str) -> nodes.container:  # NOQA
    container_node = nodes.container('',
                                     literal_block=True,
                                     classes=['literal-block-wrapper'])
    parsed = nodes.Element()
    directive.state.nested_parse(StringList([caption], source=''),
                                 directive.content_offset, parsed)
    if isinstance(parsed[0], nodes.system_message):
        msg = __('Invalid caption: %s' % parsed[0].astext())
        raise ValueError(msg)
    elif isinstance(parsed[0], nodes.Element):
        caption_node = nodes.caption(parsed[0].rawsource, '',
                                     *parsed[0].children)
        caption_node.source = literal_node.source
        caption_node.line = literal_node.line
        container_node += caption_node
        container_node += literal_node
        return container_node
    else:
        raise RuntimeError  # never reached
Example #35
0
 def _make_figure_node(self, *children):
     # Build figure node.
     if isinstance(children[0], nodes.system_message):
         return children[:1]
     figure_node = nodes.figure('', *children)
     # Pop options.
     figwidth = self.options.pop('figwidth', None)
     figclasses = self.options.pop('figclass', None)
     align = self.options.pop('align', None)
     # Figure property "figwidth".
     if figwidth:
         figure_node['width'] = figwidth
     # Figure property "figclass".
     if figclasses:
         figure_node['classes'] += figclasses
     # Figure property "align".
     if align:
         figure_node['align'] = align
     # Figure property "caption".  Only valid when texpath is used.
     if self.content:
         node = nodes.Element()  # Anonymous container for parsing.
         self.state.nested_parse(self.content, self.content_offset,
                                 node)
         first_node = node[0]
         if isinstance(first_node, nodes.paragraph):
             caption = nodes.caption(first_node.rawsource, '',
                                     *first_node.children)
             caption.source = first_node.source
             caption.line = first_node.line
             figure_node += caption
         elif not (isinstance(first_node, nodes.comment)
                   and len(first_node) == 0):
             error = self.state_machine.reporter.error(
                 'Figure caption must be a paragraph or empty comment.',
                 nodes.literal_block(self.block_text, self.block_text),
                 line=self.lineno)
             return [figure_node, error]
         if len(node) > 1:
             figure_node += nodes.legend('', *node[1:])
     return [figure_node]
Example #36
0
    def run(self):
        warning = self.state.document.reporter.warning
        env = self.state.document.settings.env
        if self.arguments and self.content:
            return [warning('uml directive cannot have both content and '
                            'a filename argument', line=self.lineno)]
        if self.arguments:
            fn = search_image_for_language(self.arguments[0], env)
            relfn, absfn = env.relfn2path(fn)
            env.note_dependency(relfn)
            try:
                umlcode = _read_utf8(absfn)
            except (IOError, UnicodeDecodeError) as err:
                return [warning('PlantUML file "%s" cannot be read: %s'
                                % (fn, err), line=self.lineno)]
        else:
            relfn = env.doc2path(env.docname, base=None)
            umlcode = '\n'.join(self.content)

        node = plantuml(self.block_text, **self.options)
        node['uml'] = umlcode
        node['incdir'] = os.path.dirname(relfn)
        node['filename'] = os.path.split(relfn)[1]

        # XXX maybe this should be moved to _visit_plantuml functions. it
        # seems wrong to insert "figure" node by "plantuml" directive.
        if 'caption' in self.options or 'align' in self.options:
            node = nodes.figure('', node)
            if 'align' in self.options:
                node['align'] = self.options['align']
        if 'caption' in self.options:
            import docutils.statemachine
            cnode = nodes.Element()  # anonymous container for parsing
            sl = docutils.statemachine.StringList([self.options['caption']],
                                                  source='')
            self.state.nested_parse(sl, self.content_offset, cnode)
            caption = nodes.caption(self.options['caption'], '', *cnode)
            node += caption

        return [node]
    def run(self):
        label = self.options.get('label', None)
        spec = self.options.get('spec', None)
        caption = self.options.get('caption', None)
        alt = self.options.get('alt', None)
        nofig = 'nofig' in self.options

        figtable_node = figtable('', ids=[label] if label is not None else [])
        figtable_node['nofig'] = nofig

        if spec is not None:
            table_spec_node = addnodes.tabular_col_spec()
            table_spec_node['spec'] = spec
            figtable_node.append(table_spec_node)

        node = nodes.Element()
        self.state.nested_parse(self.content, self.content_offset, node)
        tablenode = node[0]
        if alt is not None:
            tablenode['alt'] = alt
        figtable_node.append(tablenode)

        if caption is not None:
            # Original SphinxTr source:
            # caption_node = nodes.caption('', '', nodes.Text(caption))
            # figtable_node.append(caption_node)

            # Modified: Support for parsing content of captions
            caption_node = nodes.Element()
            self.state.nested_parse(docutils.statemachine.StringList([caption]), self.content_offset, caption_node)
            if isinstance(caption_node[0], nodes.paragraph):
                caption = nodes.caption(caption_node[0].rawsource, '', *caption_node[0].children)
                figtable_node += caption

        if label is not None:
            targetnode = nodes.target('', '', ids=[label])
            figtable_node.append(targetnode)

        return [figtable_node]
Example #38
0
    def run(self):
        env = self.state.document.settings.env
        definitions = env.numbered_blocks_definitions

        (figure, ) = Figure.run(self)
        if isinstance(figure, nodes.system_message):
            return [figure]

        id = "%s-%d" % (self.name, env.new_serialno(self.name))
        figure['ids'] = [id]
        figure['classes'].append('numbered-block')
        figure['type'] = self.name
        numbered = definitions[
            self.name]['numbered'] and 'nonumber' not in self.options
        figure['numbered'] = numbered

        # Move name from image to figure and register as target
        image = figure.children[figure.first_child_matching_class(nodes.image)]
        if len(image['names']) > 0:
            name = image['names'][0]
            figure['names'] = [name]
            if name in self.state.document.nameids:
                del (self.state.document.nameids[name])
            self.state.document.note_explicit_target(figure)

        # Prepare caption
        caption_pos = figure.first_child_matching_class(nodes.caption)
        if numbered:
            if not caption_pos:
                figure.append(nodes.caption('', ''))
            else:
                caption = figure.children[caption_pos]
                caption.insert(
                    0,
                    nodes.inline('',
                                 definitions[self.name]['title-separator'],
                                 classes=['separator']))

        return [figure]
def container_wrapper(directive: SphinxDirective, literal_node: Node,
                      caption: str) -> nodes.container:
    """We need the container to have class highlight."""
    container_node = nodes.container("",
                                     literal_block=True,
                                     language=literal_node["language"],
                                     classes=["highlight"])
    parsed = nodes.Element()
    directive.state.nested_parse(StringList([caption], source=""),
                                 directive.content_offset, parsed)
    if isinstance(parsed[0], nodes.system_message):
        msg = __("Invalid caption: %s" % parsed[0].astext())
        raise ValueError(msg)
    elif isinstance(parsed[0], nodes.Element):
        caption_node = nodes.caption(parsed[0].rawsource, "",
                                     *parsed[0].children)
        caption_node.source = literal_node.source
        caption_node.line = literal_node.line
        container_node += caption_node
        container_node += literal_node
        return container_node
    else:
        raise RuntimeError  # never reached
Example #40
0
def generate_collapsible_classlist(app, fromdocname, classes, container, caption, module_index):

    entries = defaultdict(list)
    prefix = ".".join(classes[0][0].split(".")[:module_index]) + "."
    for e in classes:
        module = e[0].split(".")[module_index]
        entries[module].append(e)

    #print("t", fromdocname)
    toc = nodes.bullet_list()
    toc += nodes.caption(caption, '', *[nodes.Text(caption)])
    for module, class_list in entries.items():
        #print("t2", "src." + prefix + module)
        ref = nodes.reference('', '')
        ref['refuri'] = app.builder.get_relative_uri(fromdocname, prefix + module)
        ref.append(nodes.Text(module.capitalize()))
        module_item = nodes.list_item('', addnodes.compact_paragraph('', '', ref), classes=["toctree-l1"])
        if fromdocname.startswith(prefix + module):
            module_item["classes"].append('current')
        toc += module_item

        subtree = nodes.bullet_list()
        module_item += subtree

        for e in class_list:
            ref = nodes.reference('', '')
            ref['refdocname'] = e[3]
            ref['refuri'] = app.builder.get_relative_uri(fromdocname, e[3])
            ref['refuri'] += '#' + e[4]
            ref.append(nodes.Text(e[0].split(".")[-1]))
            class_item = nodes.list_item('', addnodes.compact_paragraph('', '', ref), classes=["toctree-l2"])
            if fromdocname.startswith(e[3]):
                class_item['classes'].append('current')
            subtree += class_item

    container += toc
Example #41
0
 def run(self):
   if (self.options.get('type') == 'table'):
     content_node = table_container('')
   elif (self.options.get('type') == 'figure'):
     content_node = figure_container('')
   elif (self.options.get('type') == 'code'):
     content_node = code_container('')
   else:
     content_node = float_container('')
   self.state.nested_parse(self.content, self.content_offset, content_node)
   set_source_info(self, content_node)
   self.add_name(content_node)
   caption = self.options.get('caption')
   if caption:
     parsed = nodes.Element()
     self.state.nested_parse(ViewList([caption], source=''), self.content_offset, parsed)
     caption_node = nodes.caption(parsed[0].rawsource, '', *parsed[0].children)
     caption_node.source = parsed[0].source
     caption_node.line = parsed[0].line
     if ('caption-top' in self.options):
       content_node.insert(0, caption_node)
     else:
       content_node += caption_node
   return [content_node]
Example #42
0
    def run(self):
        """ Executes python code for an RST document, taking input from content or from a filename
        :return:
        """
        language = self.options.get('language', 'python')
        output_language = self.options.get('output_language', 'none')

        output = []

        shown_code = ''
        executed_code = ''

        hide = False
        skip = False
        for line in self.content:
            line_switch = line.replace(' ', '').lower()
            if line_switch == '#hide':
                hide = not hide
                continue
            if line_switch == '#skip':
                skip = not skip
                continue

            if not hide:
                shown_code += line + '\n'
            if not skip:
                executed_code += line + '\n'

        shown_code = shown_code.strip()
        executed_code = executed_code.strip()

        # Show the example code
        if 'hide_code' not in self.options:
            input_code = nodes.literal_block(shown_code, shown_code)

            input_code['language'] = language
            input_code['linenos'] = 'linenos' in self.options
            if 'header_code' in self.options:
                output.append(nodes.caption(text=self.options['header_code']))
            output.append(input_code)

        # Show the code results
        if 'header_output' in self.options:
            output.append(nodes.caption(text=self.options['header_output']))

        try:
            code_results = execute_code(executed_code,
                                        ignore_stderr='ignore_stderr'
                                        in self.options)
        except CodeException as e:
            # Newline so we don't have the build message mixed up with logs
            print('\n')

            code_lines = executed_code.splitlines()

            # If we don't get the line we print everything
            if e.line is None:
                e.line = len(code_lines)

            for i in range(max(0, e.line - 8), e.line - 1):
                log.error(f'   {code_lines[i]}')
            log.error(f'   {code_lines[e.line - 1]} <--')

            log.error('')
            for line in e.err.splitlines():
                log.error(line)

            raise ExtensionError('Could not execute code!') from None

        if 'ignore_stderr' not in self.options:
            for out in code_results.split('\n'):
                if 'Error in ' in out:
                    log.error(f'Possible Error in codeblock: {out}')

        code_results = nodes.literal_block(code_results, code_results)

        code_results['linenos'] = 'linenos' in self.options
        code_results['language'] = output_language

        if 'hide_output' not in self.options:
            output.append(code_results)
        return output
Example #43
0
def process_needgantt(app, doctree, fromdocname):
    # Replace all needgantt nodes with a list of the collected needs.
    env = app.builder.env

    link_types = env.config.needs_extra_links
    allowed_link_types_options = [
        link.upper() for link in env.config.needs_flow_link_types
    ]

    # NEEDGANTT
    for node in doctree.traverse(Needgantt):
        if not app.config.needs_include_needs:
            # Ok, this is really dirty.
            # If we replace a node, docutils checks, if it will not lose any attributes.
            # But this is here the case, because we are using the attribute "ids" of a node.
            # However, I do not understand, why losing an attribute is such a big deal, so we delete everything
            # before docutils claims about it.
            for att in ('ids', 'names', 'classes', 'dupnames'):
                node[att] = []
            node.replace_self([])
            continue

        id = node.attributes["ids"][0]
        current_needgantt = env.need_all_needgantts[id]
        all_needs_dict = env.needs_all_needs

        content = []
        try:
            if "sphinxcontrib.plantuml" not in app.config.extensions:
                raise ImportError
            from sphinxcontrib.plantuml import plantuml
        except ImportError:
            no_plantuml(node)
            continue

        plantuml_block_text = ".. plantuml::\n" \
                              "\n" \
                              "   @startuml" \
                              "   @enduml"
        puml_node = plantuml(plantuml_block_text, **dict())
        puml_node["uml"] = "@startuml\n"
        puml_connections = ""

        # Adding config
        config = current_needgantt['config']
        puml_node["uml"] += add_config(config)

        all_needs = list(all_needs_dict.values())
        found_needs = procces_filters(all_needs, current_needgantt)

        # Scale/timeline handling
        if current_needgantt['timeline'] is not None and current_needgantt[
                'timeline'] != '':
            puml_node["uml"] += 'printscale {}\n'.format(
                current_needgantt["timeline"])

        # Project start date handling
        start_date_string = current_needgantt['start_date']
        start_date_plantuml = None
        if start_date_string is not None and start_date_string != '':
            try:
                start_date = datetime.strptime(start_date_string, '%Y-%m-%d')
                # start_date = datetime.fromisoformat(start_date_string)  # > py3.7 only
            except Exception:
                raise NeedGanttException(
                    'start_date "{}"for needgantt is invalid. '
                    'File: {}:current_needgantt["lineno"]'.format(
                        start_date_string, current_needgantt["docname"]))

            month = MONTH_NAMES[int(start_date.strftime("%-m"))]
            start_date_plantuml = start_date.strftime(
                "%dth of {} %Y".format(month))
        if start_date_plantuml is not None:
            puml_node["uml"] += 'Project starts the {}\n'.format(
                start_date_plantuml)

        # Element handling
        puml_node["uml"] += '\n\' Elements definition \n\n'
        el_link_string = ''
        el_completion_string = ''
        el_color_string = ''
        for need in found_needs:
            complete = None

            if current_needgantt[
                    'milestone_filter'] is None or current_needgantt[
                        'milestone_filter'] == '':
                is_milestone = False
            else:
                is_milestone = filter_single_need(
                    need, current_needgantt['milestone_filter'])
            if current_needgantt['milestone_filter'] is None or current_needgantt['milestone_filter'] == '' or \
                    not is_milestone:
                # Normal gantt element handling
                duration_option = current_needgantt['duration_option']
                duration = need[duration_option]
                complete_option = current_needgantt['completion_option']
                complete = need[complete_option]
                if duration is None or duration == '' or not duration.isdigit(
                ):
                    logger.warning(
                        'Duration not set or invalid for needgantt chart. '
                        'Need: {}. Duration: {}'.format(need["id"], duration))
                    duration = 1
                gantt_element = '[{}] as [{}] lasts {} days\n'.format(
                    need["title"], need["id"], duration)
            else:
                gantt_element = '[{}] as [{}] lasts 0 days\n'.format(
                    need["title"], need["id"])

            el_link_string += '[{}] links to [[{}]]\n'.format(
                need["title"], calculate_link(app, need))

            if complete is not None and complete != '':
                complete = complete.replace('%', '')
                el_completion_string += '[{}] is {}% completed\n'.format(
                    need["title"], complete)

            el_color_string += '[{}] is colored in {}\n'.format(
                need["title"], need["type_color"])

            puml_node["uml"] += gantt_element

        puml_node["uml"] += '\n\' Element links definition \n\n'
        puml_node[
            "uml"] += '\n\' Deactivated, as currently supported by plantuml beta only'
        # ToDo: Activate if linking is working with default plantuml
        # puml_node["uml"] += el_link_string + '\n'

        puml_node["uml"] += '\n\' Element completion definition \n\n'
        puml_node["uml"] += el_completion_string + '\n'

        puml_node["uml"] += '\n\' Element color definition \n\n'
        if current_needgantt['no_color']:
            puml_node["uml"] += '\' Color support deactivated via flag'
        else:
            puml_node["uml"] += el_color_string + '\n'

        # Constrain handling
        puml_node["uml"] += '\n\' Constraints definition \n\n'
        puml_node["uml"] += '\n\' Constraints definition \n\n'
        for need in found_needs:
            if current_needgantt[
                    'milestone_filter'] is None or current_needgantt[
                        'milestone_filter'] == '':
                is_milestone = False
            else:
                is_milestone = filter_single_need(
                    need, current_needgantt['milestone_filter'])
            constrain_types = [
                'starts_with_links', 'starts_after_links', 'ends_with_links'
            ]
            for con_type in constrain_types:
                if is_milestone:
                    keyword = 'happens'
                elif con_type in ['starts_with_links', 'starts_after_links']:
                    keyword = 'starts'
                else:
                    keyword = 'ends'

                if con_type in ['starts_after_links', 'ends_with_links']:
                    start_end_sync = 'end'
                else:
                    start_end_sync = 'start'

                for link_type in current_needgantt[con_type]:
                    start_with_links = need[link_type]
                    for start_with_link in start_with_links:
                        start_need = all_needs_dict[start_with_link]
                        gantt_constraint = '[{}] {} at [{}]\'s ' \
                                           '{}\n'.format(need["id"], keyword, start_need["id"], start_end_sync)
                        puml_node["uml"] += gantt_constraint

        # Create a legend
        if current_needgantt["show_legend"]:
            puml_node["uml"] += '\n\n\' Legend definition \n\n'

            puml_node["uml"] += "legend\n"
            puml_node["uml"] += "|= Color |= Type |\n"
            for need in app.config.needs_types:
                puml_node[
                    "uml"] += "|<back:{color}> {color} </back>| {name} |\n".format(
                        color=need["color"], name=need["title"])
            puml_node["uml"] += "endlegend\n"

        puml_node["uml"] += "\n@enduml"
        puml_node["incdir"] = os.path.dirname(current_needgantt["docname"])
        puml_node["filename"] = os.path.split(
            current_needgantt["docname"])[1]  # Needed for plantuml >= 0.9

        scale = int(current_needgantt['scale'])
        # if scale != 100:
        puml_node['scale'] = scale

        puml_node = nodes.figure('', puml_node)

        if current_needgantt['align'] is not None and len(
                current_needgantt['align']) != '':
            puml_node['align'] = current_needgantt['align']
        else:
            puml_node['align'] = 'center'

        if current_needgantt['caption'] is not None and len(
                current_needgantt['caption']) != '':
            # Make the caption to a link to the original file.
            try:
                if "SVG" in app.config.plantuml_output_format.upper():
                    file_ext = 'svg'
                else:
                    file_ext = 'png'
            except Exception:
                file_ext = 'png'

            gen_flow_link = generate_name(app, puml_node.children[0], file_ext)
            current_file_parts = fromdocname.split('/')
            subfolder_amount = len(current_file_parts) - 1
            img_locaton = '../' * subfolder_amount + '_images/' + gen_flow_link[
                0].split('/')[-1]
            flow_ref = nodes.reference('t',
                                       current_needgantt['caption'],
                                       refuri=img_locaton)
            puml_node += nodes.caption('', '', flow_ref)

        content.append(puml_node)

        if len(content) == 0:
            nothing_found = "No needs passed the filters"
            para = nodes.paragraph()
            nothing_found_node = nodes.Text(nothing_found, nothing_found)
            para += nothing_found_node
            content.append(para)
        if current_needgantt["show_filters"]:
            content.append(get_filter_para(current_needgantt))

        if current_needgantt['debug']:
            content += get_debug_containter(puml_node)

        puml_node['class'] = ['needgantt']
        node.replace_self(content)
    def run(self):
        config = self.state.document.settings.env.config

        # Read enabled builders; Defaults to None
        if self.arguments:
            chosen_builders = choose_builders(self.arguments)
        else:
            chosen_builders = []

        # Enable 'http' language for http part
        self.arguments = ['http']

        # Optionally, read directive content from 'request' option
        cwd = os.path.dirname(self.state.document.current_source)
        if 'request' in self.options:
            request = utils.resolve_path(self.options['request'], cwd)
            with open(request) as fp:
                self.content = StringList(
                    list(map(str.rstrip, fp.readlines())), request)

        # Wrap and render main directive as 'http-example-http'
        klass = 'http-example-http'
        container = nodes.container('', classes=[klass])
        container.append(nodes.caption('', 'http'))
        container.extend(super(HTTPExample, self).run())

        # Init result node list
        result = [container]

        # Append builder responses
        for name in chosen_builders:
            raw = ('\r\n'.join(self.content)).encode('utf-8')
            request = parsers.parse_request(raw, config.httpexample_scheme)
            builder_, language = AVAILABLE_BUILDERS[name]
            command = builder_(request)

            content = StringList([command], self.content.source(0))
            options = self.options.copy()
            options.pop('name', None)
            options.pop('caption', None)

            block = CodeBlock('code-block', [language], options, content,
                              self.lineno, self.content_offset,
                              self.block_text, self.state, self.state_machine)

            # Wrap and render main directive as 'http-example-{name}'
            klass = 'http-example-{}'.format(name)
            container = nodes.container('', classes=[klass])
            container.append(nodes.caption('', name))
            container.extend(block.run())

            # Append to result nodes
            result.append(container)

        # Append optional response
        if 'response' in self.options:
            response = utils.resolve_path(self.options['response'], cwd)
            with open(response) as fp:
                content = StringList(list(map(str.rstrip, fp.readlines())),
                                     response)

            options = self.options.copy()
            options.pop('name', None)
            options.pop('caption', None)

            block = CodeBlock('code-block', ['http'], options, content,
                              self.lineno, self.content_offset,
                              self.block_text, self.state, self.state_machine)

            # Wrap and render main directive as 'http-example-response'
            klass = 'http-example-response'
            container = nodes.container('', classes=[klass])
            container.append(nodes.caption('', 'response'))
            container.extend(block.run())

            # Append to result nodes
            result.append(container)

        # Final wrap
        container_node = nodes.container('', classes=['http-example'])
        container_node.extend(result)

        return [container_node]
def process_needsequence(app, doctree, fromdocname):
    # Replace all needsequence nodes with a list of the collected needs.
    env = app.builder.env

    link_types = env.config.needs_extra_links
    # allowed_link_types_options = [link.upper() for link in env.config.needs_flow_link_types]

    # NEEDSEQUENCE
    for node in doctree.traverse(Needsequence):
        if not app.config.needs_include_needs:
            # Ok, this is really dirty.
            # If we replace a node, docutils checks, if it will not lose any attributes.
            # But this is here the case, because we are using the attribute "ids" of a node.
            # However, I do not understand, why losing an attribute is such a big deal, so we delete everything
            # before docutils claims about it.
            for att in ("ids", "names", "classes", "dupnames"):
                node[att] = []
            node.replace_self([])
            continue

        id = node.attributes["ids"][0]
        current_needsequence = env.need_all_needsequences[id]
        all_needs_dict = env.needs_all_needs

        option_link_types = [
            link.upper() for link in current_needsequence["link_types"]
        ]
        for lt in option_link_types:
            if lt not in [link["option"].upper() for link in link_types]:
                logger.warning(
                    "Unknown link type {link_type} in needsequence {flow}. Allowed values:"
                    " {link_types}".format(
                        link_type=lt,
                        flow=current_needsequence["target_node"],
                        link_types=",".join(link_types)))

        content = []
        try:
            if "sphinxcontrib.plantuml" not in app.config.extensions:
                raise ImportError
            from sphinxcontrib.plantuml import plantuml
        except ImportError:
            no_plantuml(node)
            continue

        plantuml_block_text = ".. plantuml::\n" "\n" "   @startuml" "   @enduml"
        puml_node = plantuml(plantuml_block_text)
        puml_node["uml"] = "@startuml\n"

        # Adding config
        config = current_needsequence["config"]
        puml_node["uml"] += add_config(config)

        # all_needs = list(all_needs_dict.values())

        start_needs_id = [
            x.strip() for x in re.split(";|,", current_needsequence["start"])
        ]
        if len(start_needs_id) == 0:
            raise NeedsequenceDirective("No start-id set for needsequence"
                                        " File {}"
                                        ":{}".format(
                                            {current_needsequence["docname"]},
                                            current_needsequence["lineno"]))

        puml_node["uml"] += "\n' Nodes definition \n\n"

        # Add  start participants
        p_string = ""
        c_string = ""
        for need_id in start_needs_id:
            try:
                need = all_needs_dict[need_id.strip()]
            except KeyError:
                raise NeedSequenceException(
                    "Given {} in needsequence unknown."
                    " File {}"
                    ":{}".format(need_id, current_needsequence["docname"],
                                 current_needsequence["lineno"]))

            # Add children of participants
            _msg_receiver_needs, p_string_new, c_string_new = get_message_needs(
                app,
                need,
                current_needsequence["link_types"],
                all_needs_dict,
                filter=current_needsequence["filter"])
            p_string += p_string_new
            c_string += c_string_new

        puml_node["uml"] += p_string

        puml_node["uml"] += "\n' Connection definition \n\n"
        puml_node["uml"] += c_string

        # Create a legend
        if current_needsequence["show_legend"]:
            puml_node["uml"] += create_legend(app.config.needs_types)

        puml_node["uml"] += "\n@enduml"
        puml_node["incdir"] = os.path.dirname(current_needsequence["docname"])
        puml_node["filename"] = os.path.split(
            current_needsequence["docname"])[1]  # Needed for plantuml >= 0.9

        scale = int(current_needsequence["scale"])
        # if scale != 100:
        puml_node["scale"] = scale

        puml_node = nodes.figure("", puml_node)

        if current_needsequence["align"]:
            puml_node["align"] = current_needsequence["align"]
        else:
            puml_node["align"] = "center"

        if current_needsequence["caption"]:
            # Make the caption to a link to the original file.
            try:
                if "SVG" in app.config.plantuml_output_format.upper():
                    file_ext = "svg"
                else:
                    file_ext = "png"
            except Exception:
                file_ext = "png"

            gen_flow_link = generate_name(app, puml_node.children[0], file_ext)
            current_file_parts = fromdocname.split("/")
            subfolder_amount = len(current_file_parts) - 1
            img_locaton = "../" * subfolder_amount + "_images/" + gen_flow_link[
                0].split("/")[-1]
            flow_ref = nodes.reference("t",
                                       current_needsequence["caption"],
                                       refuri=img_locaton)
            puml_node += nodes.caption("", "", flow_ref)

        # Add lineno to node
        puml_node.line = current_needsequence["lineno"]

        content.append(puml_node)

        if len(content) == 0:
            nothing_found = "No needs passed the filters"
            para = nodes.paragraph()
            nothing_found_node = nodes.Text(nothing_found, nothing_found)
            para += nothing_found_node
            content.append(para)
        if current_needsequence["show_filters"]:
            content.append(get_filter_para(current_needsequence))

        if current_needsequence["debug"]:
            content += get_debug_container(puml_node)

        node.replace_self(content)
Example #46
0
 def run(self):
     figure_node = my_figure()
     figure_node += nodes.image(uri=self.arguments[0])
     figure_node += nodes.caption(text=''.join(self.content))
     return [figure_node]
Example #47
0
    def run(self):
        config = self.state.document.settings.env.config

        # Read enabled builders; Defaults to None
        if self.arguments:
            chosen_builders = choose_builders(self.arguments)
        else:
            chosen_builders = []

        # Enable 'http' language for http part
        self.arguments = ['http']

        # split the request and optional response in the content.
        # The separator is two empty lines followed by a line starting with
        # 'HTTP/'
        request_content = StringList()
        response_content = None
        emptylines_count = 0
        in_response = False
        for i, line in enumerate(self.content):
            source = self.content.source(i)
            if in_response:
                response_content.append(line, source)
            else:
                if emptylines_count >= 2 and line.startswith('HTTP/'):
                    in_response = True
                    response_content = StringList()
                    response_content.append(line, source)
                elif line == '':
                    emptylines_count += 1
                else:
                    request_content.extend(
                        StringList([''] * emptylines_count, source))
                    emptylines_count = 0
                    request_content.append(line, source)

        # Load optional external request
        cwd = os.path.dirname(self.state.document.current_source)
        if 'request' in self.options:
            request = utils.resolve_path(self.options['request'], cwd)
            with open(request) as fp:
                request_content = StringList(
                    list(map(str.rstrip, fp.readlines())), request)

        # Load optional external response
        if 'response' in self.options:
            response = utils.resolve_path(self.options['response'], cwd)
            with open(response) as fp:
                response_content = StringList(
                    list(map(str.rstrip, fp.readlines())), response)

        # reset the content to just the request
        self.content = request_content

        # Wrap and render main directive as 'http-example-http'
        klass = 'http-example-http'
        container = nodes.container('', classes=[klass])
        container.append(nodes.caption('', 'http'))
        container.extend(super(HTTPExample, self).run())

        # Init result node list
        result = [container]

        # Append builder responses
        for name in chosen_builders:
            raw = ('\r\n'.join(request_content)).encode('utf-8')
            request = parsers.parse_request(raw, config.httpexmpl_scheme)
            builder_, language = AVAILABLE_BUILDERS[name]
            command = builder_(request)

            content = StringList([command], request_content.source(0))
            options = self.options.copy()
            options.pop('name', None)
            options.pop('caption', None)

            block = CodeBlock(
                'code-block',
                [language],
                options,
                content,
                self.lineno,
                self.content_offset,
                self.block_text,
                self.state,
                self.state_machine
            )

            # Wrap and render main directive as 'http-example-{name}'
            klass = 'http-example-{}'.format(name)
            container = nodes.container('', classes=[klass])
            container.append(nodes.caption('', name))
            container.extend(block.run())

            # Append to result nodes
            result.append(container)

        # Append optional response
        if response_content:
            options = self.options.copy()
            options.pop('name', None)
            options.pop('caption', None)

            block = CodeBlock(
                'code-block',
                ['http'],
                options,
                response_content,
                self.lineno,
                self.content_offset,
                self.block_text,
                self.state,
                self.state_machine
            )

            # Wrap and render main directive as 'http-example-response'
            klass = 'http-example-response'
            container = nodes.container('', classes=[klass])
            container.append(nodes.caption('', 'response'))
            container.extend(block.run())

            # Append to result nodes
            result.append(container)

        # Final wrap
        container_node = nodes.container('', classes=['http-example'])
        container_node.extend(result)

        return [container_node]
def process_needgantt(app, doctree, fromdocname):
    # Replace all needgantt nodes with a list of the collected needs.
    env = app.builder.env

    # link_types = env.config.needs_extra_links
    # allowed_link_types_options = [link.upper() for link in env.config.needs_flow_link_types]

    # NEEDGANTT
    for node in doctree.traverse(Needgantt):
        if not app.config.needs_include_needs:
            # Ok, this is really dirty.
            # If we replace a node, docutils checks, if it will not lose any attributes.
            # But this is here the case, because we are using the attribute "ids" of a node.
            # However, I do not understand, why losing an attribute is such a big deal, so we delete everything
            # before docutils claims about it.
            for att in ("ids", "names", "classes", "dupnames"):
                node[att] = []
            node.replace_self([])
            continue

        id = node.attributes["ids"][0]
        current_needgantt = env.need_all_needgantts[id]
        all_needs_dict = env.needs_all_needs

        content = []
        try:
            if "sphinxcontrib.plantuml" not in app.config.extensions:
                raise ImportError
            from sphinxcontrib.plantuml import plantuml
        except ImportError:
            no_plantuml(node)
            continue

        plantuml_block_text = ".. plantuml::\n" "\n" "   @startuml" "   @enduml"
        puml_node = plantuml(plantuml_block_text)
        puml_node["uml"] = "@startuml\n"

        # Adding config
        config = current_needgantt["config"]
        puml_node["uml"] += add_config(config)

        all_needs = list(all_needs_dict.values())
        found_needs = process_filters(app, all_needs, current_needgantt)

        # Scale/timeline handling
        if current_needgantt["timeline"]:
            puml_node["uml"] += "printscale {}\n".format(
                current_needgantt["timeline"])

        # Project start date handling
        start_date_string = current_needgantt["start_date"]
        start_date_plantuml = None
        if start_date_string:
            try:
                start_date = datetime.strptime(start_date_string, "%Y-%m-%d")
                # start_date = datetime.fromisoformat(start_date_string)  # > py3.7 only
            except Exception:
                raise NeedGanttException(
                    'start_date "{}"for needgantt is invalid. '
                    'File: {}:current_needgantt["lineno"]'.format(
                        start_date_string, current_needgantt["docname"]))

            month = MONTH_NAMES[int(start_date.strftime("%m"))]
            start_date_plantuml = start_date.strftime(f"%dth of {month} %Y")
        if start_date_plantuml:
            puml_node["uml"] += f"Project starts the {start_date_plantuml}\n"

        # Element handling
        puml_node["uml"] += "\n' Elements definition \n\n"
        el_link_string = ""
        el_completion_string = ""
        el_color_string = ""
        for need in found_needs:
            complete = None

            if current_needgantt["milestone_filter"]:
                is_milestone = filter_single_need(
                    app, need, current_needgantt["milestone_filter"])
            else:
                is_milestone = False

            if current_needgantt["milestone_filter"] and is_milestone:
                gantt_element = "[{}] as [{}] lasts 0 days\n".format(
                    need["title"], need["id"])
            else:  # Normal gantt element handling
                duration_option = current_needgantt["duration_option"]
                duration = need[duration_option]
                complete_option = current_needgantt["completion_option"]
                complete = need[complete_option]
                if not (duration and duration.isdigit()):
                    logger.warning(
                        "Duration not set or invalid for needgantt chart. "
                        "Need: {}. Duration: {}".format(need["id"], duration))
                    duration = 1
                gantt_element = "[{}] as [{}] lasts {} days\n".format(
                    need["title"], need["id"], duration)

            el_link_string += "[{}] links to [[{}]]\n".format(
                need["title"], calculate_link(app, need, fromdocname))

            if complete:
                complete = complete.replace("%", "")
                el_completion_string += "[{}] is {}% completed\n".format(
                    need["title"], complete)

            el_color_string += "[{}] is colored in {}\n".format(
                need["title"], need["type_color"])

            puml_node["uml"] += gantt_element

        puml_node["uml"] += "\n' Element links definition \n\n"
        puml_node[
            "uml"] += "\n' Deactivated, as currently supported by plantuml beta only"
        # ToDo: Activate if linking is working with default plantuml
        # puml_node["uml"] += el_link_string + '\n'

        puml_node["uml"] += "\n' Element completion definition \n\n"
        puml_node["uml"] += el_completion_string + "\n"

        puml_node["uml"] += "\n' Element color definition \n\n"
        if current_needgantt["no_color"]:
            puml_node["uml"] += "' Color support deactivated via flag"
        else:
            puml_node["uml"] += el_color_string + "\n"

        # Constrain handling
        puml_node["uml"] += "\n' Constraints definition \n\n"
        puml_node["uml"] += "\n' Constraints definition \n\n"
        for need in found_needs:
            if current_needgantt["milestone_filter"]:
                is_milestone = filter_single_need(
                    app, need, current_needgantt["milestone_filter"])
            else:
                is_milestone = False
            constrain_types = [
                "starts_with_links", "starts_after_links", "ends_with_links"
            ]
            for con_type in constrain_types:
                if is_milestone:
                    keyword = "happens"
                elif con_type in ["starts_with_links", "starts_after_links"]:
                    keyword = "starts"
                else:
                    keyword = "ends"

                if con_type in ["starts_after_links", "ends_with_links"]:
                    start_end_sync = "end"
                else:
                    start_end_sync = "start"

                for link_type in current_needgantt[con_type]:
                    start_with_links = need[link_type]
                    for start_with_link in start_with_links:
                        start_need = all_needs_dict[start_with_link]
                        gantt_constraint = "[{}] {} at [{}]'s " "{}\n".format(
                            need["id"], keyword, start_need["id"],
                            start_end_sync)
                        puml_node["uml"] += gantt_constraint

        # Create a legend
        if current_needgantt["show_legend"]:
            puml_node["uml"] += create_legend(app.config.needs_types)

        puml_node["uml"] += "\n@enduml"
        puml_node["incdir"] = os.path.dirname(current_needgantt["docname"])
        puml_node["filename"] = os.path.split(
            current_needgantt["docname"])[1]  # Needed for plantuml >= 0.9

        scale = int(current_needgantt["scale"])
        # if scale != 100:
        puml_node["scale"] = scale

        puml_node = nodes.figure("", puml_node)

        puml_node["align"] = current_needgantt["align"] or "center"

        if current_needgantt["caption"]:
            # Make the caption to a link to the original file.
            try:
                if "SVG" in app.config.plantuml_output_format.upper():
                    file_ext = "svg"
                else:
                    file_ext = "png"
            except Exception:
                file_ext = "png"

            gen_flow_link = generate_name(app, puml_node.children[0], file_ext)
            current_file_parts = fromdocname.split("/")
            subfolder_amount = len(current_file_parts) - 1
            img_location = "../" * subfolder_amount + "_images/" + gen_flow_link[
                0].split("/")[-1]
            flow_ref = nodes.reference("t",
                                       current_needgantt["caption"],
                                       refuri=img_location)
            puml_node += nodes.caption("", "", flow_ref)

        # Add lineno to node
        puml_node.line = current_needgantt["lineno"]

        content.append(puml_node)

        if len(content) == 0:
            nothing_found = "No needs passed the filters"
            para = nodes.paragraph()
            nothing_found_node = nodes.Text(nothing_found, nothing_found)
            para += nothing_found_node
            content.append(para)
        if current_needgantt["show_filters"]:
            content.append(get_filter_para(current_needgantt))

        if current_needgantt["debug"]:
            content += get_debug_container(puml_node)

        puml_node["class"] = ["needgantt"]
        node.replace_self(content)
Example #49
0
    def latex(self, widget: Widget, code_block_info : CodeBlockInfo):
        """Performs Latex parsing on nodes

        Used to create the PDF builds of the site.

        Args:
            widget (Widget): The current working widget

        Returns:
            List[nodes]: Returns a list of Latex nodes
        """
        nodes_latex = []

        for f in widget.files:
            # Based on sphinx/directives/code.py

            container_node = nodes.container(
                '', literal_block=True,
                classes=['literal-block-wrapper'])

            literal = nodes.literal_block('',
                                            f.content,
                                            format='latex')
            literal['language'] = self.arguments[0].split(' ')[0]
            literal['linenos'] = True
            literal['source'] = f.basename

            caption = nodes.caption('', f.basename)
            caption.source = literal.source
            caption.line = literal.line

            container_node += caption
            container_node += literal

            nodes_latex.append(container_node)

        def get_info_preamble(info_type : str) -> str:
            known_info_type : Dict[str, str] = {
                'build'   : '\\textbf{Build output}',
                'run'     : '\\textbf{Runtime output}',
                'compile' : '\\textbf{Compilation output}',
                'prove'   : '\\textbf{Prover output}'
            }
            if info_type in known_info_type:
                return known_info_type[info_type]
            else:
                return "Let's " + info_type + " the example:"

        block_info : Dict[str, str] = code_block_info.get_info()

        for info_type in sorted(block_info):

            if block_info[info_type] == "":
                # Do not show empty boxes
                continue

            preamble_node = nodes.container(
                '', literal_block=False,
                classes=[])

            preamble_raw = nodes.raw('',
                                     get_info_preamble(info_type),
                                     format='latex')

            preamble_node += preamble_raw

            container_node = nodes.container(
                '', literal_block=True,
                classes=['literal-block-wrapper'])

            literal = nodes.literal_block('',
                                          block_info[info_type],
                                          format='latex')
            literal['language'] = 'none'
            literal['source'] = info_type

            caption = nodes.caption('', info_type)
            caption.source = literal.source
            caption.line = literal.line

            # container_node += caption
            container_node += literal

            nodes_latex.append(preamble_node)
            nodes_latex.append(container_node)

        return nodes_latex
Example #50
0
    def run(self):
        """ Parse a plotly chart directive """
        self.assert_has_content()
        env = self.state.document.settings.env

        # Ensure the current chart ID is initialised in the environment
        if "next_chart_id" not in env.temp_data:
            env.temp_data["next_chart_id"] = 0

        # Get the ID of this chart
        id = env.temp_data["next_chart_id"]

        # Handle the src and destination URI of the *.json asset
        uri = directives.uri(self.arguments[0].strip())
        src_uri = os.path.join(env.app.builder.srcdir,
                               uri)  # Where to get the asset during build
        build_uri = os.path.join(env.app.builder.outdir, "_charts",
                                 uri)  # Where to put the asset during build
        page_uri = os.path.join(
            env.app.builder.outdir,
            env.docname)  # The location of the current page
        relative_uri = relative_path(
            page_uri,
            build_uri)  # Ultimate path of the asset relative to current page

        # Create the main node container and store the URI of the file which will be collected later
        node = nodes.container(id="ffs")
        node["classes"] = ["sphinx-charts"]

        # Increment the ID counter ready for the next chart
        env.temp_data["next_chart_id"] += 1

        # Only if its a supported builder do we proceed (otherwise return an empty node)
        if env.app.builder.name in get_compatible_builders(env.app):

            # Make the directories and copy file (if file has changed)
            ensuredir(os.path.dirname(build_uri))
            copyfile(src_uri, build_uri)

            download_name = self.options.pop("download_name",
                                             DEFAULT_DOWNLOAD_NAME)
            chart_node = nodes.container()
            chart_node["classes"] = [
                "sphinx-charts-chart",
                f"sphinx-charts-chart-id-{id}",
                f"sphinx-charts-chart-uri-{relative_uri}",
                f"sphinx-charts-chart-dn-{download_name}",
            ]
            chart_node.replace_attr("ids", [f"sphinx-charts-chart-id-{id}"])

            # This is a botch. Purely here to force inclusion of mathjax on pages with charts but without latex in the
            # document, because it doesn't find the $$ in the chart data (which isn't part of the document tree)
            math_node = nodes.paragraph("$$", "")
            math_node["classes"] = ["sphinx-charts-hidden"]

            placeholder_node = nodes.container()
            placeholder_node["classes"] = [
                "sphinx-charts-placeholder", f"sphinx-charts-placeholder-{id}"
            ]
            placeholder_node += nodes.caption("", "Loading...")

            node += chart_node
            node += math_node
            node += placeholder_node

            # Add optional chart caption and legend (as per figure directive)
            if self.content:
                caption_node = nodes.Element(
                )  # Anonymous container for parsing
                self.state.nested_parse(self.content, self.content_offset,
                                        caption_node)
                first_node = caption_node[0]
                if isinstance(first_node, nodes.paragraph):
                    caption = nodes.caption(first_node.rawsource, "",
                                            *first_node.children)
                    caption.source = first_node.source
                    caption.line = first_node.line
                    node += caption
                elif not (isinstance(first_node, nodes.comment)
                          and len(first_node) == 0):
                    error = self.state_machine.reporter.error(
                        "Chart caption must be a paragraph or empty comment.",
                        nodes.literal_block(self.block_text, self.block_text),
                        line=self.lineno,
                    )
                    return [node, error]
                if len(caption_node) > 1:
                    node += nodes.legend("", *caption_node[1:])

        return [node]
Example #51
0
    def run(self):
        """ Executes python code for an RST document, taking input from content or from a filename
        :return:
        """
        language = self.options.get('language', 'python')
        output_language = self.options.get('output_language', 'none')

        output = []

        shown_code = ''
        executed_code = ''

        hide = False
        skip = False
        for line in self.content:
            line_switch = line.replace(' ', '').lower()
            if line_switch == '#hide':
                hide = not hide
                continue
            if line_switch == '#skip':
                skip = not skip
                continue

            if not hide:
                shown_code += line + '\n'
            if not skip:
                executed_code += line + '\n'

        shown_code = shown_code.strip()

        # Show the example code
        if 'hide_code' not in self.options:
            input_code = nodes.literal_block(shown_code, shown_code)

            input_code['language'] = language
            input_code['linenos'] = 'linenos' in self.options
            if 'header_code' in self.options:
                output.append(nodes.caption(text=self.options['header_code']))
            output.append(input_code)

        # Show the code results
        if 'header_output' in self.options:
            output.append(nodes.caption(text=self.options['header_output']))

        code_results = execute_code(executed_code,
                                    ignore_stderr='ignore_stderr'
                                    in self.options)

        if 'ignore_stderr' not in self.options:
            for out in code_results.split('\n'):
                if 'Error in ' in out:
                    log.error(f'Possible Error in codeblock: {out}')

        code_results = nodes.literal_block(code_results, code_results)

        code_results['linenos'] = 'linenos' in self.options
        code_results['language'] = output_language

        if 'hide_output' not in self.options:
            output.append(code_results)
        return output
Example #52
0
    def run(self) -> List[nodes.Node]:
        figwidth = self.options.pop("width", None)
        figclasses = self.options.pop("class", None)
        align = self.options.pop("align", None)

        # parser = default_parser(self.env.myst_config)

        node = nodes.Element()
        # TODO test that we are using myst parser
        # ensure html image enabled
        enable_html_img = self.state._renderer.config.get("enable_html_img", False)
        try:
            self.state._renderer.config["enable_html_img"] = True
            self.state.nested_parse(self.content, self.content_offset, node)
        finally:
            self.state._renderer.config["enable_html_img"] = enable_html_img

        if not len(node.children) == 2:
            return [
                self.figure_error(
                    "content should be one image, "
                    "followed by a single paragraph caption"
                )
            ]

        image_node, caption_para = node.children
        if isinstance(image_node, nodes.paragraph):
            image_node = image_node[0]

        if not isinstance(image_node, nodes.image):
            return [
                self.figure_error(
                    "content should be one image (not found), "
                    "followed by single paragraph caption"
                )
            ]

        if not isinstance(caption_para, nodes.paragraph):
            return [
                self.figure_error(
                    "content should be one image, "
                    "followed by single paragraph caption (not found)"
                )
            ]

        caption_node = nodes.caption(caption_para.rawsource, "", *caption_para.children)
        caption_node.source = caption_para.source
        caption_node.line = caption_para.line

        figure_node = nodes.figure("", image_node, caption_node)
        self.set_source_info(figure_node)

        if figwidth is not None:
            figure_node["width"] = figwidth
        if figclasses:
            figure_node["classes"] += figclasses
        if align:
            figure_node["align"] = align
        if self.arguments:
            self.options["name"] = self.arguments[0]
            self.add_name(figure_node)

        return [figure_node]
Example #53
0
def process_needflow(app, doctree, fromdocname):
    # Replace all needflow nodes with a list of the collected needs.
    # Augment each need with a backlink to the original location.
    env = app.builder.env

    link_types = env.config.needs_extra_links
    allowed_link_types_options = [link.upper() for link in env.config.needs_flow_link_types]

    # NEEDFLOW
    for node in doctree.traverse(Needflow):
        if not app.config.needs_include_needs:
            # Ok, this is really dirty.
            # If we replace a node, docutils checks, if it will not lose any attributes.
            # But this is here the case, because we are using the attribute "ids" of a node.
            # However, I do not understand, why losing an attribute is such a big deal, so we delete everything
            # before docutils claims about it.
            for att in ("ids", "names", "classes", "dupnames"):
                node[att] = []
            node.replace_self([])
            continue

        id = node.attributes["ids"][0]
        current_needflow = env.need_all_needflows[id]
        all_needs = env.needs_all_needs

        option_link_types = [link.upper() for link in current_needflow["link_types"]]
        for lt in option_link_types:
            if lt not in [link["option"].upper() for link in link_types]:
                logger.warning(
                    "Unknown link type {link_type} in needflow {flow}. Allowed values: {link_types}".format(
                        link_type=lt, flow=current_needflow["target_node"], link_types=",".join(link_types)
                    )
                )

        content = []
        try:
            if "sphinxcontrib.plantuml" not in app.config.extensions:
                raise ImportError
            from sphinxcontrib.plantuml import plantuml
        except ImportError:
            content = nodes.error()
            para = nodes.paragraph()
            text = nodes.Text("PlantUML is not available!", "PlantUML is not available!")
            para += text
            content.append(para)
            node.replace_self(content)
            continue

        plantuml_block_text = ".. plantuml::\n" "\n" "   @startuml" "   @enduml"
        puml_node = plantuml(plantuml_block_text)
        puml_node["uml"] = "@startuml\n"
        puml_connections = ""

        # Adding config
        config = current_needflow["config"]
        if config and len(config) >= 3:
            # Remove all empty lines
            config = "\n".join([line.strip() for line in config.split("\n") if line.strip()])
            puml_node["uml"] += "\n' Config\n\n"
            puml_node["uml"] += config
            puml_node["uml"] += "\n\n"

        all_needs = list(all_needs.values())
        found_needs = process_filters(app, all_needs, current_needflow)

        processed_need_part_ids = []

        puml_node["uml"] += "\n' Nodes definition \n\n"

        for need_info in found_needs:
            # Check if need_part was already handled during handling of parent need.
            # If this is the case, it is already part of puml-code and we do not need to create a node.
            if not (need_info["is_part"] and need_info["id_complete"] in processed_need_part_ids):
                # Check if we need to embed need_parts into parent need, because they are also part of search result.
                node_part_code = ""
                valid_need_parts = [x for x in found_needs if x["is_part"] and x["id_parent"] == need_info["id"]]
                for need_part in valid_need_parts:
                    part_link = calculate_link(app, need_part, fromdocname)
                    diagram_template = Template(env.config.needs_diagram_template)
                    part_text = diagram_template.render(**need_part)
                    part_colors = []
                    if need_part["type_color"]:
                        # We set # later, as the user may not have given a color and the node must get highlighted
                        part_colors.append(need_part["type_color"].replace("#", ""))

                    if current_needflow["highlight"] and filter_single_need(
                        app, need_part, current_needflow["highlight"], all_needs
                    ):
                        part_colors.append("line:FF0000")

                    node_part_code += '{style} "{node_text}" as {id} [[{link}]] #{color}\n'.format(
                        id=make_entity_name(need_part["id_complete"]),
                        node_text=part_text,
                        link=part_link,
                        color=";".join(part_colors),
                        style="rectangle",
                    )

                    processed_need_part_ids.append(need_part["id_complete"])

                link = calculate_link(app, need_info, fromdocname)

                diagram_template = Template(env.config.needs_diagram_template)
                node_text = diagram_template.render(**need_info)
                if need_info["is_part"]:
                    need_id = need_info["id_complete"]
                else:
                    need_id = need_info["id"]

                colors = []
                if need_info["type_color"]:
                    # We set # later, as the user may not have given a color and the node must get highlighted
                    colors.append(need_info["type_color"].replace("#", ""))

                if current_needflow["highlight"] and filter_single_need(
                    app, need_info, current_needflow["highlight"], all_needs
                ):
                    colors.append("line:FF0000")

                # Only add subelements and their {...} container, if we really need them.
                # Otherwise plantuml may not set style correctly, if {..} is empty
                if node_part_code:
                    node_part_code = f"{{\n {node_part_code} }}"

                style = need_info["type_style"]

                node_code = '{style} "{node_text}" as {id} [[{link}]] #{color} {need_parts}\n'.format(
                    id=make_entity_name(need_id),
                    node_text=node_text,
                    link=link,
                    color=";".join(colors),
                    style=style,
                    need_parts=node_part_code,
                )
                puml_node["uml"] += node_code

            for link_type in link_types:
                # Skip link-type handling, if it is not part of a specified list of allowed link_types or
                # if not part of the overall configuration of needs_flow_link_types
                if (current_needflow["link_types"] and link_type["option"].upper() not in option_link_types) or (
                    not current_needflow["link_types"] and link_type["option"].upper() not in allowed_link_types_options
                ):
                    continue

                for link in need_info[link_type["option"]]:
                    # If source or target of link is a need_part, a specific style is needed
                    if "." in link or "." in need_info["id_complete"]:
                        final_link = link
                        if current_needflow["show_link_names"] or env.config.needs_flow_show_links:
                            desc = link_type["outgoing"] + "\\n"
                            comment = f": {desc}"
                        else:
                            comment = ""

                        if "style_part" in link_type and link_type["style_part"]:
                            link_style = "[{style}]".format(style=link_type["style_part"])
                        else:
                            link_style = "[dotted]"
                    else:
                        final_link = link
                        if current_needflow["show_link_names"] or env.config.needs_flow_show_links:
                            comment = ": {desc}".format(desc=link_type["outgoing"])
                        else:
                            comment = ""

                        if "style" in link_type and link_type["style"]:
                            link_style = "[{style}]".format(style=link_type["style"])
                        else:
                            link_style = ""

                    # Do not create an links, if the link target is not part of the search result.
                    if final_link not in [x["id"] for x in found_needs if x["is_need"]] and final_link not in [
                        x["id_complete"] for x in found_needs if x["is_part"]
                    ]:
                        continue

                    if "style_start" in link_type and link_type["style_start"]:
                        style_start = link_type["style_start"]
                    else:
                        style_start = "-"

                    if "style_end" in link_type and link_type["style_end"]:
                        style_end = link_type["style_end"]
                    else:
                        style_end = "->"

                    puml_connections += "{id} {style_start}{link_style}{style_end} {link}{comment}\n".format(
                        id=make_entity_name(need_info["id_complete"]),
                        link=make_entity_name(final_link),
                        comment=comment,
                        link_style=link_style,
                        style_start=style_start,
                        style_end=style_end,
                    )

        puml_node["uml"] += "\n' Connection definition \n\n"
        puml_node["uml"] += puml_connections

        # Create a legend
        if current_needflow["show_legend"]:
            puml_node["uml"] += create_legend(app.config.needs_types)

        puml_node["uml"] += "\n@enduml"
        puml_node["incdir"] = os.path.dirname(current_needflow["docname"])
        puml_node["filename"] = os.path.split(current_needflow["docname"])[1]  # Needed for plantuml >= 0.9

        scale = int(current_needflow["scale"])
        # if scale != 100:
        puml_node["scale"] = scale

        puml_node = nodes.figure("", puml_node)

        if current_needflow["align"]:
            puml_node["align"] = current_needflow["align"]
        else:
            puml_node["align"] = "center"

        if current_needflow["caption"]:
            # Make the caption to a link to the original file.
            try:
                if "SVG" in app.config.plantuml_output_format.upper():
                    file_ext = "svg"
                else:
                    file_ext = "png"
            except Exception:
                file_ext = "png"

            gen_flow_link = generate_name(app, puml_node.children[0], file_ext)
            current_file_parts = fromdocname.split("/")
            subfolder_amount = len(current_file_parts) - 1
            img_locaton = "../" * subfolder_amount + "_images/" + gen_flow_link[0].split("/")[-1]
            flow_ref = nodes.reference("t", current_needflow["caption"], refuri=img_locaton)
            puml_node += nodes.caption("", "", flow_ref)

        # Add lineno to node
        puml_node.line = current_needflow["lineno"]

        content.append(puml_node)

        if len(content) == 0:
            nothing_found = "No needs passed the filters"
            para = nodes.paragraph()
            nothing_found_node = nodes.Text(nothing_found, nothing_found)
            para += nothing_found_node
            content.append(para)
        if current_needflow["show_filters"]:
            para = nodes.paragraph()
            filter_text = "Used filter:"
            filter_text += (
                " status(%s)" % " OR ".join(current_needflow["status"]) if len(current_needflow["status"]) > 0 else ""
            )
            if len(current_needflow["status"]) > 0 and len(current_needflow["tags"]) > 0:
                filter_text += " AND "
            filter_text += (
                " tags(%s)" % " OR ".join(current_needflow["tags"]) if len(current_needflow["tags"]) > 0 else ""
            )
            if (len(current_needflow["status"]) > 0 or len(current_needflow["tags"]) > 0) and len(
                current_needflow["types"]
            ) > 0:
                filter_text += " AND "
            filter_text += (
                " types(%s)" % " OR ".join(current_needflow["types"]) if len(current_needflow["types"]) > 0 else ""
            )

            filter_node = nodes.emphasis(filter_text, filter_text)
            para += filter_node
            content.append(para)

        if current_needflow["debug"]:
            debug_container = nodes.container()
            if isinstance(puml_node, nodes.figure):
                data = puml_node.children[0]["uml"]
            else:
                data = puml_node["uml"]
            data = "\n".join([html.escape(line) for line in data.split("\n")])
            debug_para = nodes.raw("", f"<pre>{data}</pre>", format="html")
            debug_container += debug_para
            content += debug_container

        node.replace_self(content)
Example #54
0
    def run(self):
        grid_node = nodes.container()
        grid_node['classes'] += ['m-imagegrid', 'm-container-inflate']

        rows = [[]]
        total_widths = [0]
        for uri in self.content:
            # New line, calculating width from 0 again
            if not uri:
                rows.append([])
                total_widths.append(0)
                continue

            # Open the files and calculate the overall width
            # Support both {filename} (3.7.1) and {static} (3.8) placeholders
            file = os.path.join(os.getcwd(), settings['PATH'])
            absuri = uri.format(filename=file, static=file)
            im = PIL.Image.open(absuri)

            # Get EXIF info, if it's there
            if hasattr(im, '_getexif') and im._getexif() is not None:
                exif = {
                    PIL.ExifTags.TAGS[k]: v
                    for k, v in im._getexif().items()
                    if k in PIL.ExifTags.TAGS and len(str(v)) < 256
                }

                # Not all info might be present
                caption = []
                if 'FNumber' in exif:
                    caption += [
                        "F{}".format(
                            float(
                                float(exif['FNumber'][0]) /
                                float(exif['FNumber'][1])))
                    ]
                if 'ExposureTime' in exif:
                    numerator, denominator = exif['ExposureTime']
                    if int(numerator) > int(denominator):
                        caption += [
                            "{} s".format(
                                float(numerator) / float(denominator))
                        ]
                    else:
                        caption += ["{}/{} s".format(numerator, denominator)]
                if 'ISOSpeedRatings' in exif:
                    caption += ["ISO {}".format(exif['ISOSpeedRatings'])]
                caption = ', '.join(caption)

            # It's not (e.g. a PNG file), empty caption
            else:
                caption = ""

            rel_width = float(im.width) / im.height
            total_widths[-1] += rel_width
            rows[-1].append((uri, rel_width, caption))

        for i, row in enumerate(rows):
            row_node = nodes.container()

            for uri, rel_width, caption in row:
                image_reference = rst.directives.uri(uri)
                image_node = nodes.image('', uri=image_reference)

                # <figurecaption> in case there's a caption
                if caption:
                    text_nodes, _ = self.state.inline_text(
                        caption, self.lineno)
                    text_node = nodes.paragraph('', '', *text_nodes)
                    overlay_node = nodes.caption()
                    overlay_node.append(text_node)

                # Otherwise an empty <div>
                else:
                    overlay_node = nodes.container()

                link_node = nodes.reference('', refuri=image_reference)
                link_node.append(image_node)
                link_node.append(overlay_node)
                wrapper_node = nodes.figure(
                    width="{:.3f}%".format(rel_width * 100.0 /
                                           total_widths[i]))
                wrapper_node.append(link_node)
                row_node.append(wrapper_node)

            grid_node.append(row_node)

        return [grid_node]
Example #55
0
        def _render_image(output: NotebookNode, index: int):
            # Sphinx treats absolute paths as being rooted at the source
            # directory, so make a relative path, which Sphinx treats
            # as being relative to the current working directory.
            filename = os.path.basename(output.metadata["filenames"][mime_type])

            # checks if file dir path is inside a subdir of dir
            filedir = os.path.dirname(output.metadata["filenames"][mime_type])
            subpaths = filedir.split(self.sphinx_dir)
            final_dir = self.sphinx_dir
            if subpaths and len(subpaths) > 1:
                subpath = subpaths[1]
                final_dir += subpath

            uri = os.path.join(final_dir, filename)
            # TODO I'm not quite sure why, but as soon as you give it a width,
            # it becomes clickable?! (i.e. will open the image in the browser)
            image_node = nodes.image(uri=uri)

            myst_meta_img = self.node.metadata.get(
                self.env.config.nb_render_key, {}
            ).get("image", {})

            for key, spec in [
                ("classes", directives.class_option),
                ("alt", directives.unchanged),
                ("height", directives.length_or_unitless),
                ("width", directives.length_or_percentage_or_unitless),
                ("scale", directives.percentage),
                ("align", align),
            ]:
                if key in myst_meta_img:
                    value = myst_meta_img[key]
                    try:
                        image_node[key] = spec(value)
                    except (ValueError, TypeError) as error:
                        error_msg = (
                            "Invalid image attribute: "
                            "(key: '{}'; value: {})\n{}".format(key, value, error)
                        )
                        return [self.make_error(error_msg)]

            myst_meta_fig = self.node.metadata.get(
                self.env.config.nb_render_key, {}
            ).get("figure", {})
            if "caption" not in myst_meta_fig:
                return [image_node]

            figure_node = nodes.figure("", image_node)
            caption = nodes.caption(myst_meta_fig["caption"], "")
            figure_node += caption
            # TODO only contents of one paragraph? (and second should be a legend)
            self.parse_markdown(myst_meta_fig["caption"], caption)
            if "name" in myst_meta_fig:
                name = myst_meta_fig["name"]
                self.add_source_and_line(figure_node)
                self.add_name(figure_node, name)
                # The target should have already been processed by now, with
                # sphinx.transforms.references.SphinxDomains, which calls
                # sphinx.domains.std.StandardDomain.process_doc,
                # so we have to replicate that here
                std = self.env.get_domain("std")
                nametypes = self.document.nametypes.items()
                self.document.nametypes = {name: True}
                try:
                    std.process_doc(self.env, self.env.docname, self.document)
                finally:
                    self.document.nametypes = nametypes

            return [figure_node]
Example #56
0
    def render_container_myst_open(self, token):
        """Render a container (`:::{name}` blocks), based on its name."""
        # match first line regex
        match = REGEX_ADMONTION.match(token.info.strip())

        # default behaviour
        if not match:
            return self.default_container(
                token, "admonition argument did not match required regex")

        name = match.groupdict()["name"]

        if name in STD_ADMONITIONS:
            admonition = self.get_admonition(token, **match.groupdict())
            self.add_line_and_source_path(admonition, token)
            with self.current_node_context(admonition, append=True):
                self.render_children(token)
            return

        if name == "figure" and self.config.get("enable_figures", False):
            # must be of length 2
            if not len(token.children) == 2:
                return self.figure_error(token)
            # 1st must be paragraph_open with 1 child type inline and 1 child type image
            html_image = None
            if token.children[0].type == "html_block":
                html_image = HTMLImgParser().parse(token.children[0].content,
                                                   self.document,
                                                   token.children[0].map[0])
                if html_image is None:
                    return self.figure_error(token)
            elif not (token.children[0].children
                      and len(token.children[0].children) == 1
                      and len(token.children[0].children[0].children) == 1
                      and token.children[0].children[0].children[0].type
                      == "image"):
                return self.figure_error(token)
            # 2nd must be a paragraph
            if not token.children[1].type == "paragraph_open":
                return self.figure_error(token)

            figure_node = nodes.figure(
                "", classes=match.groupdict()["classes"][1:].split(","))
            if match.groupdict()["title"].strip():
                name = nodes.fully_normalize_name(
                    match.groupdict()["title"].strip())
                figure_node["names"].append(name)
                self.document.note_explicit_target(figure_node, figure_node)
            with self.current_node_context(figure_node, append=True):
                if html_image is None:
                    self.render_image(
                        token.children[0].children[0].children[0])
                else:
                    self.current_node.append(html_image)
                caption = nodes.caption("", "")
                with self.current_node_context(caption, append=True):
                    self.render_children(token.children[1])
            return

        return self.default_container(
            token, f"admonition name not recognised: {name}")
Example #57
0
    def run(self):
        """ Restructured text extension for including inline JSAV content on module pages """
        self.options['exer_name'] = self.arguments[0]
        self.options['type'] = self.arguments[1]
        self.options['odsa_path'] = os.path.relpath(conf.odsa_path,
                                                    conf.ebook_path)

        # Set defaults for any values that aren't configured
        if 'required' not in self.options:
            self.options['required'] = False

        if 'points' not in self.options:
            self.options['points'] = 0

        if 'threshold' not in self.options:
            self.options['threshold'] = 1.0

        if 'long_name' not in self.options:
            self.options['long_name'] = self.options['exer_name']

        if 'align' not in self.options:
            self.options['align'] = 'center'

        if 'output' in self.options and self.options['output'] == "show":
            self.options['output_code'] = '<p class="jsavoutput jsavline"></p>'
        else:
            self.options['output_code'] = ''

        if self.options['type'] == "dgm":
            avdgm_node = av_dgm()
            anchor_node = av_anchor()

            avdgm_node['exer_name'] = self.options['exer_name']
            anchor_node['ids'].append(self.options['exer_name'])
            avdgm_node += anchor_node
            if self.content:
                node = nodes.Element()  # anonymous container for parsing
                self.state.nested_parse(self.content, self.content_offset,
                                        node)
                first_node = node[0]
                if isinstance(first_node, nodes.paragraph):
                    caption = nodes.caption(first_node.rawsource, '',
                                            *first_node.children)
                    caption['align'] = self.options['align']
                    avdgm_node += caption

            return [avdgm_node]
        elif self.options['type'] == "ss" and self.content:
            avss_node = av_ss()
            avss_node['res'] = SLIDESHOW % self.options
            node = nodes.Element()  # anonymous container for parsing
            self.state.nested_parse(self.content, self.content_offset, node)
            first_node = node[0]
            if isinstance(first_node, nodes.paragraph):
                caption = nodes.caption(first_node.rawsource, '',
                                        *first_node.children)
                caption['align'] = self.options['align']
                avss_node += caption
            return [avss_node]
        else:
            res = SLIDESHOW % self.options
            return [nodes.raw('', res, format='html')]
def process_needsequence(app, doctree, fromdocname):
    # Replace all needsequence nodes with a list of the collected needs.
    env = app.builder.env

    link_types = env.config.needs_extra_links
    allowed_link_types_options = [
        link.upper() for link in env.config.needs_flow_link_types
    ]

    # NEEDSEQUENCE
    for node in doctree.traverse(Needsequence):
        if not app.config.needs_include_needs:
            # Ok, this is really dirty.
            # If we replace a node, docutils checks, if it will not lose any attributes.
            # But this is here the case, because we are using the attribute "ids" of a node.
            # However, I do not understand, why losing an attribute is such a big deal, so we delete everything
            # before docutils claims about it.
            for att in ('ids', 'names', 'classes', 'dupnames'):
                node[att] = []
            node.replace_self([])
            continue

        id = node.attributes["ids"][0]
        current_needsequence = env.need_all_needsequences[id]
        all_needs_dict = env.needs_all_needs

        option_link_types = [
            link.upper() for link in current_needsequence['link_types']
        ]
        for lt in option_link_types:
            if lt not in [link['option'].upper() for link in link_types]:
                logger.warning(
                    'Unknown link type {link_type} in needsequence {flow}. Allowed values:'
                    ' {link_types}'.format(
                        link_type=lt,
                        flow=current_needsequence['target_node'],
                        link_types=",".join(link_types)))

        content = []
        try:
            if "sphinxcontrib.plantuml" not in app.config.extensions:
                raise ImportError
            from sphinxcontrib.plantuml import plantuml
        except ImportError:
            no_plantuml(node)
            continue

        plantuml_block_text = ".. plantuml::\n" \
                              "\n" \
                              "   @startuml" \
                              "   @enduml"
        puml_node = plantuml(plantuml_block_text, **dict())
        puml_node["uml"] = "@startuml\n"

        # Adding config
        config = current_needsequence['config']
        puml_node["uml"] += add_config(config)

        all_needs = list(all_needs_dict.values())

        start_needs_id = [
            x.strip() for x in re.split(";|,", current_needsequence['start'])
        ]
        if len(start_needs_id) == 0:
            raise NeedsequenceDirective('No start-id set for needsequence'
                                        ' File '
                                        ':{}'.format(
                                            {current_needsequence["docname"]},
                                            current_needsequence["lineno"]))

        puml_node["uml"] += '\n\' Nodes definition \n\n'

        # Add  start participants
        p_string = ''
        c_string = ''
        for need_id in start_needs_id:
            try:
                need = all_needs_dict[need_id.strip()]
            except KeyError:
                raise NeedSequenceException(
                    'Given {} in needsequence unknown.'
                    ' File {}'
                    ':{}'.format(need_id, current_needsequence["docname"],
                                 current_needsequence["lineno"]))

            # Add children of participants
            msg_receiver_needs, p_string_new, c_string_new = get_message_needs(
                need,
                current_needsequence['link_types'],
                all_needs_dict,
                filter=current_needsequence['filter'])
            p_string += p_string_new
            c_string += c_string_new

        puml_node["uml"] += p_string

        puml_node["uml"] += '\n\' Connection definition \n\n'
        puml_node["uml"] += c_string

        # Create a legend
        if current_needsequence["show_legend"]:
            puml_node["uml"] += '\n\n\' Legend definition \n\n'

            puml_node["uml"] += "legend\n"
            puml_node["uml"] += "|= Color |= Type |\n"
            for need in app.config.needs_types:
                puml_node[
                    "uml"] += "|<back:{color}> {color} </back>| {name} |\n".format(
                        color=need["color"], name=need["title"])
            puml_node["uml"] += "endlegend\n"

        puml_node["uml"] += "\n@enduml"
        puml_node["incdir"] = os.path.dirname(current_needsequence["docname"])
        puml_node["filename"] = os.path.split(
            current_needsequence["docname"])[1]  # Needed for plantuml >= 0.9

        scale = int(current_needsequence['scale'])
        # if scale != 100:
        puml_node['scale'] = scale

        puml_node = nodes.figure('', puml_node)

        if current_needsequence['align'] is not None and len(
                current_needsequence['align']) != '':
            puml_node['align'] = current_needsequence['align']
        else:
            puml_node['align'] = 'center'

        if current_needsequence['caption'] is not None and len(
                current_needsequence['caption']) != '':
            # Make the caption to a link to the original file.
            try:
                if "SVG" in app.config.plantuml_output_format.upper():
                    file_ext = 'svg'
                else:
                    file_ext = 'png'
            except Exception:
                file_ext = 'png'

            gen_flow_link = generate_name(app, puml_node.children[0], file_ext)
            current_file_parts = fromdocname.split('/')
            subfolder_amount = len(current_file_parts) - 1
            img_locaton = '../' * subfolder_amount + '_images/' + gen_flow_link[
                0].split('/')[-1]
            flow_ref = nodes.reference('t',
                                       current_needsequence['caption'],
                                       refuri=img_locaton)
            puml_node += nodes.caption('', '', flow_ref)

        content.append(puml_node)

        if len(content) == 0:
            nothing_found = "No needs passed the filters"
            para = nodes.paragraph()
            nothing_found_node = nodes.Text(nothing_found, nothing_found)
            para += nothing_found_node
            content.append(para)
        if current_needsequence["show_filters"]:
            content.append(get_filter_para(current_needsequence))

        if current_needsequence['debug']:
            content += get_debug_containter(puml_node)

        node.replace_self(content)
Example #59
0
    def resolve_toctree(self,
                        docname,
                        builder,
                        toctree,
                        prune=True,
                        maxdepth=0,
                        titles_only=False,
                        collapse=False,
                        includehidden=False):
        # type: (unicode, Builder, addnodes.toctree, bool, int, bool, bool, bool) -> nodes.Node
        """Resolve a *toctree* node into individual bullet lists with titles
        as items, returning None (if no containing titles are found) or
        a new node.

        If *prune* is True, the tree is pruned to *maxdepth*, or if that is 0,
        to the value of the *maxdepth* option on the *toctree* node.
        If *titles_only* is True, only toplevel document titles will be in the
        resulting tree.
        If *collapse* is True, all branches not containing docname will
        be collapsed.
        """
        if toctree.get('hidden', False) and not includehidden:
            return None

        # For reading the following two helper function, it is useful to keep
        # in mind the node structure of a toctree (using HTML-like node names
        # for brevity):
        #
        # <ul>
        #   <li>
        #     <p><a></p>
        #     <p><a></p>
        #     ...
        #     <ul>
        #       ...
        #     </ul>
        #   </li>
        # </ul>
        #
        # The transformation is made in two passes in order to avoid
        # interactions between marking and pruning the tree (see bug #1046).

        toctree_ancestors = self.get_toctree_ancestors(docname)

        def _toctree_add_classes(node, depth):
            """Add 'toctree-l%d' and 'current' classes to the toctree."""
            for subnode in node.children:
                if isinstance(subnode,
                              (addnodes.compact_paragraph, nodes.list_item)):
                    # for <p> and <li>, indicate the depth level and recurse
                    subnode['classes'].append('toctree-l%d' % (depth - 1))
                    _toctree_add_classes(subnode, depth)
                elif isinstance(subnode, nodes.bullet_list):
                    # for <ul>, just recurse
                    _toctree_add_classes(subnode, depth + 1)
                elif isinstance(subnode, nodes.reference):
                    # for <a>, identify which entries point to the current
                    # document and therefore may not be collapsed
                    if subnode['refuri'] == docname:
                        if not subnode['anchorname']:
                            # give the whole branch a 'current' class
                            # (useful for styling it differently)
                            branchnode = subnode
                            while branchnode:
                                branchnode['classes'].append('current')
                                branchnode = branchnode.parent
                        # mark the list_item as "on current page"
                        if subnode.parent.parent.get('iscurrent'):
                            # but only if it's not already done
                            return
                        while subnode:
                            subnode['iscurrent'] = True
                            subnode = subnode.parent

        def _entries_from_toctree(toctreenode,
                                  parents,
                                  separate=False,
                                  subtree=False):
            """Return TOC entries for a toctree node."""
            refs = [(e[0], e[1]) for e in toctreenode['entries']]
            entries = []
            for (title, ref) in refs:
                try:
                    refdoc = None
                    if url_re.match(ref):
                        if title is None:
                            title = ref
                        reference = nodes.reference('',
                                                    '',
                                                    internal=False,
                                                    refuri=ref,
                                                    anchorname='',
                                                    *[nodes.Text(title)])
                        para = addnodes.compact_paragraph('', '', reference)
                        item = nodes.list_item('', para)
                        toc = nodes.bullet_list('', item)
                    elif ref == 'self':
                        # 'self' refers to the document from which this
                        # toctree originates
                        ref = toctreenode['parent']
                        if not title:
                            title = clean_astext(self.env.titles[ref])
                        reference = nodes.reference('',
                                                    '',
                                                    internal=True,
                                                    refuri=ref,
                                                    anchorname='',
                                                    *[nodes.Text(title)])
                        para = addnodes.compact_paragraph('', '', reference)
                        item = nodes.list_item('', para)
                        # don't show subitems
                        toc = nodes.bullet_list('', item)
                    else:
                        if ref in parents:
                            logger.warning(
                                'circular toctree references '
                                'detected, ignoring: %s <- %s',
                                ref,
                                ' <- '.join(parents),
                                location=ref)
                            continue
                        refdoc = ref
                        toc = self.tocs[ref].deepcopy()
                        maxdepth = self.env.metadata[ref].get('tocdepth', 0)
                        if ref not in toctree_ancestors or (prune
                                                            and maxdepth > 0):
                            self._toctree_prune(toc, 2, maxdepth, collapse)
                        process_only_nodes(toc, builder.tags)
                        if title and toc.children and len(toc.children) == 1:
                            child = toc.children[0]
                            for refnode in child.traverse(nodes.reference):
                                if refnode['refuri'] == ref and \
                                   not refnode['anchorname']:
                                    refnode.children = [nodes.Text(title)]
                    if not toc.children:
                        # empty toc means: no titles will show up in the toctree
                        logger.warning(
                            'toctree contains reference to document %r that '
                            'doesn\'t have a title: no link will be generated',
                            ref,
                            location=toctreenode)
                except KeyError:
                    # this is raised if the included file does not exist
                    logger.warning(
                        'toctree contains reference to nonexisting document %r',
                        ref,
                        location=toctreenode)
                else:
                    # if titles_only is given, only keep the main title and
                    # sub-toctrees
                    if titles_only:
                        # delete everything but the toplevel title(s)
                        # and toctrees
                        for toplevel in toc:
                            # nodes with length 1 don't have any children anyway
                            if len(toplevel) > 1:
                                subtrees = toplevel.traverse(addnodes.toctree)
                                if subtrees:
                                    toplevel[1][:] = subtrees
                                else:
                                    toplevel.pop(1)
                    # resolve all sub-toctrees
                    for subtocnode in toc.traverse(addnodes.toctree):
                        if not (subtocnode.get('hidden', False)
                                and not includehidden):
                            i = subtocnode.parent.index(subtocnode) + 1
                            for item in _entries_from_toctree(
                                    subtocnode, [refdoc] + parents,
                                    subtree=True):
                                subtocnode.parent.insert(i, item)
                                i += 1
                            subtocnode.parent.remove(subtocnode)
                    if separate:
                        entries.append(toc)
                    else:
                        entries.extend(toc.children)
            if not subtree and not separate:
                ret = nodes.bullet_list()
                ret += entries
                return [ret]
            return entries

        maxdepth = maxdepth or toctree.get('maxdepth', -1)
        if not titles_only and toctree.get('titlesonly', False):
            titles_only = True
        if not includehidden and toctree.get('includehidden', False):
            includehidden = True

        # NOTE: previously, this was separate=True, but that leads to artificial
        # separation when two or more toctree entries form a logical unit, so
        # separating mode is no longer used -- it's kept here for history's sake
        tocentries = _entries_from_toctree(toctree, [], separate=False)
        if not tocentries:
            return None

        newnode = addnodes.compact_paragraph('', '')
        caption = toctree.attributes.get('caption')
        if caption:
            caption_node = nodes.caption(caption, '', *[nodes.Text(caption)])
            caption_node.line = toctree.line
            caption_node.source = toctree.source
            caption_node.rawsource = toctree['rawcaption']
            if hasattr(toctree, 'uid'):
                # move uid to caption_node to translate it
                caption_node.uid = toctree.uid
                del toctree.uid
            newnode += caption_node
        newnode.extend(tocentries)
        newnode['toctree'] = True

        # prune the tree to maxdepth, also set toc depth and current classes
        _toctree_add_classes(newnode, 1)
        self._toctree_prune(newnode, 1, prune and maxdepth or 0, collapse)

        if len(newnode[-1]) == 0:  # No titles found
            return None

        # set the target paths in the toctrees (they are not known at TOC
        # generation time)
        for refnode in newnode.traverse(nodes.reference):
            if not url_re.match(refnode['refuri']):
                refnode['refuri'] = builder.get_relative_uri(
                    docname, refnode['refuri']) + refnode['anchorname']
        return newnode
Example #60
0
    def run(self) -> List[nodes.Node]:
        """Con :class:`.TestDirective` it's some subclass, and append custom options in return node."""
        options = self.options

        ## Empty directive would add an empty literal line.
        #  (common, just to print a graphvar global from a previous doctest)
        #
        if not "\n".join(self.content).strip():
            options["hide"] = True

        self.name = self._con_name
        try:
            original_nodes = super().run()
        finally:
            self.name = self._real_name

        location = self.state_machine.get_source_and_line(self.lineno)

        img_format = self._decide_img_format(options)
        log.debug("decided `graph-format`: %r", img_format, location=location)
        if not img_format:
            # Bail out, probably unknown builder.
            return original_nodes

        node = graphtik_node(graphvar=options.get("graphvar"), img_format=img_format)
        node.source, node.line = location
        ## Decide a unique filename (and id).
        #
        name = options.get("name") or ""
        if name:
            name = nodes.fully_normalize_name(name)
        targetname = (
            f"graphtik-{self.env.docname}-{name}-{self.env.new_serialno('graphtik')}"
        )
        node["filename"] = targetname
        node += original_nodes

        figure = nodes.figure()
        figure.source, figure.line = location
        align = options.get("align")
        if align:
            align = f"align-{align}"
            figure["classes"].append(align)
        figure["classes"].extend(options.get("figclass", "").split())
        node += figure

        # TODO: emulate sphinx-processing for image width & height attrs.
        img_attrs = {k: v for k, v in options.items() if k in _img_options}
        image = dynaimage(**img_attrs)
        image.source, image.line = location
        image["classes"].extend(options.get("class", "").split())
        #  TODO: TCs for zooamble-SVGs options & configs.
        if "svg" in img_format:
            zoomable = options.get("zoomable")
            if zoomable is None:
                zoomable = self.config.graphtik_zoomable
                if zoomable:
                    image["classes"].append("graphtik-zoomable-svg")
        ## Assign a special *dataset* html-attribute
        #  with the content of a respective option.
        #
        zoomable_options = options.get("zoomable-opts")
        if zoomable_options:
            image["data-svg-zoom-opts"] = zoomable_options
        figure += image

        # A caption is needed if :name: is given, to create a permalink on it
        # (see sphinx/writers/html:HTMLTranslator.depart_caption()),
        # so get it here, not to overwrite it with :name: (if given below).`
        caption = options.get("caption")

        ## Prepare target,
        #
        if "name" in options:
            ##  adapted from: self.add_name()
            #
            name = options.pop("name")
            if not caption:
                caption = name
            figure["names"].append(targetname)
            ## adapted from: sphinx.domains.std.Target directive.
            #
            std = cast(StandardDomain, self.env.get_domain("std"))
            ## Suppress warning on duplicates (replaced with INFO).
            #  Duplicates occur either by include directives
            #  or because :noindex: in autoclass is ignored here.
            #
            objtype = "graphtik"
            if (objtype, name) in std.objects:
                docname = std.objects[objtype, name][0]
                log.info(
                    __("Skipping duplicate %s description of %s, other instance in %s"),
                    objtype,
                    name,
                    docname,
                    location=location,
                )
            else:
                std.note_object(objtype, name, targetname, figure)

        ## See sphinx.ext.graphviz:figure_wrapper(),
        #  and <sphinx.git>/tests/roots/test-add_enumerable_node/enumerable_node.py:MyFigure
        #
        if caption:
            inodes, messages = self.state.inline_text(caption, self.lineno)
            caption_node = nodes.caption(caption, "", *inodes)
            self.set_source_info(caption_node)
            caption_node += messages
            figure += caption_node

        return [node]