def run(self): doc = self.state.document env = doc.settings.env if 'layout' in self.options: layout = self.options['layout'] else: layout = env.config.demo_layout if not self.layout_re.match(layout): return [ doc.reporter.error("invalid layout specifier: %s" % layout, lineno=self.lineno) ] order = [] for block in layout.split(','): block = block.strip() is_hidden = block[0] == '-' block = block.lstrip('+-') order.append((block, is_hidden)) wrapper = nodes.compound(classes=['demo-wrapper']) data = "\n".join(self.content) for block, is_hidden in order: if block == 'demo': header = nodes.paragraph(classes=['demo-header']) header += nodes.Text("Demo") if is_hidden: header['classes'].append('demo-hide') demo = nodes.raw(data, data, format='html', classes=['demo-area']) html_wrapper = addnodes.only(expr='html') html_wrapper += header html_wrapper += demo wrapper += html_wrapper elif block == 'source': header = nodes.paragraph(classes=['demo-header']) header += nodes.Text("Source") if is_hidden: header['classes'].append('demo-hide') source = nodes.literal_block(data, data, language='html', classes=['demo-source']) html_wrapper = addnodes.only(expr='html') html_wrapper += header wrapper += html_wrapper wrapper += source else: assert False, block return [wrapper]
def doctree_read(app, doctree): # Add viewcode nodes for code elements referenced in the document. env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # handle desc (description) nodes (module contents) for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if not _update_tags(env, modname, fullname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') # build up an xref and add it to the desc node onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref('', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode # handle index nodes (modules themselves) for objnode in doctree.traverse(addnodes.index): # extract module name by de-munging the "target" field index_target = objnode['entries'][0][2] if not index_target.startswith('module-'): continue modname = index_target.replace('module-', '', 1) _update_tags(env, modname) pagename = '_modules/' + modname.replace('.', '/') # build up an xref and add it in a new paragraph after the index node xref = addnodes.pending_xref('', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid='', refdoc=env.docname) xref += nodes.inline('', _('[source]'), classes=['viewcode-link']) idx = objnode.parent.index(objnode) + 1 objnode.parent.insert(idx, nodes.paragraph('', '', xref))
def run(self): from docutils import nodes from sphinx import addnodes from sphinx.util.nodes import set_source_info node = addnodes.only() node.document = self.state.document set_source_info(self, node) node['expr'] = self.arguments[0] # hack around title style bookkeeping surrounding_title_styles = self.state.memo.title_styles surrounding_section_level = self.state.memo.section_level self.state.memo.title_styles = [] self.state.memo.section_level = 0 try: result = self.state.nested_parse(self.content, 0, node, match_titles=1) depth = len(surrounding_title_styles) if self.state.memo.title_styles: style = self.state.memo.title_styles[0] if style in surrounding_title_styles: depth = surrounding_title_styles.index(style) parent = self.state.parent for i in range(len(surrounding_title_styles) - depth): if parent.parent: parent = parent.parent parent.append(node) finally: self.state.memo.title_styles = surrounding_title_styles self.state.memo.section_level = surrounding_section_level return []
def run(self): sponsor_link = self.env.config.sponsor_link organization = self.env.config.organization admonition_node = nodes.admonition(classes=["admonition-sponsor"]) admonition_node += nodes.title(text="Sponsor") # Parse admonition body contents. # Needs to use a container here instead of list otherwise exception. node_list = nodes.container() self.state.nested_parse(self.content, self.content_offset, node_list) admonition_node += node_list.children # Add sponsor button for HTML and fallback for PDF. html = f"<iframe src=\"{sponsor_link}/button\" title=\"Sponsor {organization}\" height=\"35\" width=\"116\" style=\"border: 0; display: block;\"></iframe>" html_node = nodes.raw(text=html, format="html") only_pdf = addnodes.only(expr="latex") only_pdf_paragraph = nodes.inline() self.state.nested_parse( nodes.inline(text=f":link:`Sponsor Us <{sponsor_link}?o=esb>`"), 0, only_pdf_paragraph) only_pdf += only_pdf_paragraph admonition_node += html_node admonition_node += only_pdf return [admonition_node]
def handle_options(self, sig, signode): if not self.make_section_and_title and self.options.get('title'): self.state_machine.reporter.warning( "A ':title:' option was given for Protobuf object '%s' in document '%s', but this was ignored since " "the Protobuf type '%s' is configured not to render any title." % (sig, self.env.docname, self.objtype), line=self.lineno) # Source links file_path = self.options.get('src_file_path', '').strip() if file_path: base_url = self.options.get('src_base_url', '').strip( ) or self.env.config.protobufdomain_sourcelinks_base_url # TODO via config/template to allow custom line range anchors (e.g. '#1' for Gerrit or '#L1-L7' for GitHub). linerange = self.options.get('src_linerange', '').strip() linerange_anchor = "#" + linerange.split("-", 1)[0] url = base_url + file_path + linerange_anchor # class and title looks as with 'viewcode' extension. Rather than extending that extension with support for # this domain, create our own link for now... pnode = nodes.reference('', '', internal=False, refuri=url, reftype='viewcode', refdomain='std', refexplicit=False) pnode['classes'].append('viewcode-link') pnode['classes'].append('headerlink') pnode += nodes.inline('', 'source') srclink_node = addnodes.only(expr='html') srclink_node += pnode signode += srclink_node
def run(self): from docutils import nodes from sphinx import addnodes from sphinx.util.nodes import set_source_info node = addnodes.only() node.document = self.state.document set_source_info(self, node) node['expr'] = self.arguments[0] # hack around title style bookkeeping surrounding_title_styles = self.state.memo.title_styles surrounding_section_level = self.state.memo.section_level self.state.memo.title_styles = [] self.state.memo.section_level = 0 try: result = self.state.nested_parse(self.content, 0, node, match_titles=1) depth = len(surrounding_title_styles) if self.state.memo.title_styles: style = self.state.memo.title_styles[0] if style in surrounding_title_styles: depth = surrounding_title_styles.index(style) parent = self.state.parent for i in xrange(len(surrounding_title_styles) - depth): if parent.parent: parent = parent.parent parent.append(node) finally: self.state.memo.title_styles = surrounding_title_styles self.state.memo.section_level = surrounding_section_level return []
def run(self): node = addnodes.only() node.document = self.state.document node.line = self.lineno node['expr'] = self.arguments[0] self.state.nested_parse(self.content, self.content_offset, node, match_titles=1) return [node]
def run(self): doc = self.state.document env = doc.settings.env if 'layout' in self.options: layout = self.options['layout'] else: layout = env.config.demo_layout if not self.layout_re.match(layout): return [doc.reporter.error("invalid layout specifier: %s" % layout, lineno=self.lineno)] order = [] for block in layout.split(','): block = block.strip() is_hidden = block[0] == '-' block = block.lstrip('+-') order.append((block, is_hidden)) wrapper = nodes.compound(classes=['demo-wrapper']) data = "\n".join(self.content) for block, is_hidden in order: if block == 'demo': header = nodes.paragraph(classes=['demo-header']) header += nodes.Text("Demo") if is_hidden: header['classes'].append('demo-hide') demo = nodes.raw(data, data, format='html', classes=['demo-area']) html_wrapper = addnodes.only(expr='html') html_wrapper += header html_wrapper += demo wrapper += html_wrapper elif block == 'source': header = nodes.paragraph(classes=['demo-header']) header += nodes.Text("Source") if is_hidden: header['classes'].append('demo-hide') source = nodes.literal_block(data, data, language='html', classes=['demo-source']) html_wrapper = addnodes.only(expr='html') html_wrapper += header wrapper += html_wrapper wrapper += source else: assert False, block return [wrapper]
def build_result_table(product, cut): meta = product.get('meta') data = product.get('data') if 'domain' not in meta: return build = get_build_by_domain(meta['domain']) if not build.span: return table_node = nodes.table() measures = build.measures(data, cut) group_node = nodes.tgroup(cols=build.span) table_node += group_node for measure in measures: colspec_node = nodes.colspec(colwidth=measure) group_node += colspec_node head_node = nodes.thead() group_node += head_node head_rows = build.head(build.head_height()) if head_rows: for row in head_rows: row_node = nodes.row() head_node += row_node for cell, rowspan, colspan, classes in row: entry_node = nodes.entry(classes=classes) if rowspan > 1: entry_node['morerows'] = rowspan - 1 if colspan > 1: entry_node['morecols'] = colspan - 1 row_node += entry_node para_node = nodes.paragraph() entry_node += para_node text_node = nodes.Text(cell) para_node += text_node body_node = nodes.tbody() group_node += body_node body_rows = build.body(build.body_height(data, cut), data, cut) if body_rows: for row in body_rows: row_node = nodes.row() body_node += row_node for cell, rowspan, colspan, classes in row: entry_node = nodes.entry(classes=classes) if rowspan > 1: entry_node['morerows'] = rowspan - 1 if colspan > 1: entry_node['morecols'] = colspan - 1 row_node += entry_node para_node = nodes.paragraph() entry_node += para_node text_node = nodes.Text(cell) if any(cls in classes for cls in ['htsql-empty-val', 'htsql-null-val', 'htsql-cut']): only_node = addnodes.only(expr='latex or text') only_node += text_node para_node += only_node else: para_node += text_node return table_node
def doctree_read(app, doctree): env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} def has_tag(modname, fullname, docname, refname): entry = env._viewcode_modules.get(modname, None) try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False return if not isinstance(analyzer.code, text_type): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code if entry is None or entry[0] != code: analyzer.find_tags() entry = code, analyzer.tags, {}, refname env._viewcode_modules[modname] = entry elif entry is False: return _, tags, used, _ = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_import: modname = _get_full_modname(app, modname, fullname) if not modname: continue fullname = signode.get('fullname') if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def doctree_read(app, doctree): env = app.builder.env if not hasattr(env, "_viewcode_modules"): env._viewcode_modules = {} def has_tag(modname, fullname, docname): entry = env._viewcode_modules.get(modname, None) try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False return if not isinstance(analyzer.code, str): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code if entry is None or entry[0] != code: analyzer.find_tags() entry = code, analyzer.tags, {} env._viewcode_modules[modname] = entry elif entry is False: return code, tags, used = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get("domain") != "py": continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get("module") if not modname: continue fullname = signode.get("fullname") if not has_tag(modname, fullname, env.docname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = "_modules/" + modname.replace(".", "/") onlynode = addnodes.only(expr="html") onlynode += addnodes.pending_xref( "", reftype="viewcode", refdomain="std", refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname, ) onlynode[0] += nodes.inline("", _("[source]"), classes=["viewcode-link"]) signode += onlynode
def doctree_read(app, doctree): env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} def has_tag(modname, fullname, docname): entry = env._viewcode_modules.get(modname, None) if entry is None: try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False return analyzer.find_tags() if not isinstance(analyzer.code, unicode): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code entry = code, analyzer.tags, {} env._viewcode_modules[modname] = entry elif entry is False: return code, tags, used = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if not has_tag(modname, fullname, env.docname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref('', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def doctree_read(app, doctree): # Add viewcode nodes for code elements referenced in the document. env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # handle desc (description) nodes (module contents) for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if not _update_tags(env, modname, fullname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') # build up an xref and add it to the desc node onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode # handle index nodes (modules themselves) for objnode in doctree.traverse(addnodes.index): # extract module name by de-munging the "target" field index_target = objnode['entries'][0][2] if not index_target.startswith('module-'): continue modname = index_target.replace('module-', '', 1) _update_tags(env, modname) pagename = '_modules/' + modname.replace('.', '/') # build up an xref and add it in a new paragraph after the index node xref = addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid='', refdoc=env.docname) xref += nodes.inline('', _('[source]'), classes=['viewcode-link']) idx = objnode.parent.index(objnode) + 1 objnode.parent.insert(idx, nodes.paragraph('', '', xref))
def make_httpdomain_rst(self, mapped_routes): node = nodes.section() node.document = self.state.document result = ViewList() routes = {} for route in mapped_routes: if route['method'] == ANY_KEY: method = 'any' else: method = route['method'] directives = http_directive( method, route['pattern'], route['docs'], ) routes[(method, route['pattern'])] = route for line in directives: result.append(line, '<autopyramid>') nested_parse_with_titles(self.state, result, node) for objnode in node.traverse(addnodes.desc): if objnode.get('domain') != 'http': continue for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue method = signode.get('method') path = signode.get('path') mapped_route = routes.get((method, path)) if not method or not path or not mapped_route: continue xref_node = self._make_view_source_xref(mapped_route) if not xref_node: continue xref_node += nodes.inline('', '[source]', classes=['viewcode-link']) source_node = addnodes.only(expr='html') source_node += xref_node signode += source_node return node.children
def youtube_embed(id): html = f""" <div class="video-container"> <iframe width="100%" height="100%" src="https://www.youtube-nocookie.com/embed/{id}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> </iframe> </div>""" # Add only HTML node. only_html = addnodes.only(expr="html") text = "https://www.youtube.com/watch?v={id}" # Add YouTube HTML to only node. only_html += nodes.raw(text=html, format="html") # Add fallback for PDFs. only_pdf = addnodes.only(expr="latex") # TODO: add optional fallback text only_pdf += nodes.paragraph(text=f"https://www.youtube.com/watch?v={id}") return [only_html, only_pdf]
def doctree_read(app, doctree): # Get the configuration parameters if app.config.edit_on_github_project == 'REQUIRED': raise ValueError( "The edit_on_github_project configuration variable must be " "provided in the conf.py") source_root = app.config.edit_on_github_source_root url = get_url_base(app) docstring_message = app.config.edit_on_github_docstring_message # Handle the docstring-editing links for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if fullname in names: # only one link per name, please continue names.add(fullname) obj = import_object(modname, fullname) anchor = None if obj is not None: try: lines, lineno = inspect.getsourcelines(obj) except: pass else: anchor = '#L%d' % lineno if anchor: real_modname = inspect.getmodule(obj).__name__ path = '%s%s%s.py%s' % (url, source_root, real_modname.replace('.', '/'), anchor) onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_github_help_message, refuri=path) onlynode[0] += nodes.inline( '', '', nodes.raw('', ' ', format='html'), nodes.Text(docstring_message), classes=['edit-on-github', 'viewcode-link']) signode += onlynode
def doctree_read(app, doctree): # type: (Sphinx, nodes.Node) -> None env = app.builder.env resolve_target = getattr(env.config, 'linkcode_resolve', None) if not callable(env.config.linkcode_resolve): raise LinkcodeError( "Function `linkcode_resolve` is not given in conf.py") domain_keys = { 'py': ['module', 'fullname'], 'c': ['names'], 'cpp': ['names'], 'js': ['object', 'fullname'], } for objnode in doctree.traverse(addnodes.desc): domain = objnode.get('domain') uris = set() # type: Set[unicode] for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue # Convert signode to a specified format info = {} for key in domain_keys.get(domain, []): value = signode.get(key) if not value: value = '' info[key] = value if not info: continue # Call user code to resolve the link uri = resolve_target(domain, info) if not uri: # no source continue if uri in uris or not uri: # only one link per name, please continue uris.add(uri) inline = nodes.inline('', _('[source]'), classes=['viewcode-link']) onlynode = addnodes.only(expr='html') onlynode += nodes.reference('', '', inline, internal=False, refuri=uri) signode += onlynode
def build_toc(node, depth=1): # type: (nodes.Node, int) -> List[nodes.Node] entries = [] for sectionnode in node: # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then # resolved in self.get_and_resolve_doctree) if isinstance(sectionnode, addnodes.only): onlynode = addnodes.only(expr=sectionnode['expr']) blist = build_toc(sectionnode, depth) if blist: onlynode += blist.children # type: ignore entries.append(onlynode) continue if not isinstance(sectionnode, nodes.section): for toctreenode in traverse_in_section( sectionnode, addnodes.toctree): item = toctreenode.copy() entries.append(item) # important: do the inventory stuff TocTree(app.env).note(docname, toctreenode) continue title = sectionnode[0] # copy the contents of the section title, but without references # and unnecessary stuff visitor = SphinxContentsFilter(doctree) title.walkabout(visitor) nodetext = visitor.get_entry_text() if not numentries[0]: # for the very first toc entry, don't add an anchor # as it is the file's title anyway anchorname = '' else: anchorname = '#' + sectionnode['ids'][0] numentries[0] += 1 # make these nodes: # list_item -> compact_paragraph -> reference reference = nodes.reference('', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) sub_item = build_toc(sectionnode, depth + 1) item += sub_item entries.append(item) if entries: return nodes.bullet_list('', *entries) return []
def doctree_read(app, doctree): # type: (Sphinx, nodes.Node) -> None env = app.builder.env resolve_target = getattr(env.config, 'linkcode_resolve', None) if not callable(env.config.linkcode_resolve): raise LinkcodeError( "Function `linkcode_resolve` is not given in conf.py") domain_keys = { 'py': ['module', 'fullname'], 'c': ['names'], 'cpp': ['names'], 'js': ['object', 'fullname'], } for objnode in doctree.traverse(addnodes.desc): domain = objnode.get('domain') uris = set() # type: Set[str] for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue # Convert signode to a specified format info = {} for key in domain_keys.get(domain, []): value = signode.get(key) if not value: value = '' info[key] = value if not info: continue if 'lineno' in signode.attributes: info['lineno'] = signode.attributes['lineno'] # Call user code to resolve the link uri = resolve_target(domain, info) if not uri: # no source continue if uri in uris or not uri: # only one link per name, please continue uris.add(uri) inline = nodes.inline('', _('[source]'), classes=['viewcode-link']) onlynode = addnodes.only(expr='html') onlynode += nodes.reference('', '', inline, internal=False, refuri=uri) signode += onlynode
def add_source_link(self, signode: addnodes.desc) -> None: """ Add link to source code to *signode* """ filename, lineno = self.options['source'].split(':') if not hasattr(self.env, '_snakefiles'): self.env._snakefiles = set() self.env._snakefiles.add(filename) onlynode = addnodes.only(expr='html') # show only in html onlynode += nodes.reference( '', refuri='_snakefiles/{}.html#line-{}'.format(filename, lineno)) onlynode[0] += nodes.inline('', '[source]', classes=['viewcode-link']) signode += onlynode
def doctree_read(app, doctree): # Get the configuration parameters if app.config.edit_on_github_project == 'REQUIRED': raise ValueError( "The edit_on_github_project configuration variable must be " "provided in the conf.py") source_root = app.config.edit_on_github_source_root url = get_url_base(app) docstring_message = app.config.edit_on_github_docstring_message # Handle the docstring-editing links for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if fullname in names: # only one link per name, please continue names.add(fullname) obj = import_object(modname, fullname) anchor = None if obj is not None: try: lines, lineno = inspect.getsourcelines(obj) except: pass else: anchor = '#L%d' % lineno if anchor: real_modname = inspect.getmodule(obj).__name__ path = '%s%s%s.py%s' % ( url, source_root, real_modname.replace('.', '/'), anchor) onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_github_help_message, refuri=path) onlynode[0] += nodes.inline( '', '', nodes.raw('', ' ', format='html'), nodes.Text(docstring_message), classes=['edit-on-github', 'viewcode-link']) signode += onlynode
def build_toc(node, depth=1): # type: (nodes.Element, int) -> nodes.bullet_list entries = [] # type: List[nodes.Element] for sectionnode in node: # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then # resolved in self.get_and_resolve_doctree) if isinstance(sectionnode, nodes.section): title = sectionnode[0] # copy the contents of the section title, but without references # and unnecessary stuff visitor = SphinxContentsFilter(doctree) title.walkabout(visitor) nodetext = visitor.get_entry_text() if not numentries[0]: # for the very first toc entry, don't add an anchor # as it is the file's title anyway anchorname = '' else: anchorname = '#' + sectionnode['ids'][0] numentries[0] += 1 # make these nodes: # list_item -> compact_paragraph -> reference reference = nodes.reference( '', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) # type: nodes.Element sub_item = build_toc(sectionnode, depth + 1) if sub_item: item += sub_item entries.append(item) elif isinstance(sectionnode, addnodes.only): onlynode = addnodes.only(expr=sectionnode['expr']) blist = build_toc(sectionnode, depth) if blist: onlynode += blist.children entries.append(onlynode) elif isinstance(sectionnode, nodes.Element): for toctreenode in traverse_in_section(sectionnode, addnodes.toctree): item = toctreenode.copy() entries.append(item) # important: do the inventory stuff TocTree(app.env).note(docname, toctreenode) if entries: return nodes.bullet_list('', *entries) return None
def run(self): # type: () -> List[nodes.Node] node = addnodes.only() node.document = self.state.document self.set_source_info(node) node['expr'] = self.arguments[0] # Same as util.nested_parse_with_titles but try to handle nested # sections which should be raised higher up the doctree. memo = self.state.memo # type: Any surrounding_title_styles = memo.title_styles surrounding_section_level = memo.section_level memo.title_styles = [] memo.section_level = 0 try: self.state.nested_parse(self.content, self.content_offset, node, match_titles=True) title_styles = memo.title_styles if (not surrounding_title_styles or not title_styles or title_styles[0] not in surrounding_title_styles or not self.state.parent): # No nested sections so no special handling needed. return [node] # Calculate the depths of the current and nested sections. current_depth = 0 parent = self.state.parent while parent: current_depth += 1 parent = parent.parent current_depth -= 2 title_style = title_styles[0] nested_depth = len(surrounding_title_styles) if title_style in surrounding_title_styles: nested_depth = surrounding_title_styles.index(title_style) # Use these depths to determine where the nested sections should # be placed in the doctree. n_sects_to_raise = current_depth - nested_depth + 1 parent = cast(nodes.Element, self.state.parent) for i in range(n_sects_to_raise): if parent.parent: parent = parent.parent parent.append(node) return [] finally: memo.title_styles = surrounding_title_styles memo.section_level = surrounding_section_level
def doctree_read(app, doctree): env = app.builder.env resolve_target = getattr(env.config, 'linkcode_resolve', None) if not isinstance(env.config.linkcode_resolve, collections.Callable): raise LinkcodeError( "Function `linkcode_resolve` is not given in conf.py") domain_keys = dict( py=['module', 'fullname'], c=['names'], cpp=['names'], js=['object', 'fullname'], ) for objnode in doctree.traverse(addnodes.desc): domain = objnode.get('domain') uris = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue # Convert signode to a specified format info = {} for key in domain_keys.get(domain, []): value = signode.get(key) if not value: value = '' info[key] = value if not info: continue # Call user code to resolve the link uri = resolve_target(domain, info) if not uri: # no source continue if uri in uris or not uri: # only one link per name, please continue uris.add(uri) onlynode = addnodes.only(expr='html') onlynode += nodes.reference('', '', internal=False, refuri=uri) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def run(self): # type: () -> List[nodes.Node] node = addnodes.only() node.document = self.state.document set_source_info(self, node) node['expr'] = self.arguments[0] # Same as util.nested_parse_with_titles but try to handle nested # sections which should be raised higher up the doctree. memo = self.state.memo # type: Any surrounding_title_styles = memo.title_styles surrounding_section_level = memo.section_level memo.title_styles = [] memo.section_level = 0 try: self.state.nested_parse(self.content, self.content_offset, node, match_titles=True) title_styles = memo.title_styles if (not surrounding_title_styles or not title_styles or title_styles[0] not in surrounding_title_styles or not self.state.parent): # No nested sections so no special handling needed. return [node] # Calculate the depths of the current and nested sections. current_depth = 0 parent = self.state.parent while parent: current_depth += 1 parent = parent.parent current_depth -= 2 title_style = title_styles[0] nested_depth = len(surrounding_title_styles) if title_style in surrounding_title_styles: nested_depth = surrounding_title_styles.index(title_style) # Use these depths to determine where the nested sections should # be placed in the doctree. n_sects_to_raise = current_depth - nested_depth + 1 parent = cast(nodes.Element, self.state.parent) for i in range(n_sects_to_raise): if parent.parent: parent = parent.parent parent.append(node) return [] finally: memo.title_styles = surrounding_title_styles memo.section_level = surrounding_section_level
def build_toc(node, depth=1, main=False, title_visited=False): entries = [] for sectionnode in node: # EV: added or condition on 'main' and 'title_visited' # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then # resolved in self.get_and_resolve_doctree) if isinstance(sectionnode, addnodes.only): onlynode = addnodes.only(expr=sectionnode['expr']) blist = build_toc(sectionnode, depth) if blist: onlynode += blist.children entries.append(onlynode) if not isinstance(sectionnode, nodes.section) or (main and title_visited): for toctreenode in traverse_in_section(sectionnode, addnodes.toctree): item = toctreenode.copy() entries.append(item) # important: do the inventory stuff self.note_toctree(docname, toctreenode) continue title = sectionnode[0] # copy the contents of the section title, but without references # and unnecessary stuff visitor = SphinxContentsFilter(document) title.walkabout(visitor) nodetext = visitor.get_entry_text() if not numentries[0]: # for the very first toc entry, don't add an anchor # as it is the file's title anyway anchorname = '' else: anchorname = '#' + sectionnode['ids'][0] numentries[0] += 1 reference = nodes.reference( '', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) if maxdepth == 0 or depth < maxdepth: # EV: set 'main' and 'title_visited' args item += build_toc(sectionnode, depth+1, main=main, title_visited=True) entries.append(item) if entries: return nodes.bullet_list('', *entries) return []
def _add_pending_source_cross_reference(app: Sphinx, signode: Node, fullname: str) -> None: """ Adds a pending source cross reference to the signature in the doctree, `signode`. The viewcode and linkcode extensions walk the doctree once parsed and then add this node, however since sphinx_c_autodoc already has to add logic, the `module` option to the directives it seems more practical to just create the full pending cross reference here, and then viewcode is an extension which will populate this cross refernce. Args: app (Sphinx): The sphinx app currently doing the processing. signode (Node): The signature node to apply the source code cross reference to. fullname (str): The dotted fullname of the C construct. """ module = signode.get("module") if module is None: return source_page = _get_source_page_name(module) # Using the `viewcode-link` to be consistent with the python versions in # case someone else wants to walk the tree and do other links inline = nodes.inline("", "[source]", classes=["viewcode-link"]) # Limit this cross referencing only to html html_node = addnodes.only(expr="html") html_node += addnodes.pending_xref( "", inline, reftype=f"{C_DOMAIN_LINK_PREFIX}viewcode", refdomain="std", refexplicit=False, reftarget=source_page, refid=f"{C_DOMAIN_LINK_PREFIX}{fullname}", refdoc=app.builder.env.docname, module=module, fullname=fullname, ) signode += html_node
def run(self): node = addnodes.only() node.document = self.state.document set_source_info(self, node) node['expr'] = 'iguide' class_value = ['iguide', self.arguments[0]] pending = nodes.pending(misc.ClassAttribute, {'class': class_value, 'directive': self.name}, self.block_text) self.state_machine.document.note_pending(pending) node += pending self.state.nested_parse(self.content, self.content_offset, node, match_titles=1) return [node]
def run(self) -> List[nodes.Node]: """ Create the installation node. """ if self.env.docname != self.env.config.master_doc: # pragma: no cover warnings.warn( "The 'sidebar-links' directive can only be used on the Sphinx master doc. " "No links will be shown.", UserWarning, ) return [] body = StringList([ ".. toctree::", " :hidden:", ]) with body.with_indent(" ", 1): if "caption" in self.options: body.append(f":caption: {self.options['caption']}") else: # pragma: no cover body.append(":caption: Links") body.blankline() if "github" in self.options: body.append(self.process_github_option()) if "pypi" in self.options: body.append( f"PyPI <https://pypi.org/project/{self.options['pypi']}>") body.extend(self.content) body.blankline() body.blankline() only_node = addnodes.only(expr="html") content_node = nodes.paragraph(rawsource=str(body)) only_node += content_node self.state.nested_parse(docutils.statemachine.StringList(body), self.content_offset, content_node) return [only_node]
def doctree_read(app, doctree): env = app.builder.env resolve_target = getattr(env.config, "linkcode_resolve", None) if not callable(env.config.linkcode_resolve): raise LinkcodeError("Function `linkcode_resolve` is not given in conf.py") domain_keys = dict(py=["module", "fullname"], c=["names"], cpp=["names"], js=["object", "fullname"]) for objnode in doctree.traverse(addnodes.desc): domain = objnode.get("domain") uris = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue # Convert signode to a specified format info = {} for key in domain_keys.get(domain, []): value = signode.get(key) if not value: value = "" info[key] = value if not info: continue # Call user code to resolve the link uri = resolve_target(domain, info) if not uri: # no source continue if uri in uris or not uri: # only one link per name, please continue uris.add(uri) onlynode = addnodes.only(expr="html") onlynode += nodes.reference("", "", internal=False, refuri=uri) onlynode[0] += nodes.inline("", _("[source]"), classes=["viewcode-link"]) signode += onlynode
def run(self): link = self.arguments[0] embed_type = "Card" if "/c/" in link else "Board" container = nodes.container() html = f""" <blockquote class="trello-{embed_type.lower()}-compact"> <a href="{link}">Trello {embed_type}</a> </blockquote>""" html_node = nodes.raw(text=html, format="html") only_pdf = addnodes.only(expr="latex") # We need to provide a node for nested parsing. And another node for populating the parsed node. only_pdf_paragraph = nodes.inline() self.state.nested_parse( nodes.inline(text=f"`Trello {embed_type} <{link}>`_"), 0, only_pdf_paragraph) only_pdf += only_pdf_paragraph container += html_node container += only_pdf return container.children
def run(self) -> List[nodes.Node]: """ Process the content of the directive. """ summary = getattr(self.config, "documentation_summary", '').strip() if not summary: return [] # pragma: no cover # if self.env.app.builder.format.lower() == "latex" or not summary: # return [] targetid = f'documentation-summary-{self.env.new_serialno("documentation-summary"):d}' onlynode = addnodes.only(expr="html") content = f'**{summary}**' content_node = nodes.paragraph(rawsource=content, ids=[targetid]) onlynode += content_node self.state.nested_parse(StringList([content]), self.content_offset, content_node) summary_node_purger.add_node(self.env, content_node, content_node, self.lineno) if "meta" in self.options: meta_content = f'.. meta::\n :description: {self.config.project} -- {summary}\n' meta_node = nodes.paragraph(rawsource=meta_content, ids=[targetid]) onlynode += meta_node self.state.nested_parse( StringList(meta_content.split('\n')), self.content_offset, meta_node, ) summary_node_purger.add_node(self.env, meta_node, meta_node, self.lineno) return [onlynode]
def run(self): self.assert_has_content() node = addnodes.only() node.document = self.state.document set_source_info(self, node) node['expr'] = 'iguide' text = '\n'.join(self.content) admonition_node = nodes.admonition(text, **self.options) self.add_name(admonition_node) title_text = self.arguments[0] textnodes, messages = self.state.inline_text(title_text, self.lineno) admonition_node += nodes.title(title_text, '', *textnodes) admonition_node += messages admonition_node['classes'] += ['iguide'] self.state.nested_parse(self.content, self.content_offset, admonition_node) node += admonition_node return [node]
def doctree_read(app, doctree): # type: (Sphinx, nodes.Node) -> None env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore if app.builder.name == "singlehtml": return if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub: return def has_tag(modname, fullname, docname, refname): entry = env._viewcode_modules.get(modname, None) # type: ignore if entry is False: return code_tags = app.emit_firstresult('viewcode-find-source', modname) if code_tags is None: try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False # type: ignore return if not isinstance(analyzer.code, text_type): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code analyzer.find_tags() tags = analyzer.tags else: code, tags = code_tags if entry is None or entry[0] != code: entry = code, tags, {}, refname env._viewcode_modules[modname] = entry # type: ignore _, tags, used, _ = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() # type: Set[unicode] for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_follow_imported_members: new_modname = app.emit_firstresult( 'viewcode-follow-imported', modname, fullname, ) if not new_modname: new_modname = _get_full_modname(app, modname, fullname) modname = new_modname if not modname: continue fullname = signode.get('fullname') if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def doctree_read(app, doctree): classes_to_attributes = {} def get_unique_parts(parts): unique_parts = [parts[0]] for part in parts[1:]: if part != unique_parts[-1]: unique_parts.append(part) else: break return unique_parts for desc_node in doctree.traverse(addnodes.desc): if desc_node.get('domain') != 'py': continue signature_node = desc_node.traverse(addnodes.desc_signature)[0] module_name = signature_node.get('module') object_name = signature_node.get('fullname') object_type = desc_node.get('objtype') module = importlib.import_module(module_name) # Strip 'abjad.tools.' or 'experimental.tools.' from signature. # Also strip duplicate class names. if object_type in ('function', 'class'): addname_node = signature_node.traverse(addnodes.desc_addname)[0] text = addname_node[0].astext() parts = [x for x in text.split('.') if x] parts = get_unique_parts(parts) if parts[0] in ('abjad', 'experimental'): parts = parts[2:-1] text = '{}.'.format('.'.join(parts)) addname_node[0] = nodes.Text(text) if object_type == 'class': cls = getattr(module, object_name, None) if cls is None: continue if cls not in classes_to_attributes: classes_to_attributes[cls] = {} attributes = inspect.classify_class_attrs(cls) for attribute in attributes: classes_to_attributes[cls][attribute.name] = attribute if inspect.isabstract(cls): labelnode = addnodes.only(expr='html') labelnode.append(nodes.literal( '', ' abstract ', classes=['attribute', 'abstract'], )) signature_node.insert(0, labelnode) elif object_type in ('method', 'attribute', 'staticmethod', 'classmethod'): object_parts = object_name.split('.') cls_name, attr_name = object_name.split('.') cls = getattr(module, cls_name, None) if cls is None: continue attr = getattr(cls, attr_name) inspected_attr = classes_to_attributes[cls][attr_name] label_node = addnodes.only(expr='html') defining_class = inspected_attr.defining_class if defining_class != cls: addname_node = signature_node.traverse( addnodes.desc_addname)[0] xref_node = addnodes.pending_xref( '', refdomain='py', refexplicit=True, reftype='class', reftarget='{}.{}'.format( defining_class.__module__, defining_class.__name__, )) xref_node.append(nodes.literal( '', '{}'.format(defining_class.__name__), )) html_only_class_name_node = addnodes.only(expr='html') html_only_class_name_node.append(nodes.Text('(')) html_only_class_name_node.append(xref_node) html_only_class_name_node.append(nodes.Text(').')) latex_only_class_name_node = addnodes.only(expr='latex') latex_only_class_name_node.append(nodes.Text( '({}).'.format(defining_class.__name__), )) addname_node.clear() addname_node.append(html_only_class_name_node) addname_node.append(latex_only_class_name_node) label_node.append(nodes.literal( '', ' inherited ', classes=['attribute', 'inherited'], )) if getattr(attr, '__isabstractmethod__', False): label_node.append(nodes.literal( '', ' abstract ', classes=['attribute', 'abstract'], )) if isinstance(attr, types.FunctionType): # remove Sphinx's annotation, so we can use our own. signature_node.pop(0) label_node.append(nodes.literal( '', ' staticmethod ', classes=['attribute', 'staticmethod'], )) elif hasattr(attr, 'im_self') and attr.im_self is not None: signature_node.pop(0) label_node.append(nodes.literal( '', ' classmethod ', classes=['attribute', 'classmethod'], )) signature_node.insert(0, label_node)
def doctree_read(app, doctree): # type: (Sphinx, nodes.Node) -> None env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore if app.builder.name == "singlehtml": return if app.builder.name.startswith( "epub") and not env.config.viewcode_enable_epub: return def has_tag(modname, fullname, docname, refname): entry = env._viewcode_modules.get(modname, None) # type: ignore try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False # type: ignore return if not isinstance(analyzer.code, text_type): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code if entry is False: return elif entry is None or entry[0] != code: analyzer.find_tags() entry = code, analyzer.tags, {}, refname env._viewcode_modules[modname] = entry # type: ignore _, tags, used, _ = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() # type: Set[unicode] for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_import: modname = _get_full_modname(app, modname, fullname) if not modname: continue fullname = signode.get('fullname') if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref('', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def doctree_read(app, doctree): # Get the configuration parameters if app.config.edit_on_github_project == 'REQUIRED': raise ValueError( "The edit_on_github_project configuration variable must be " "provided in the conf.py") source_root = app.config.edit_on_github_source_root if source_root != '' and not source_root.endswith('/'): source_root += '/' doc_root = app.config.edit_on_github_doc_root if doc_root != '' and not doc_root.endswith('/'): doc_root += '/' url = 'http://github.com/%s/tree/%s/' % ( app.config.edit_on_github_project, app.config.edit_on_github_branch) docstring_message = app.config.edit_on_github_docstring_message page_message = app.config.edit_on_github_page_message # Handle the "edit this page" link doc_path = os.path.relpath(doctree.get('source'), app.builder.srcdir) if not re.match(app.config.edit_on_github_skip_regex, doc_path): path = url + doc_root + doc_path onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_bitbucket_help_message, refuri=path) onlynode[0] += nodes.inline( '', page_message, classes=['edit-on-github']) para = nodes.paragraph() para.update_basic_atts({'classes':['edit-on-github-para']}) para += onlynode if 'edit-section' in doctree[-1].attributes['classes']: doctree[-1] += para else: section = nodes.section() section.update_basic_atts({'classes':['edit-section']}) section += para doctree += section # Handle the docstring-editing links for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if fullname in names: # only one link per name, please continue names.add(fullname) obj = import_object(modname, fullname) anchor = None if obj is not None: try: lines, lineno = inspect.getsourcelines(obj) except: pass else: anchor = '#L%d' % lineno if anchor: path = '%s%s%s.py%s' % ( url, source_root, modname.replace('.', '/'), anchor) onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_github_help_message, refuri=path) onlynode[0] += nodes.inline( '', '', nodes.raw('', ' ', format='html'), nodes.Text(docstring_message), classes=['edit-on-github', 'viewcode-link']) signode += onlynode
def doctree_read(app, doctree): classes_to_attributes = {} def get_unique_parts(parts): unique_parts = [parts[0]] for part in parts[1:]: if part != unique_parts[-1]: unique_parts.append(part) else: break return unique_parts for desc_node in doctree.traverse(addnodes.desc): if desc_node.get('domain') != 'py': continue signature_node = desc_node.traverse(addnodes.desc_signature)[0] module_name = signature_node.get('module') object_name = signature_node.get('fullname') object_type = desc_node.get('objtype') module = importlib.import_module(module_name) if object_type == 'class': cls = getattr(module, object_name, None) if cls is None: continue if cls not in classes_to_attributes: classes_to_attributes[cls] = {} attributes = inspect.classify_class_attrs(cls) for attribute in attributes: classes_to_attributes[cls][attribute.name] = attribute if inspect.isabstract(cls): labelnode = addnodes.only(expr='html') labelnode.append(nodes.emphasis( 'abstract ', 'abstract ', classes=['property'], )) signature_node.insert(0, labelnode) elif object_type in ('method', 'attribute', 'staticmethod', 'classmethod'): cls_name, attr_name = object_name.split('.') cls = getattr(module, cls_name, None) if cls is None: continue attr = getattr(cls, attr_name) inspected_attr = classes_to_attributes[cls][attr_name] label_node = addnodes.only(expr='html') defining_class = inspected_attr.defining_class if defining_class != cls: addname_node = signature_node.traverse( addnodes.desc_addname)[0] if defining_class.__module__.startswith('supriya'): reftarget = defining_class.__module__ else: reftarget = '{}.{}'.format( defining_class.__module__, defining_class.__name__, ) xref_node = addnodes.pending_xref( '', refdomain='py', refexplicit=True, reftype='class', reftarget=reftarget, ) xref_node.append(nodes.literal( '', '{}'.format(defining_class.__name__), classes=['descclassname'], )) html_only_class_name_node = addnodes.only(expr='html') html_only_class_name_node.append(nodes.Text('(')) html_only_class_name_node.append(xref_node) html_only_class_name_node.append(nodes.Text(').')) latex_only_class_name_node = addnodes.only(expr='latex') latex_only_class_name_node.append(nodes.Text( '({}).'.format(defining_class.__name__), )) addname_node.clear() addname_node.append(html_only_class_name_node) addname_node.append(latex_only_class_name_node) #label_node.append(nodes.emphasis( # 'inherited ', # 'inherited ', # classes=['property'], # )) if getattr(attr, '__isabstractmethod__', False): label_node.append(nodes.emphasis( 'abstract ', 'abstract ', classes=['property'], )) if hasattr(attr, 'im_self') and attr.im_self is not None: signature_node.pop(0) label_node.append(nodes.emphasis( 'classmethod ', 'classmethod ', classes=['property'], )) signature_node.insert(0, label_node)
def build_toc(node: nodes.Element, depth: int = 1) -> Optional[nodes.bullet_list]: """ Build the table of contents. :param node: :param depth: """ entries: List[nodes.Element] = [] item: nodes.Element toctree_plus_types = set(app.env.config.toctree_plus_types) for sectionnode in node: # find all toctree nodes in this section and add them # to the toc (just copying the toctree node which is then # resolved in self.get_and_resolve_doctree) if isinstance(sectionnode, nodes.section): title = sectionnode[0] # copy the contents of the section title, but without references # and unnecessary stuff visitor = SphinxContentsFilter(doctree) title.walkabout(visitor) nodetext = visitor.get_entry_text() if not numentries[0]: # for the very first toc entry, don't add an anchor # as it is the file's title anyway anchorname = '' else: anchorname = f'#{sectionnode["ids"][0]}' numentries[0] += 1 # make these nodes: # list_item -> compact_paragraph -> reference reference = nodes.reference( '', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext, ) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) sub_item = build_toc(sectionnode, depth + 1) if sub_item: item += sub_item entries.append(item) elif isinstance(sectionnode, addnodes.desc): # Add class, function and method directives to toctree. # (doesn't currently work for method directives - are they nested?) if sectionnode.attributes["objtype"] in toctree_plus_types: attributes = sectionnode.children[0].attributes if not attributes["ids"]: # Has no anchor continue title = attributes.get("fullname", sectionnode.children[0].astext()) if sectionnode.attributes["objtype"] in {"method", "attribute"}: # TODO: remove special case title = title.split('.', 1)[-1] anchorname = f'#{attributes["ids"][0]}' reference = nodes.reference( '', '', internal=True, refuri=docname, anchorname=anchorname, *[nodes.literal(text=title)], ) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) sub_item = build_toc(sectionnode.children[1], depth + 1) if sub_item: item += sub_item entries.append(item) elif TOCTREE_PLUS_DEBUG: print(sectionnode) pprint(sectionnode.attributes["objtype"]) elif isinstance(sectionnode, addnodes.only): onlynode = addnodes.only(expr=sectionnode["expr"]) blist = build_toc(sectionnode, depth) if blist: onlynode += blist.children entries.append(onlynode) elif isinstance(sectionnode, nodes.Element): for toctreenode in traverse_in_section(sectionnode, addnodes.toctree): item = toctreenode.copy() entries.append(item) # important: do the inventory stuff TocTree(app.env).note(docname, toctreenode) if entries: return nodes.bullet_list('', *entries) else: return None
def doctree_read(app, doctree): env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} def get_full_modname(modname, attribute): try: __import__(modname) except Exception as error: if not app.quiet: app.info(traceback.format_exc().rstrip()) app.warn('viewcode can\'t import %s, failed with error "%s"' % (modname, error)) return None module = sys.modules[modname] try: # Allow an attribute to have multiple parts and incidentally allow # repeated .s in the attribute. attr = attribute.split('.') value = module for attr in attribute.split('.'): if attr: value = safe_getattr(value, attr) except AttributeError: app.warn('Didn\'t find %s in %s' % (attribute, module.__name__)) return None else: return safe_getattr(value, '__module__', None) def has_tag(modname, fullname, docname, refname): entry = env._viewcode_modules.get(modname, None) if entry is None: try: analyzer = ModuleAnalyzer.for_module(modname) except Exception: env._viewcode_modules[modname] = False return analyzer.find_tags() if not isinstance(analyzer.code, text_type): code = analyzer.code.decode(analyzer.encoding) else: code = analyzer.code entry = code, analyzer.tags, {}, refname env._viewcode_modules[modname] = entry elif entry is False: return _, tags, used, _ = entry if fullname in tags: used[fullname] = docname return True for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_import: modname = get_full_modname(modname, fullname) if not modname: continue if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode
def style_document(app, document): def get_unique_parts(parts): unique_parts = [parts[0]] for part in parts[1:]: if part != unique_parts[-1]: unique_parts.append(part) else: break return unique_parts classes_to_attributes = {} for desc_node in document.traverse(addnodes.desc): if desc_node.get('domain') != 'py': continue signature_node = desc_node.traverse(addnodes.desc_signature)[0] module_name = signature_node.get('module') object_name = signature_node.get('fullname') object_type = desc_node.get('objtype') module = importlib.import_module(module_name) if object_type in ('function', 'class'): addname_node = signature_node.traverse( addnodes.desc_addname)[0] text = addname_node[0].astext() parts = [x for x in text.split('.') if x] parts = get_unique_parts(parts) if parts[0] in ('abjad', 'experimental', 'ide'): parts = parts[-1:] if parts: text = '{}.'.format('.'.join(parts)) else: text = '' addname_node[0] = nodes.Text(text) if object_type == 'class': cls = getattr(module, object_name, None) if cls is None: continue if cls not in classes_to_attributes: classes_to_attributes[cls] = {} attributes = inspect.classify_class_attrs(cls) for attribute in attributes: classes_to_attributes[cls][attribute.name] = attribute if inspect.isabstract(cls): labelnode = addnodes.only(expr='html') labelnode.append( nodes.emphasis( 'abstract ', 'abstract ', classes=['property'], )) signature_node.insert(0, labelnode) elif object_type in ('method', 'attribute', 'staticmethod', 'classmethod'): cls_name, attr_name = object_name.split('.') cls = getattr(module, cls_name, None) if cls is None: continue attr = getattr(cls, attr_name) inspected_attr = classes_to_attributes[cls][attr_name] label_node = addnodes.only(expr='html') defining_class = inspected_attr.defining_class if defining_class != cls: addname_node = signature_node.traverse( addnodes.desc_addname)[0] if defining_class.__module__.startswith('abjad'): reftarget = defining_class.__module__ else: reftarget = '{}.{}'.format( defining_class.__module__, defining_class.__name__, ) xref_node = addnodes.pending_xref( '', refdomain='py', refexplicit=True, reftype='class', reftarget=reftarget, ) xref_node.append( nodes.literal( '', '{}'.format(defining_class.__name__), classes=['descclassname'], )) html_only_class_name_node = addnodes.only(expr='html') html_only_class_name_node.append(nodes.Text('(')) html_only_class_name_node.append(xref_node) html_only_class_name_node.append(nodes.Text(').')) latex_only_class_name_node = addnodes.only(expr='latex') latex_only_class_name_node.append( nodes.Text('({}).'.format(defining_class.__name__), )) addname_node.clear() addname_node.append(html_only_class_name_node) addname_node.append(latex_only_class_name_node) if getattr(attr, '__isabstractmethod__', False): label_node.append( nodes.emphasis( 'abstract ', 'abstract ', classes=['property'], )) if hasattr(attr, 'im_self') and attr.im_self is not None: signature_node.pop(0) label_node.append( nodes.emphasis( 'classmethod ', 'classmethod ', classes=['property'], )) signature_node.insert(0, label_node)
def run(self): env = self.state.document.settings.env extcode_config = env.app.config.extcode if not extcode_config: if all(opt not in self.options for opt in self.extra_option_spec): return super(ExtCode, self).run() # nothing to do special rendered_block = self.options.get('rendered-block', extcode_config.get('rendered-block')) line_annotations = {} annotations = self.options.get('annotations', []) annotationsmap = dict((k.astext(), v) for k, v in annotations) for i, c in enumerate(self.content): match = annotation_matcher(c) if match: self.content[i], label = match.groups() if label in annotationsmap: line_annotations[i] = (label, annotationsmap[label]) else: #TODO: warning line_annotations[i] = (label, None) # get literal from modified self.content literal = super(ExtCode, self).run()[0] # line_annotations attribute will be used for writer (not yet) literal['line_annotations'] = line_annotations wrapper = extcode(classes=['extcode']) set_source_info(self, wrapper) #check: can parse rst? and partial build? try: partial_doc = sandbox_rst_parser(u'\n'.join(self.content), env.doc2path(env.docname), env.settings) partial_out = sandbox_partial_builder(partial_doc, env) except Exception as e: env.warn(env.docname, u'extcode: partial build failed: %s' % str(e), lineno=self.lineno) partial_doc = None partial_out = None if literal['language'] == 'rst' and rendered_block: wrapper['classes'].append('extcode-layout-' + rendered_block) rendered = nodes.container() set_source_info(self, rendered) only_html = addnodes.only(expr='html') set_source_info(self, only_html) only_html += nodes.raw(partial_out, partial_out, format='html', classes=['extcode-rendered']) rendered += only_html if 'rendered-image' in self.options: only_xml = addnodes.only(expr='xml') set_source_info(self, only_xml) only_xml += nodes.image(self.options['rendered-image'], uri=self.options['rendered-image']) rendered += only_xml #FIXME: need translation support make_text = lambda t: nodes.inline(t, t) if rendered_block == 'horizontal': table = build_table( [[make_text('literal'), make_text('rendered')], [literal, rendered]], [1, 1], head_rows=1, attrs={'classes': ['extcode-layout']}) table.setdefault('classes', []).append('extcode-layout') wrapper.append(table) elif rendered_block == 'vertical': table = build_table([[make_text('literal'), literal], [make_text('rendered'), rendered]], [2, 8], stub_columns=1, attrs={'classes': ['extcode-layout']}) table.setdefault('classes', []).append('extcode-layout') wrapper.append(table) else: # toggle, tab wrapper.append(literal) wrapper.append(rendered) else: wrapper.append(literal) if line_annotations and 'annotate-inline' in self.options: prefix = '... ' #TODO prefixi customization contents = [] for i in range(0, len(self.content)): label, value = line_annotations.get(i, ('', None)) line = nodes.line() if label and value: #FIXME: label and explanation need translation support abbr = nodes.abbreviation( label, label ) #TODO: label customization (i.e. render with number) abbr['explanation'] = value.astext() line.append(nodes.inline(prefix, prefix)) line.append(abbr) elif label: line.append(nodes.inline(prefix, prefix)) line.append(nodes.Text(label, label)) contents.append(line) overlay = nodes.line_block(classes=['extcode-overlay']) set_source_info(self, overlay) overlay.extend(contents) wrapper.append(overlay) if annotations and 'annotate-block' in self.options: annotations['classes'] = ['extcode-annotations'] set_source_info(self, annotations) wrapper.append(annotations) return [wrapper]
def doctree_read(app, doctree): # Get the configuration parameters if app.config.edit_on_github_project == 'REQUIRED': raise ValueError( "The edit_on_github_project configuration variable must be " "provided in the conf.py") source_root = app.config.edit_on_github_source_root if source_root != '' and not source_root.endswith('/'): source_root += '/' doc_root = app.config.edit_on_github_doc_root if doc_root != '' and not doc_root.endswith('/'): doc_root += '/' url = 'http://github.com/%s/tree/%s/' % (app.config.edit_on_github_project, app.config.edit_on_github_branch) docstring_message = app.config.edit_on_github_docstring_message page_message = app.config.edit_on_github_page_message # Handle the "edit this page" link doc_path = os.path.relpath(doctree.get('source'), app.builder.srcdir) if not re.match(app.config.edit_on_github_skip_regex, doc_path): path = url + doc_root + doc_path onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_bitbucket_help_message, refuri=path) onlynode[0] += nodes.inline('', page_message, classes=['edit-on-github']) para = nodes.paragraph() para.update_basic_atts({'classes': ['edit-on-github-para']}) para += onlynode if 'edit-section' in doctree[-1].attributes['classes']: doctree[-1] += para else: section = nodes.section() section.update_basic_atts({'classes': ['edit-section']}) section += para doctree += section # Handle the docstring-editing links for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') if not modname: continue fullname = signode.get('fullname') if fullname in names: # only one link per name, please continue names.add(fullname) obj = import_object(modname, fullname) anchor = None if obj is not None: try: lines, lineno = inspect.getsourcelines(obj) except: pass else: anchor = '#L%d' % lineno if anchor: path = '%s%s%s.py%s' % (url, source_root, modname.replace('.', '/'), anchor) onlynode = addnodes.only(expr='html') onlynode += nodes.reference( reftitle=app.config.edit_on_github_help_message, refuri=path) onlynode[0] += nodes.inline( '', '', nodes.raw('', ' ', format='html'), nodes.Text(docstring_message), classes=['edit-on-github', 'viewcode-link']) signode += onlynode
continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_import: modname = get_full_modname(modname, fullname) if not modname: continue if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref( '', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode def missing_reference(app, env, node, contnode): # resolve our "viewcode" reference nodes -- they need special treatment if node['reftype'] == 'viewcode': return make_refnode(app.builder, node['refdoc'], node['reftarget'], node['refid'], contnode)
def doctree_read(app: Sphinx, doctree: Node) -> None: env = app.builder.env if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # type: ignore if app.builder.name == "singlehtml": return if app.builder.name.startswith("epub") and not env.config.viewcode_enable_epub: return def has_tag(modname: str, fullname: str, docname: str, refname: str) -> bool: entry = env._viewcode_modules.get(modname, None) # type: ignore if entry is False: return False code_tags = app.emit_firstresult('viewcode-find-source', modname) if code_tags is None: try: analyzer = ModuleAnalyzer.for_module(modname) analyzer.find_tags() except Exception: env._viewcode_modules[modname] = False # type: ignore return False code = analyzer.code tags = analyzer.tags else: code, tags = code_tags if entry is None or entry[0] != code: entry = code, tags, {}, refname env._viewcode_modules[modname] = entry # type: ignore _, tags, used, _ = entry if fullname in tags: used[fullname] = docname return True return False for objnode in doctree.traverse(addnodes.desc): if objnode.get('domain') != 'py': continue names = set() # type: Set[str] for signode in objnode: if not isinstance(signode, addnodes.desc_signature): continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_follow_imported_members: new_modname = app.emit_firstresult( 'viewcode-follow-imported', modname, fullname, ) if not new_modname: new_modname = _get_full_modname(app, modname, fullname) modname = new_modname if not modname: continue fullname = signode.get('fullname') if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') inline = nodes.inline('', _('[source]'), classes=['viewcode-link']) onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref('', inline, reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) signode += onlynode
continue modname = signode.get('module') fullname = signode.get('fullname') refname = modname if env.config.viewcode_import: modname = get_full_modname(modname, fullname) if not modname: continue if not has_tag(modname, fullname, env.docname, refname): continue if fullname in names: # only one link per name, please continue names.add(fullname) pagename = '_modules/' + modname.replace('.', '/') onlynode = addnodes.only(expr='html') onlynode += addnodes.pending_xref('', reftype='viewcode', refdomain='std', refexplicit=False, reftarget=pagename, refid=fullname, refdoc=env.docname) onlynode[0] += nodes.inline('', _('[source]'), classes=['viewcode-link']) signode += onlynode def missing_reference(app, env, node, contnode): # resolve our "viewcode" reference nodes -- they need special treatment