Source code for romnn_sphinx_press_theme

from os import path

from docutils import nodes
from sphinx.environment.collectors import EnvironmentCollector
from sphinx import addnodes
from sphinx.util.osutil import relative_uri

__version__ = (0, 4, 0)


class SimpleTocTreeCollector(EnvironmentCollector):
    """A TocTree collector that saves toctrees in a simple dict.

    sphinx.environment.collectors.toctree.TocTreeCollector saves
    TocTree as docutils.nodes which are hard to work with...

    Executed once per document/page, at sphinx's "read" phase.

    Saved data example:
    >>> {
    >>>  'sections': [{'title': 'Demo', 'href': '#demo'}],
    >>>  'toctrees': [<toctree: >]
    >>> }
    """

    def enable(self, app):
        super().enable(app)
        # env is populated from cache, if not cache create/initalize attibute
        if not hasattr(app.env, "toc_dict"):
            app.env.toc_dict = {}

    def clear_doc(self, app, env, docname):
        env.toc_dict.pop(docname, None)

    def merge_other(self, app, env, docnames, other):
        for docname in docnames:
            env.toc_dict[docname] = other.toc_dict[docname]

    def process_doc(self, app, doctree):
        docname = app.env.docname  # sphinx mutates this, ouch!!!

        # print(f"================ Collector\n{docname}\n============\n")
        # get 1 level document toc (sections)
        section_nodes = [s for s in doctree if isinstance(s, nodes.section)]
        # if first level is a single section,
        # ignore it and use second level of sections
        if len(section_nodes) == 1:
            section2_nodes = [
                s for s in section_nodes[0] if isinstance(s, nodes.section)
            ]
            if section2_nodes:  # do not replace with level-2 sections if None
                section_nodes = section2_nodes

        sections = []
        for node in section_nodes:
            sections.append(
                {"title": node[0].astext(), "href": "#{}".format(node["ids"][0]),}
            )

        app.env.toc_dict[docname] = {
            "sections": sections,
            "toctrees": doctree.traverse(addnodes.toctree),
        }


[docs]def google_docstring_example(param1: int, param2: str) -> bool: """Example function with types documented in the docstring. `PEP 484`_ type annotations are supported. If attribute, parameter, and return types are annotated according to `PEP 484`_, they do not need to be included in the docstring: Args: param1: The first parameter. param2: The second parameter. Returns: bool: The return value. True for success, False otherwise. .. _PEP 484: https://www.python.org/dev/peps/pep-0484/ """ return param1 < 0 and param2 == "Hello World"
[docs]def add_toctree_data(app, pagename, templatename, context, doctree): """Create toctree_data, used to build sidebar navigation :param pagename: The name of the page :type pagename: str :param templatename: The name of the templatename :type templatename: str :param context: The context :type context: dict :param doctree: A doctree :type doctree: docutils.nodes.document Add to `toctree_data` to `context` that will be available on templates. Although data is "global", it is called once per page because current page is "highlighted", and some part of TOC might be collapsed. :return: None """ # print(f"---------- Context\n{pagename}\n-------------\n") # start from master_doc master = app.env.get_doctree(app.env.config.master_doc) # each toctree will create navigation section res = [] # list of top level toctrees in master_doc for tree in master.traverse(addnodes.toctree): # special case for toctree that includes a single item # that contains a nested toctree. # In this case, just use the referenced toctree directly title = tree["caption"] if len(tree["entries"]) == 1: entry_docname = tree["entries"][0][1] toctrees = app.env.toc_dict[entry_docname]["toctrees"] if toctrees: # FIXME assert ( len(toctrees) == 1 ), "Press: Not supported more then one toctree on nested toctree" tree = toctrees[0] current0 = False # same page might have multiple tocs # add toc tree items, expand one more level if toctree is current page entries = [] for _title, name in tree["entries"]: if not _title: _title = app.env.titles[name].astext() current1 = pagename == name children = [] if current1: current0 = True # if current, add another level children = app.env.toc_dict[name]["sections"] # add page_toc for current page entries.append( { "name": name, "title": _title, "current": current1, "children": children, } ) toc_docname = tree["parent"] # docname where this toc appears # Anchor element is the section containing the toc, # as the toc itself does not contain ID. anchor_id = "" # tree.parent is the parent docutils node. # First parent is "compound" node toctree-wrapper, # second parent is the section containing the toctree toc_section = tree.parent.parent if toc_section["ids"]: # no id means toc actually not in a section # TODO: should we be strict about toc being inside a section anchor_id = toc_section["ids"][0] if not title: title = toc_section["names"][0] # sphinx `pathto` does not play nice with anchors when # `allow_sharp_as_current_path` is True baseuri = app.builder.get_target_uri(pagename).rsplit("#", 1)[0] toc_uri = app.builder.get_target_uri(toc_docname).rsplit("#", 1)[0] toc_href = "{}#{}".format(relative_uri(baseuri, toc_uri), anchor_id) res.append( { "docname": toc_docname, "href": toc_href, "title": title, "current": current0, "entries": entries, } ) context["toctree_data"] = res
def setup(app): app.add_env_collector(SimpleTocTreeCollector) app.connect("html-page-context", add_toctree_data) app.add_html_theme("press", path.abspath(path.dirname(__file__)))