Example #1
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]
Example #2
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 #3
0
    def run(self):
        env = self.state.document.settings.env

        node = nodes.Element()
        node.document = self.state.document
        self.state.nested_parse(self.content, self.content_offset, node)

        images = []
        caption_and_legend = []
        for child in node:
            if isinstance(child, (nodes.target, nodes.image, nodes.figure)):
                images.append(child)
            else:
                caption_and_legend.append(child)

        items = []
        row_item_count = min(
            len(images), self.options.get('rowitems', DEFAULT_ROW_ITEM_COUNT))
        labels = self.options.get('labels', [])
        for img, label in itertools.zip_longest(images, labels):
            item_node = multifigure_item('', img)
            item_node['item-width'] = 100 // row_item_count
            if label is not None:
                item_node['label'] = label
            items.append(item_node)

        caption, legend = caption_and_legend[0], caption_and_legend[1:]

        resultnode = nodes.figure('', multifigure_content('', *items))
        resultnode['labels'] = labels
        resultnode.append(nodes.caption(caption.rawsource, '', *caption))
        if legend:
            resultnode.append(nodes.legend('', *legend))

        return [resultnode]
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):
        try:
            data = retrieve_glue_data(self.document, self.arguments[0])
        except RetrievalError as exc:
            return [glue_warning(str(exc), self.document, self.line)]
        render: Dict[str, Any] = {}
        for key in ("alt", "height", "width", "scale", "class"):
            if key in self.options:
                render.setdefault("image",
                                  {})[key.replace("classes",
                                                  "class")] = self.options[key]
        paste_nodes = render_variable_output(data,
                                             self.document,
                                             self.line,
                                             self.source,
                                             render=render)

        # note: most of this is copied directly from sphinx.Figure

        # create figure node
        figure_node = nodes.figure("", *paste_nodes)
        self.set_source_info(figure_node)

        # add attributes
        figwidth = self.options.pop("figwidth", None)
        figclasses = self.options.pop("figclass", None)
        align = self.options.pop("align", None)
        if figwidth is not None:
            figure_node["width"] = figwidth
        if figclasses:
            figure_node["classes"] += figclasses
        if align:
            figure_node["align"] = align

        # add target
        self.add_name(figure_node)

        # create the caption and legend
        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 = glue_warning(
                    "Figure caption must be a paragraph or empty comment.",
                    self.document,
                    self.lineno,
                )
                return [figure_node, error]
            if len(node) > 1:
                figure_node += nodes.legend("", *node[1:])

        return [figure_node]
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]
Example #7
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 #8
0
    def run(self):
        figwidth = self.options.pop('figwidth', None)
        figclasses = self.options.pop('figclass', ["right"])
        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 #9
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 #10
0
def figure(name, arguments, options, content, lineno, content_offset,
           block_text, state, state_machine):
    figwidth = options.get('figwidth')
    if figwidth:
        del options['figwidth']
    figclasses = options.get('figclass')
    if figclasses:
        del options['figclass']
    align = options.get('align')
    if align:
        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 #11
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 #12
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 #13
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 #14
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 = url2pathname(image_node["uri"])
             try:
                 img = PIL.Image.open(
                     imagepath.encode(sys.getfilesystemencoding()))
             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 #15
0
    def separate_legend_from_content(self):
        """
        I can't just nested_parse(self.content...) because I want
        to support any directive, even if it is not available locally.
        That bit of rst might just get parsed in an external service
        """
        content_offset = self.content_offset  # This is 0-based
        """:type content_offset: int"""
        content_block = self.content
        """:type content_block: docutils.statemachine.StringList"""
        state = self.state
        """:type state: docutils.parsers.rst.states.Body"""

        # we only use the first legend, don't overwrite. (limit=1)
        directives_list = list_directives_in_block(content_offset,
                                                   content_block,
                                                   type_limit=['legend'],
                                                   limit=1)

        if not directives_list:  # then there is no legend
            return None, content_block

        (offset_in_block, directive_offset, directive_name,
         match) = directives_list[0]

        legend_directive \
            = make_dummy_directive(directive_name, optional_arguments=0, final_argument_whitespace=False)

        block, indent, blank_finish \
            = content_block.get_indented(start=offset_in_block, first_indent=match.end())

        arguments, options, legend_content, legend_content_offset \
            = state.parse_directive_block(block, directive_offset, legend_directive, option_presets={})

        legend = nodes.legend(legend_content)
        state.nested_parse(legend_content, legend_content_offset, legend)

        last_offset = legend_content.offset(-1) - content_offset + 1
        if blank_finish:
            last_offset += 1

        visual_content = content_block[:]
        """copy of content_block that will have legend removed"""
        visual_content.disconnect()  # disconnect from content_block
        del visual_content[offset_in_block:last_offset]
        # legend_block = content_block[offset_in_block:last_offset]

        return legend, visual_content
    def run(self):
        self.options['width'] = '95%'
        label = self.options.get('label', None)

        (image_node, ) = Image.run(self)
        if isinstance(image_node, nodes.system_message):
            return [image_node]

        figure_node = nodes.figure('',
                                   image_node,
                                   ids=[label] if label is not None else [])
        figure_node['align'] = 'center'

        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_node = nodes.caption(first_node.rawsource, '',
                                             *first_node.children)
                caption_node.source = first_node.source
                caption_node.line = first_node.line
                figure_node += caption_node
            elif not (isinstance(first_node, nodes.comment)
                      and len(first_node) == 0):
                error = self.state_machine.reporter.error(
                    'Subfigure 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:
            rst = ViewList()
            rst.append(self.options['caption'], "", 0)

            parsed_node = nodes.section()
            parsed_node.document = self.state.document
            nested_parse_with_titles(self.state, rst, parsed_node)

            node = parsed_node[0]
            caption_node = nodes.caption(node.rawsource, '', *node.children)
            caption_node.source = node.source
            caption_node.line = node.line
            figure_node += caption_node

        return [figure_node]
    def separate_legend_from_content(self):
        """
        I can't just nested_parse(self.content...) because I want
        to support any directive, even if it is not available locally.
        That bit of rst might just get parsed in an external service
        """
        content_offset = self.content_offset  # This is 0-based
        """:type content_offset: int"""
        content_block = self.content
        """:type content_block: docutils.statemachine.StringList"""
        state = self.state
        """:type state: docutils.parsers.rst.states.Body"""

        # we only use the first legend, don't overwrite. (limit=1)
        directives_list = list_directives_in_block(content_offset, content_block, type_limit=['legend'],
                                                             limit=1)

        if not directives_list:  # then there is no legend
            return None, content_block

        (offset_in_block, directive_offset, directive_name, match) = directives_list[0]

        legend_directive \
            = make_dummy_directive(directive_name, optional_arguments=0, final_argument_whitespace=False)

        block, indent, blank_finish \
            = content_block.get_indented(start=offset_in_block, first_indent=match.end())

        arguments, options, legend_content, legend_content_offset \
            = state.parse_directive_block(block, directive_offset, legend_directive, option_presets={})

        legend = nodes.legend(legend_content)
        state.nested_parse(legend_content, legend_content_offset, legend)

        last_offset = legend_content.offset(-1) - content_offset + 1
        if blank_finish:
            last_offset += 1

        visual_content = content_block[:]
        """copy of content_block that will have legend removed"""
        visual_content.disconnect()  # disconnect from content_block
        del visual_content[offset_in_block:last_offset]
        # legend_block = content_block[offset_in_block:last_offset]

        return legend, visual_content
Example #18
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 #19
0
 def run(self):
     figwidth = self.options.pop("figwidth", None)
     figclasses = self.options.pop("figclass", None)
     align = self.options.pop("align", None)
     # On the Paste node we should add an attribute to specify that only image
     # type mimedata is allowed, then this would be used by
     # PasteNodesToDocutils -> CellOutputsToNodes to alter the render priority
     # and/or log warnings if that type of mimedata is not available
     (paste_node, ) = Paste.run(self)
     if isinstance(paste_node, nodes.system_message):
         return [paste_node]
     figure_node = nodes.figure("", paste_node)
     figure_node.line = paste_node.line
     figure_node.source = paste_node.source
     if figwidth is not None:
         figure_node["width"] = figwidth
     if figclasses:
         figure_node["classes"] += figclasses
     if align:
         figure_node["align"] = align
     self.add_name(figure_node)
     # note: this is copied directly from sphinx.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 #20
0
def figure(name, arguments, options, content, lineno,
           content_offset, block_text, state, state_machine):
    figwidth = options.setdefault('figwidth')
    figclass = options.setdefault('figclass')
    del options['figwidth']
    del options['figclass']
    (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:
            # PIL doesn't like Unicode paths:
            try:
                i = Image.open(str(image_node['uri']))
            except (IOError, UnicodeError):
                pass
            else:
                figure_node['width'] = i.size[0]
    elif figwidth is not None:
        figure_node['width'] = figwidth
    if figclass:
        figure_node.set_class(figclass)
    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 #21
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 #22
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 #23
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 #24
0
def create_figure_context(
    self: DocutilsNbRenderer | SphinxNbRenderer,
    figure_options: dict[str, Any] | None,
    line: int,
) -> Iterator:
    """Create a context manager, which optionally wraps new nodes in a figure node.

    A caption may also be added before or after the nodes.
    """
    if not isinstance(figure_options, dict):
        yield
        return

    # note: most of this is copied directly from sphinx.Figure

    # create figure node
    figure_node = nodes.figure()
    figure_node.line = line
    figure_node.source = self.document["source"]

    # add attributes to figure node
    if figure_options.get("classes"):  # TODO change to class?
        figure_node["classes"] += str(figure_options["classes"]).split()
    if figure_options.get("align") in ("center", "left", "right"):
        figure_node["align"] = figure_options["align"]

    # add target name
    if figure_options.get("name"):
        name = nodes.fully_normalize_name(str(figure_options.get("name")))
        figure_node["names"].append(name)
        self.document.note_explicit_target(figure_node, figure_node)

    # create caption node
    caption = None
    if figure_options.get("caption", ""):
        node = nodes.Element()  # anonymous container for parsing
        with self.current_node_context(node):
            self.nested_render_text(str(figure_options["caption"]), line)
        first_node = node.children[0]
        legend_nodes = node.children[1:]
        if isinstance(first_node, nodes.paragraph):
            caption = nodes.caption(first_node.rawsource, "", *first_node.children)
            caption.source = self.document["source"]
            caption.line = line
        elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0):
            self.create_warning(
                "Figure caption must be a paragraph or empty comment.",
                line=line,
                wtype=DEFAULT_LOG_TYPE,
                subtype="fig_caption",
            )

    self.current_node.append(figure_node)
    old_current_node = self.current_node
    self.current_node = figure_node

    if caption and figure_options.get("caption_before", False):
        figure_node.append(caption)
        if legend_nodes:
            figure_node += nodes.legend("", *legend_nodes)

    yield

    if caption and not figure_options.get("caption_before", False):
        figure_node.append(caption)
        if legend_nodes:
            figure_node += nodes.legend("", *legend_nodes)

    self.current_node = old_current_node