Ejemplo n.º 1
0
def register_spec_with_docutils(spec: specparser.Spec,
                                default_domain: Optional[str]) -> Registry:
    """Register all of the definitions in the spec with docutils, overwriting the previous
       call to this function. This function should only be called once in the
       process lifecycle."""

    from .legacy_guides import LegacyGuideDirective, LegacyGuideIndexDirective

    SPECIAL_DIRECTIVE_HANDLERS["guide"] = LegacyGuideDirective
    SPECIAL_DIRECTIVE_HANDLERS["guide-index"] = LegacyGuideIndexDirective

    builder = Registry.Builder()
    directives = list(spec.directive.items())
    roles = list(spec.role.items())

    # Define rstobjects
    for name, rst_object in spec.rstobject.items():
        directive = rst_object.create_directive()
        directives.append((name, directive))
        role = rst_object.create_role()
        roles.append((name, role))

    for name, directive in directives:
        # Skip abstract base directives
        if name.startswith("_"):
            continue

        options: Dict[str, object] = {
            option_name: spec.get_validator(option)
            for option_name, option in directive.options.items()
        }

        base_class: Any = BaseDocutilsDirective

        # Tabs have special handling because of the need to support legacy syntax
        if name == "tabs":
            base_class = BaseTabsDirective
        elif name in SPECIAL_DIRECTIVE_HANDLERS:
            base_class = SPECIAL_DIRECTIVE_HANDLERS[name]

        DocutilsDirective = make_docutils_directive_handler(
            directive, base_class, name, options)
        builder.add_directive(name, DocutilsDirective)

    # reference tabs directive declaration as first step in registering tabs-* with docutils
    tabs_directive = spec.directive["tabs"]

    # Define tabsets
    for name in spec.tabs:
        tabs_base_class: Any = BaseTabsDirective
        tabs_name = "tabs-" + name

        # copy and modify the tabs directive to update its name to match the deprecated tabs-* naming convention
        modified_tabs_directive = dataclasses.replace(tabs_directive,
                                                      name=tabs_name)

        tabs_options: Dict[str, object] = {
            option_name: spec.get_validator(option)
            for option_name, option in tabs_directive.options.items()
        }

        DocutilsDirective = make_docutils_directive_handler(
            modified_tabs_directive, tabs_base_class, "tabs", tabs_options)

        builder.add_directive(tabs_name, DocutilsDirective)

    # Docutils builtins
    builder.add_directive("unicode",
                          docutils.parsers.rst.directives.misc.Unicode)
    builder.add_directive("replace",
                          docutils.parsers.rst.directives.misc.Replace)

    # Define roles
    builder.add_role("", handle_role_null)
    for name, role_spec in roles:
        handler: Optional[RoleHandlerType] = None
        domain = role_spec.domain or ""
        if not role_spec.type or role_spec.type == specparser.PrimitiveRoleType.text:
            handler = TextRoleHandler(domain)
        elif isinstance(role_spec.type, specparser.LinkRoleType):
            handler = LinkRoleHandler(role_spec.type.link,
                                      role_spec.type.format)
        elif isinstance(role_spec.type, specparser.RefRoleType):
            handler = RefRoleHandler(
                role_spec.type.domain or domain,
                role_spec.type.name,
                role_spec.type.tag,
                role_spec.rstobject.type
                if role_spec.rstobject else specparser.TargetType.plain,
                role_spec.type.format,
            )
        elif role_spec.type == specparser.PrimitiveRoleType.explicit_title:
            handler = ExplicitTitleRoleHandler(domain)

        if not handler:
            raise ValueError('Unknown role type "{}"'.format(role_spec.type))

        builder.add_role(name, handler)

    return builder.build(default_domain)
Ejemplo n.º 2
0
def register_spec_with_docutils(spec: specparser.Spec) -> None:
    """Register all of the definitions in the spec with docutils."""
    from .legacy_guides import LegacyGuideDirective, LegacyGuideIndexDirective

    directives = list(spec.directive.items())
    roles = list(spec.role.items())

    # Define rstobjects
    for name, rst_object in spec.rstobject.items():
        directive = rst_object.create_directive()
        role = rst_object.create_role()
        directives.append((name, directive))
        roles.append((name, role))

    for name, directive in directives:
        # Skip abstract base directives
        if name.startswith("_"):
            continue

        # Tabs have special handling because of the need to support legacy syntax
        if name == "tabs" or name.startswith("tabs-"):
            docutils.parsers.rst.directives.register_directive(name, TabsDirective)
            continue

        options: Dict[str, object] = {
            option_name: spec.get_validator(option)
            for option_name, option in directive.options.items()
        }

        class DocutilsDirective(BaseDocutilsDirective):
            has_content = bool(directive.content_type)
            optional_arguments = 1 if directive.argument_type else 0
            final_argument_whitespace = True
            option_spec = options

        new_name = (
            "".join(e for e in name.title() if e.isalnum() or e == "_") + "Directive"
        )
        DocutilsDirective.__name__ = DocutilsDirective.__qualname__ = new_name
        docutils.parsers.rst.directives.register_directive(name, DocutilsDirective)

    # Some directives currently have special handling
    docutils.parsers.rst.directives.register_directive("code-block", CodeDirective)
    docutils.parsers.rst.directives.register_directive("code", CodeDirective)
    docutils.parsers.rst.directives.register_directive("sourcecode", CodeDirective)
    docutils.parsers.rst.directives.register_directive("deprecated", VersionDirective)
    docutils.parsers.rst.directives.register_directive("versionadded", VersionDirective)
    docutils.parsers.rst.directives.register_directive(
        "versionchanged", VersionDirective
    )
    docutils.parsers.rst.directives.register_directive("guide", LegacyGuideDirective)
    docutils.parsers.rst.directives.register_directive("card-group", CardGroupDirective)
    docutils.parsers.rst.directives.register_directive(
        "guide-index", LegacyGuideIndexDirective
    )
    docutils.parsers.rst.directives.register_directive("toctree", TocTreeDirective)

    # Define roles
    for name, role_spec in roles:
        handler = None
        if not role_spec.type or role_spec.type == specparser.PrimitiveRoleType.text:
            handler = handle_role_text
        elif isinstance(role_spec.type, specparser.LinkRoleType):
            handler = LinkRoleHandler(role_spec.type.link)
        elif role_spec.type == specparser.PrimitiveRoleType.explicit_title:
            handler = handle_role_explicit_title

        if not handler:
            raise ValueError('Unknown role type "{}"'.format(role_spec.type))

        docutils.parsers.rst.roles.register_local_role(name, handler)