Beispiel #1
0
def page_role(_role: str,
              rawtext: str,
              text: str,
              lineno: int,
              inliner: Inliner,
              options: dict = None,
              _content: dict = None):
    if options is None:
        options = {}

    set_classes(options)

    if "/" in text:
        parts = [escape(x) for x in text.rsplit("/", 1)]
    else:
        msg = inliner.reporter.error(
            "Page specification must be in the form <page_slug>/<text>",
            line=lineno)
        prb = inliner.problematic(text, rawtext, msg)

        return [prb], [msg]

    try:
        url = url_for("wiki.page", page=parts[0])
        name = parts[1]

        html = f"""<a href="{url}">{name}</a>"""

        node = nodes.raw(html, html, format="html", **options)
        return [node], []
    except Exception as e:
        msg = inliner.reporter.error(str(e), line=lineno)
        prb = inliner.problematic(text, rawtext, msg)

        return [prb], [msg]
Beispiel #2
0
    def _parse(self, line):
        """
        Parses a single line/string for inline rst statements, like strong, emphasis, literal, ...

        :param line: string to parse
        :return: nodes
        """
        inline_parser = Inliner()
        inline_parser.init_customizations(self.doc_settings)
        result, message = inline_parser.parse(line, 0, self.doc_memo, self.dummy_doc)
        if message:
            raise SphinxNeedLayoutException(message)
        return result
Beispiel #3
0
def sphinx_state(local_app):
    """
    Fixture which will provide a sphinx state for use in testing sphinx
    directives.

    Yields:
        :class:`docutils.parsers.rst.states.State`: A state for use in testing
            directive functionality.
    """
    # Get the environment and decorate it with what sphinx may need for the
    # parsing.
    env = local_app.env
    env.temp_data["docname"] = "test"  # A fake document name

    # Create a document and inliner object, to be perfectly honest not sure
    # exactly what these are or do, but needed to get the directive to run.
    document = new_document(__file__)
    document.settings.pep_references = 1
    document.settings.rfc_references = 1
    document.settings.env = env
    document.settings.tab_width = 4
    inliner = Inliner()
    inliner.init_customizations(document.settings)

    # Create a state machine so that we can get a state to pass back.
    statemachine = RSTStateMachine(state_classes=state_classes, initial_state="Body")
    statemachine.input_lines = StringList([""] * 40)
    state = statemachine.get_state()
    state.document = document
    state.memo = Struct(
        inliner=inliner,
        language=en,
        title_styles=[],
        reporter=document.reporter,
        document=document,
        section_level=0,
        section_bubble_up_kludge=False,
    )

    state.memo.reporter.get_source_and_line = statemachine.get_source_and_line

    # The environemnt isn't normally available on the state in sphinx, but it's
    # done here to make testing easier.
    state.env = env

    # Sphinx monkeypatches docutils when run. This is how it get's
    # monkeypatched so that the python directives and roles can be found
    with sphinx_domains(env):

        # Provide the state back to the test.
        yield state
Beispiel #4
0
def icon_role(_role: str,
              rawtext: str,
              text: str,
              lineno: int,
              inliner: Inliner,
              options: dict = None,
              _content: dict = None):
    if options is None:
        options = {}

    set_classes(options)

    if "/" in text:
        parts = [escape(x) for x in text.split("/")]
    else:
        msg = inliner.reporter.error(
            "Icon specification must be in the form <type>/<name>",
            line=lineno)
        prb = inliner.problematic(text, rawtext, msg)

        return [prb], [msg]

    if len(parts) != 2:
        msg = inliner.reporter.error(
            "Icon specification must be in the form <type>/<name>",
            line=lineno)
        prb = inliner.problematic(text, rawtext, msg)

        return [prb], [msg]
    else:
        if parts[0] == "light":
            weight = "fal"
        elif parts[0] == "regular":
            weight = "far"
        elif parts[0] == "solid":
            weight = "fas"
        elif parts[0] == "branding":
            weight = "fab"
        else:
            msg = inliner.reporter.error(
                "Icon type must be one of light, regular, solid or branding",
                line=lineno)
            prb = inliner.problematic(text, rawtext, msg)

            return [prb], [msg]

        html = f"""<i class="uk-icon fa-fw {weight} fa-{parts[1]}"></i>"""

        node = nodes.raw(html, html, format="html", **options)
        return [node], []
Beispiel #5
0
 def parse_message_to_doctree(po, message):
     inliner = Inliner()
     settings = AttrDict({
         'character_level_inline_markup': False,
         'pep_references': None,
         'rfc_references': None
     })
     inliner.init_customizations(settings)
     document = new_document(None)
     document.settings.syntax_highlight = 'long'
     stream = StringIO()
     reporter = Reporter(po.file,
                         report_level=Reporter.WARNING_LEVEL,
                         halt_level=Reporter.SEVERE_LEVEL,
                         stream=stream)
     memo = Struct(document=document,
                   reporter=reporter,
                   language=None,
                   inliner=inliner)
     doctree, errors = inliner.parse(message, po.current_index, memo, None)
     warning = stream.getvalue()
     return doctree, errors, warning
def fcicon_role(name: str,
                rawtext: str,
                text: str,
                lineno: int,
                inliner: Inliner,
                options: dict = {},
                content: List[str] = []):
    """FreeCAD Icon role function.

    Returns 2 part tuple containing list of nodes to insert into the
    document and a list of system messages.  Both are allowed to be
    empty.

    For additional information on role functions, see:
        * https://docutils.readthedocs.io/en/sphinx-docs/howto/rst-roles.html
        * https://doughellmann.com/blog/2010/05/09/defining-custom-roles-in-sphinx/

    :param name: The role name used in the document.
    :param rawtext: The entire markup snippet, with role.
    :param text: The text marked with the role.
    :param lineno: The line number where rawtext appears in the input.
    :param inliner: The inliner instance that called us.
    :param options: Directive options for customization.
    :param content: The directive content for customization.
    """
    try:
        pattern = re.compile('([\w\s]+) \((sm|md|lg)\) \<(.*\.\w+)\>')
        result = pattern.search(text)
        if not result or len(result.groups()) != 3:
            raise ValueError
        alt, size, filename = result.groups()
    except ValueError:
        msg = inliner.reporter.error(
            'FreeCAD Icon must include alt, size (sm, md, or lg), and filename (e.g. :fcicon:`My Icon Alt (md) <MyIcon.svg>`); '
            '"%s" is invalid.' % text, line=lineno)
        prb = inliner.problematic(rawtext, rawtext, msg)
        return [prb], [msg]
    app = inliner.document.settings.env.app
    try:
        freecad_icon_directory = app.config.freecad_icon_directory
        if not freecad_icon_directory:
            raise AttributeError
    except AttributeError:
        raise ValueError(
            'freecad_icon_directory configuration value is not set')
    image = make_image_node(freecad_icon_directory, alt, size, filename)
    return [image], []
Beispiel #7
0
def nxt_hint_role_fn(_: str, rawtext: str, text: str, lineno: int, inliner:
        Inliner, *args: Any) -> Tuple[List[Node], List[system_message]]:
    """The nxt_hint role handler for inline text outside code blocks."""

    node = nxt_hint()
    groups = re.search(NXT_HINT_REGEX,
                       rawtext.replace('\n', ' ').replace('\r', ''))

    try:
        node.term, node.tip = groups.group(1), groups.group(2)
    except IndexError:
        msg = inliner.reporter.error(
            f'Inline term "{text}" is invalid.', line=lineno)
        prb = inliner.problematic(rawtext, rawtext, msg)
        return [prb], [msg]

    return [node], []
Beispiel #8
0
 def rolefunc(
     role_name: str,  # e.g. "role"
     rawtext: str,  # e.g. ":role:`text`"
     text: str,  # e.g. "text"
     lineno: int,
     inliner: Inliner,
     options: Dict[str, Any] = None,
     content: List[str] = None,
 ) -> Tuple[List[Node], List[str]]:
     """
     Attempt to implemented substitutions inside inline markup.
     This is not directly supported:
         https://sourceforge.net/p/docutils/feature-requests/53/
     Role functions: see
         http://docutils.sourceforge.net/docs/howto/rst-roles.html
     See also:
         https://github.com/sphinx-doc/sphinx/issues/2173
     Returns the tuple (nodes, messages).
     Search docutils for "role_fn" to see how this function will be called.
     """
     options = options or {}  # type: Dict[str, Any]
     content = content or []  # type: List[str]
     log.debug("rolefunc() called with role_name={rn!r}, rawtext={rt!r}, "
               "text={t!r}, lineno={ln}, inliner={i!r}, "
               "options={o!r}, content={c!r}".format(
                   rn=role_name,
                   rt=rawtext,
                   t=text,
                   ln=lineno,
                   i=inliner,
                   o=options,
                   c=content,
               ))
     parsed_nodes, parsed_msgs = inliner.parse(
         text=text, lineno=0, memo=inliner,
         parent=None)  # type: Tuple[List[Node], List[str]]
     top_node = nodes.inline(  # was nodes.inline
         text="", refid=css_class, **options)  # type: Element
     top_node["classes"].append(
         css_class)  # see deprecated Element.set_class  # noqa
     top_node += parsed_nodes  # adds children to this_node; see Element
     return [top_node], []
Beispiel #9
0
def _role_annot(
    name: str,
    rawtext: str,
    text: str,
    lineno: int,
    inliner: Inliner,
    options: Dict[str, Any] = {},
    content: Sequence[str] = (),
    # *,  # https://github.com/ambv/black/issues/613
    additional_classes: Iterable[str] = (),
) -> Tuple[List[Node], List[SystemMessage]]:
    options = options.copy()
    set_classes(options)
    if additional_classes:
        options["classes"] = options.get("classes", []).copy()
        options["classes"].extend(additional_classes)
    memo = Struct(document=inliner.document,
                  reporter=inliner.reporter,
                  language=inliner.language)
    node = nodes.inline(unescape(rawtext), "", **options)
    children, messages = inliner.parse(_unescape(text), lineno, memo, node)
    node.extend(children)
    return [node], messages
Beispiel #10
0
    def reset(self, document, parent, level):
        """Reset the state of state machine.

        After reset, self and self.state can be used to
        passed to docutils.parsers.rst.Directive.run

        Parameters
        ----------
        document: docutils document
            Current document of the node.
        parent: parent node
            Parent node that will be used to interpret role and directives.
        level: int
            Current section level.
        """
        self.language = languages.get_language(
            document.settings.language_code)
        # setup memo
        self.memo.document = document
        self.memo.reporter = document.reporter
        self.memo.language = self.language
        self.memo.section_level = level
        # setup inliner
        if self.memo.inliner is None:
            self.memo.inliner = Inliner()
            self.memo.inliner.init_customizations(document.settings)
        inliner = self.memo.inliner
        inliner.reporter = document.reporter
        inliner.document = document
        inliner.language = self.language
        inliner.parent = parent
        # setup self
        self.document = document
        self.reporter = self.memo.reporter
        self.node = parent
        self.state.runtime_init()
        self.input_lines = document['source']
Beispiel #11
0
def indexmarkup_role(
        typ: str,
        rawtext: str,
        text: str,
        lineno: int,
        inliner: Inliner,
        options: Dict = {},
        content: List[str] = []) -> Tuple[List[Node], List[system_message]]:
    """Role for PEP/RFC references that generate an index entry."""
    warnings.warn(
        'indexmarkup_role() is deprecated.  Please use PEP or RFC class instead.',
        RemovedInSphinx40Warning,
        stacklevel=2)
    env = inliner.document.settings.env
    if not typ:
        assert env.temp_data['default_role']
        typ = env.temp_data['default_role'].lower()
    else:
        typ = typ.lower()

    has_explicit_title, title, target = split_explicit_title(text)
    title = utils.unescape(title)
    target = utils.unescape(target)
    targetid = 'index-%s' % env.new_serialno('index')
    indexnode = addnodes.index()
    targetnode = nodes.target('', '', ids=[targetid])
    inliner.document.note_explicit_target(targetnode)
    if typ == 'pep':
        indexnode['entries'] = [
            ('single', _('Python Enhancement Proposals; PEP %s') % target,
             targetid, '', None)
        ]
        anchor = ''
        anchorindex = target.find('#')
        if anchorindex > 0:
            target, anchor = target[:anchorindex], target[anchorindex:]
        if not has_explicit_title:
            title = "PEP " + utils.unescape(title)
        try:
            pepnum = int(target)
        except ValueError:
            msg = inliner.reporter.error('invalid PEP number %s' % target,
                                         line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
        ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum
        sn = nodes.strong(title, title)
        rn = nodes.reference('',
                             '',
                             internal=False,
                             refuri=ref + anchor,
                             classes=[typ])
        rn += sn
        return [indexnode, targetnode, rn], []
    elif typ == 'rfc':
        indexnode['entries'] = [('single', 'RFC; RFC %s' % target, targetid,
                                 '', None)]
        anchor = ''
        anchorindex = target.find('#')
        if anchorindex > 0:
            target, anchor = target[:anchorindex], target[anchorindex:]
        if not has_explicit_title:
            title = "RFC " + utils.unescape(title)
        try:
            rfcnum = int(target)
        except ValueError:
            msg = inliner.reporter.error('invalid RFC number %s' % target,
                                         line=lineno)
            prb = inliner.problematic(rawtext, rawtext, msg)
            return [prb], [msg]
        ref = inliner.document.settings.rfc_base_url + inliner.rfc_url % rfcnum
        sn = nodes.strong(title, title)
        rn = nodes.reference('',
                             '',
                             internal=False,
                             refuri=ref + anchor,
                             classes=[typ])
        rn += sn
        return [indexnode, targetnode, rn], []
    else:
        raise ValueError('unknown role type: %s' % typ)