def toctree_directive(dirname, arguments, options, content, lineno, content_offset, block_text, state, state_machine): node = nodes.admonition() node['classes'] += ['admonition-toctree'] node += nodes.title('', 'Toctree') para = nodes.paragraph('') node += para ul = nodes.bullet_list() para += ul for line in content: line = line.strip() if not line or line.startswith(':'): continue try: uri, name = resolve_name(line, state.inliner) title = name try: doc = models.Docstring.on_site.get(name=name) if doc.title: title = doc.title except models.Docstring.DoesNotExist: pass entry = nodes.reference('', title, refuri=uri) except ValueError: entry = nodes.reference('', line, name=line, refname=':ref:`%s`' % line) ul += nodes.list_item('', nodes.paragraph('', '', entry)) return [node]
def indexmarkup_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): """Role for PEP/RFC references that generate an index entry.""" env = inliner.document.settings.env if not typ: typ = env.config.default_role else: typ = typ.lower() has_explicit_title, title, target = split_explicit_title(text) # type: bool, unicode, unicode # NOQA 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 = '' # type: unicode 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], []
def generate_footer(self): # @@@ Text is hard-coded for now. # Should be made dynamic (language-dependent). settings = self.document.settings if settings.generator or settings.datestamp or settings.source_link or settings.source_url: text = [] if settings.source_link and settings._source or settings.source_url: if settings.source_url: source = settings.source_url else: source = utils.relative_path(settings._destination, settings._source) text.extend([nodes.reference("", "View document source", refuri=source), nodes.Text(".\n")]) if settings.datestamp: datestamp = time.strftime(settings.datestamp, time.gmtime()) text.append(nodes.Text("Generated on: " + datestamp + ".\n")) if settings.generator: text.extend( [ nodes.Text("Generated by "), nodes.reference("", "Docutils", refuri="http://docutils.sourceforge.net/"), nodes.Text(" from "), nodes.reference("", "reStructuredText", refuri="http://" "docutils.sourceforge.net/rst.html"), nodes.Text(" source.\n"), ] ) return [nodes.paragraph("", "", *text)] else: return None
def filebrief_replace_node(app, doctree, itemtype, items): """ where does the scene take place? here sir, here!!! I saw chaisaw, acid, and the like. what? this is just python code idiot! """ env = app.builder.env nodefuncmap = dict() if itemtype == "functions": nodefuncmap = filebrief_nodefuncmap(doctree) listnode = nodes.bullet_list() for refname, (docname, type, theid) in sorted(items.iteritems()): pnode = nodes.paragraph() if itemtype == "classes": pnode = nodes.paragraph("class ", "class ") refnode = nodes.reference(refname, refname, refdocname=docname, refid=theid) retnode = refnode cnode = nodefuncmap.get(theid) if cnode: (_, fname) = split_func_name(refname) refnode = nodes.reference(fname, fname, refdocname=docname, refid=theid) i = cnode[0].first_child_matching_class(addnodes.desc_name) cnode[0][i] = refnode cnode.children = cnode[0].children retnode = cnode pnode.append(retnode) listnode.append(pnode) return listnode
def generate_footer(self): # @@@ Text is hard-coded for now. # Should be made dynamic (language-dependent). settings = self.document.settings if settings.generator or settings.datestamp or settings.source_link \ or settings.source_url: text = [] if settings.source_link and settings._source \ or settings.source_url: if settings.source_url: source = settings.source_url else: source = utils.relative_path(settings._destination, settings._source) text.extend([ nodes.reference('', 'View document source', refuri=source), nodes.Text('.\n')]) if settings.datestamp: datestamp = time.strftime(settings.datestamp, time.gmtime()) text.append(nodes.Text('Generated on: ' + datestamp + '.\n')) if settings.generator: text.extend([ nodes.Text('Generated by '), nodes.reference('', 'Docutils', refuri= 'http://docutils.sourceforge.net/'), nodes.Text(' from '), nodes.reference('', 'reStructuredText', refuri='http://' 'docutils.sourceforge.net/rst.html'), nodes.Text(' source.\n')]) return [nodes.paragraph('', '', *text)] else: return None
def test_get_full_qualified_name(): env = Mock(domaindata={}) domain = JavaScriptDomain(env) # non-js references node = nodes.reference() assert domain.get_full_qualified_name(node) is None # simple reference node = nodes.reference(reftarget='func') assert domain.get_full_qualified_name(node) == 'func' # with js:module context kwargs = {'js:module': 'module1'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'module1.func' # with js:object context kwargs = {'js:object': 'Class'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'Class.func' # with both js:module and js:object context kwargs = {'js:module': 'module1', 'js:object': 'Class'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'module1.Class.func'
def process_usecase_nodes(app, doctree, fromdocname): if not app.config.usecases_include_usecases: for node in doctree.traverse(usecase): node.parent.remove(node) # Replace all usecaselist nodes with a list of the collected usecases. # Argument each usecase with a backlink to the original location. env = app.builder.env if not hasattr(env, "usecase_all_usecases"): return for node in doctree.traverse(usecaselist): if not app.config.usecases_include_usecases: node.replace_self([]) continue content = [] for usecase_info in env.usecase_all_usecases: para = nodes.paragraph() # Create a reference if app.config.usecases_simple_usecaseslist: para += nodes.strong("UseCase: ", "UseCase: ") # description = ( # _('%s ') % # (usecase_info['usecase-name'])) # para += nodes.Text(description, description) newnode = nodes.reference("", "") innernode = nodes.emphasis(_(usecase_info["usecase-name"]), _(usecase_info["usecase-name"])) newnode["refdocname"] = usecase_info["docname"] newnode["refuri"] = app.builder.get_relative_uri(fromdocname, usecase_info["docname"]) newnode["refuri"] += "#" + usecase_info["target"]["refid"] newnode.append(innernode) para += newnode content.append(para) else: filename = env.doc2path(usecase_info["docname"], base=None) description = _("(The original entry is located in %s, line %d and can be found ") % ( filename, usecase_info["lineno"], ) para += nodes.Text(description, description) newnode = nodes.reference("", "") innernode = nodes.emphasis(_("here"), _("here")) newnode["refdocname"] = usecase_info["docname"] newnode["refuri"] = app.builder.get_relative_uri(fromdocname, usecase_info["docname"]) # newnode['refuri'] += '#' + usecase_info['target']['refid'] newnode.append(innernode) para += newnode para += nodes.Text(".)", ".)") # Insert into the usecaselist content.append(usecase_info["usecase"]) content.append(para) node.replace_self(content)
def xref( typ, rawtext, text, lineno, inliner, options={}, content=[] ): title = target = text titleistarget = True # look if explicit title and target are given with `foo <bar>` syntax brace = text.find('<') if brace != -1: titleistarget = False m = caption_ref_re.match(text) if m: target = m.group(2) title = m.group(1) else: # fallback: everything after '<' is the target target = text[brace+1:] title = text[:brace] link = xref.links[target] if brace != -1: pnode = nodes.reference(target, title, refuri=link[1]) else: pnode = nodes.reference(target, link[0], refuri=link[1]) return [pnode], []
def test_get_full_qualified_name(): env = Mock(domaindata={}) domain = PythonDomain(env) # non-python references node = nodes.reference() assert domain.get_full_qualified_name(node) is None # simple reference node = nodes.reference(reftarget='func') assert domain.get_full_qualified_name(node) == 'func' # with py:module context kwargs = {'py:module': 'module1'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'module1.func' # with py:class context kwargs = {'py:class': 'Class'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'Class.func' # with both py:module and py:class context kwargs = {'py:module': 'module1', 'py:class': 'Class'} node = nodes.reference(reftarget='func', **kwargs) assert domain.get_full_qualified_name(node) == 'module1.Class.func'
def run(self): if 'align' in self.options: if isinstance(self.state, states.SubstitutionDef): # Check for align_v_values. if self.options['align'] not in self.align_v_values: raise self.error( 'Error in "%s" directive: "%s" is not a valid value ' 'for the "align" option within a substitution ' 'definition. Valid values for "align" are: "%s".' % (self.name, self.options['align'], '", "'.join(self.align_v_values))) elif self.options['align'] not in self.align_h_values: raise self.error( 'Error in "%s" directive: "%s" is not a valid value for ' 'the "align" option. Valid values for "align" are: "%s".' % (self.name, self.options['align'], '", "'.join(self.align_h_values))) messages = [] reference = directives.uri(self.arguments[0]) self.options['uri'] = reference reference_node = None if 'target' in self.options: block = states.escape2null( self.options['target']).splitlines() block = [line for line in block] target_type, data = self.state.parse_target( block, self.block_text, self.lineno) if target_type == 'refuri': reference_node = nodes.reference(refuri=data) elif target_type == 'refname': reference_node = nodes.reference( refname=fully_normalize_name(data), name=whitespace_normalize_name(data)) reference_node.indirect_reference_name = data self.state.document.note_refname(reference_node) else: # malformed target messages.append(data) # data is a system message del self.options['target'] image_node = nodes.image(self.block_text, **self.options) if 'iconmargin' in self.options: image_node['classes'].append('iconmargin') set_classes(self.options) if 'iconmarginheight' in self.options: image_node['iconmarginheight'] = \ int(self.options['iconmarginheight']) if 'iconmarginraise' in self.options: image_node['iconmarginraise'] = True if reference_node: reference_node += image_node return messages + [reference_node] else: return messages + [image_node]
def validator(name, raw_text, text, lineno, inliner): """ Link to the JSON Schema documentation for a validator. Arguments: name (str): the name of the role in the document raw_source (str): the raw text (role with argument) text (str): the argument given to the role lineno (int): the line number inliner (docutils.parsers.rst.states.Inliner): the inliner Returns: tuple: a 2-tuple of nodes to insert into the document and an iterable of system messages, both possibly empty """ if text == "$ref": return [nodes.reference(raw_text, text, refuri=ref_url)], [] elif text == "$schema": return [nodes.reference(raw_text, text, refuri=schema_url)], [] # find the header in the validation spec containing matching text header = spec.xpath("//h1[contains(text(), '{0}')]".format(text)) if len(header) == 0: inliner.reporter.warning( "Didn't find a target for {0}".format(text), ) uri = base_url else: if len(header) > 1: inliner.reporter.info( "Found multiple targets for {0}".format(text), ) # get the href from link in the header uri = base_url + header[0].find("a").attrib["href"] reference = nodes.reference(raw_text, text, refuri=uri) return [reference], []
def _parse_ref(rawtext, text, link, inliner): uri, name = resolve_name(link, inliner, postpone=True) if uri: return nodes.reference(text, text, refuri=uri) else: # postpone resolution to generate warnings about failing links ref = nodes.reference(text, text, name=link, refname=':ref:`%s`'%link) return ref
def indexmarkup_role(typ, rawtext, etext, lineno, inliner, options={}, content=[]): env = inliner.document.settings.env if not typ: typ = env.config.default_role text = utils.unescape(etext) targetid = 'index-%s' % env.index_num env.index_num += 1 indexnode = addnodes.index() targetnode = nodes.target('', '', ids=[targetid]) inliner.document.note_explicit_target(targetnode) if typ == 'envvar': env.note_index_entry('single', text, targetid, text) env.note_index_entry('single', 'environment variable; %s' % text, targetid, text) indexnode['entries'] = [('single', text, targetid, text), ('single', 'environment variable; %s' % text, targetid, text)] xref_nodes = xfileref_role(typ, rawtext, etext, lineno, inliner, options, content)[0] return [indexnode, targetnode] + xref_nodes, [] elif typ == 'pep': env.note_index_entry('single', 'Python Enhancement Proposals!PEP %s' % text, targetid, 'PEP %s' % text) indexnode['entries'] = [('single', 'Python Enhancement Proposals!PEP %s' % text, targetid, 'PEP %s' % text)] try: pepnum = int(text) except ValueError: msg = inliner.reporter.error('invalid PEP number %s' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = inliner.document.settings.pep_base_url + 'pep-%04d' % pepnum sn = nodes.strong('PEP '+text, 'PEP '+text) rn = nodes.reference('', '', refuri=ref) rn += sn return [indexnode, targetnode, rn], [] elif typ == 'rfc': env.note_index_entry('single', 'RFC; RFC %s' % text, targetid, 'RFC %s' % text) indexnode['entries'] = [('single', 'RFC; RFC %s' % text, targetid, 'RFC %s' % text)] try: rfcnum = int(text) except ValueError: msg = inliner.reporter.error('invalid RFC number %s' % text, 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('RFC '+text, 'RFC '+text) rn = nodes.reference('', '', refuri=ref) rn += sn return [indexnode, targetnode, rn], []
def review_role(role, rawtext, text, lineno, inliner, options={}, content=[]): """Role linking to a docstring, and displaying its review status""" name = text.strip() try: uri, real_name = resolve_name(name, inliner) doc = models.Docstring.on_site.get(name=real_name) ref = nodes.reference('', name, refuri=uri) cls = models.REVIEW_STATUS_CODES.get(doc.review) if cls: ref['classes'].append(cls) except (models.Docstring.DoesNotExist, ValueError): ref = nodes.reference('', name, name=name, refname=':review:`%s`'%name) return [ref], []
def ref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): """Reimplementation of Sphinx's ref role, but just links unconditionally.""" msg_list = [] match = _ref_re.match(text) if match is not None: text = match.groups()[0].strip() target = "#" + match.groups()[1] pnode = nodes.reference(text, text, internal=True, refuri=target) else: class RefVisitor(nodes.NodeVisitor, object): text = None def __init__(self, document, label): self._label = label super(RefVisitor, self).__init__(document) def visit_target(self, node): if self._label not in node.attributes["ids"]: return else: sibs = node.parent.children next_sib = sibs[sibs.index(node) + 1] # text has to be the figure caption if isinstance(next_sib, nodes.figure): self.text = [ x for x in next_sib.children if isinstance(x, nodes.caption) ][0].astext() elif isinstance( next_sib, nodes.section ): # text has to be the title self.text = next_sib.attributes["names"][0].title() def unknown_visit(self, node): pass visitor = RefVisitor(inliner.document, text) inliner.document.walk(visitor) if visitor.text is None: visitor.text = text.replace("-", " ").title() logger.info( 'ref label {} is missing or not known yet at this point in the document or not immediately before figure or section. Proceeding anyway but title "{}" in this ref may be wrong.'.format( text, visitor.text ) ) target = "#" + text pnode = nodes.reference(text, visitor.text, internal=True, refuri=target) pnode["classes"] = ["reference"] return [pnode], msg_list
def dox(name, rawtext, text, lineno, inliner: Inliner, options={}, content=[]): title, target, hash = parse_link(text) # Otherwise adding classes to the options behaves globally (uh?) _options = dict(options) set_classes(_options) # Avoid assert on adding to undefined member later if 'classes' not in _options: _options['classes'] = [] # Try linking to the whole docs first for basename, url, css_classes in tagfile_basenames: if basename == target: if not title: # TODO: extract title from index page in the tagfile logger.warning("Link to main page `{}` requires a title".format(target)) title = target _options['classes'] += css_classes node = nodes.reference(rawtext, title, refuri=url + hash, **_options) return [node], [] for prefix in symbol_prefixes: if prefix + target in symbol_mapping: link_title, url, css_classes = symbol_mapping[prefix + target] if title: use_title = title elif link_title: use_title = link_title else: if link_title is not None: logger.warning("Doxygen anchor `{}` has no title, using its ID as link title".format(target)) use_title = target _options['classes'] += css_classes node = nodes.reference(rawtext, use_title, refuri=url + hash, **_options) return [node], [] # TODO: print file and line #msg = inliner.reporter.warning( #'Doxygen symbol %s not found' % target, line=lineno) #prb = inliner.problematic(rawtext, rawtext, msg) if title: logger.warning("Doxygen symbol `{}` not found, rendering just link title".format(target)) node = nodes.inline(rawtext, title, **_options) else: logger.warning("Doxygen symbol `{}` not found, rendering as monospace".format(target)) node = nodes.literal(rawtext, target, **_options) return [node], []
def mkYrefNode(target,text,rawtext,role,explicitText,lineno,options={}): """Create hyperlink to yade target. Targets starting with literal 'yade.' are absolute, but the leading 'yade.' will be stripped from the link text. Absolute tergets are supposed to live in page named yade.[module].html, anchored at #yade.[module2].[rest of target], where [module2] is identical to [module], unless mapped over by moduleMap. Other targets are supposed to live in yade.wrapper (such as c++ classes).""" writer=__builtin__.writer # to make sure not shadowed by a local var import string if target.startswith('yade.'): module='.'.join(target.split('.')[0:2]) module2=(module if module not in moduleMap.keys() else moduleMap[module]) if target==module: target='' # to reference the module itself uri=('%%%s#%s'%(module2,target) if writer=='latex' else '%s.html#%s'%(module2,target)) if not explicitText and module!=module2: text=module2+'.'+'.'.join(target.split('.')[2:]) text=string.replace(text,'yade.','',1) elif target.startswith('external:'): exttarget=target.split(':',1)[1] if not explicitText: text=exttarget target=exttarget if '.' in exttarget else 'module-'+exttarget uri=(('%%external#%s'%target) if writer=='latex' else 'external.html#%s'%target) else: uri=(('%%yade.wrapper#yade.wrapper.%s'%target) if writer=='latex' else 'yade.wrapper.html#yade.wrapper.%s'%target) #print writer,uri if 0: refnode=addnodes.pending_xref(rawtext,reftype=role,refexplicit=explicitText,reftarget=target) #refnode.line=lineno #refnode+=nodes.literal(rawtext,text,classes=['ref',role]) return [refnode],[] #ret.rawtext,reftype=role, else: return nodes.reference(rawtext,docutils.utils.unescape(text),refuri=uri,**options)
def ref_role(role, rawtext, text, lineno, inliner, options={}, content=[]): # match :ref:`Bar! <link/link/link>` from rawText p = re.search('`(.*) <(.*)>`', rawtext) if(p): return [nodes.reference(rawtext, p.group(1), refuri= cherrypy.request.script_name + "/" + p.group(2), **options)], [] else: return [], []
def issues_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Use: :issue|bug|feature|support:`ticket number` When invoked as :issue:, turns into just a "#NN" hyperlink to Github. When invoked otherwise, turns into "[Type] <#NN hyperlink>: ". """ # Old-style 'just the issue link' behavior issue_no = utils.unescape(text) ref = "https://github.com/fabric/fabric/issues/" + issue_no link = nodes.reference(rawtext, '#' + issue_no, refuri=ref, **options) ret = [link] # Additional 'new-style changelog' stuff if name in issue_types: which = '[<span class="changelog-%s">%s</span>]' % ( name, name.capitalize() ) ret = [ nodes.raw(text=which, format='html'), nodes.inline(text=" "), link, nodes.inline(text=":") ] return ret, []
def _create_notes_paragraph(self, notes): """ Constructs a paragraph which represents the implementation notes The paragraph consists of text and clickable URL nodes if links were given in the notes. """ para = nodes.paragraph() # links could start with http:// or https:// link_idxs = [m.start() for m in re.finditer('https?://', notes)] start_idx = 0 for link_idx in link_idxs: # assume the notes start with text (could be empty) para.append(nodes.inline(text=notes[start_idx:link_idx])) # create a URL node until the next text or the end of the notes link_end_idx = notes.find(" ", link_idx) if link_end_idx == -1: # In case the notes end with a link without a blank link_end_idx = len(notes) uri = notes[link_idx:link_end_idx + 1] para.append(nodes.reference("", uri, refuri=uri)) start_idx = link_end_idx + 1 # get all text after the last link (could be empty) or all of the # text if no link was given para.append(nodes.inline(text=notes[start_idx:])) return para
def blogref_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """ Inserts a reference to the blog entry of the specified date. Instead of writing ``:doc:`/blog/2011/0406``` it is better to write ``:blogref:`20110406``` because the latter works between Sphinx trees and also supports archived blog entries. """ # thanks to http://docutils.sourceforge.net/docs/howto/rst-roles.html # this code originally from roles.pep_reference_role #~ print 20130315, rawtext, text, utils.unescape(text) has_explicit_title, title, target = split_explicit_title(text) try: date = i2d(int(target)) except ValueError: msg = inliner.reporter.error( 'Invalid text %r: must be an integer date of style "20130315" .' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] #~ print repr(env) #~ raise Exception(20130315) #~ ref = inliner.document.settings.pep_base_url #~ + inliner.document.settings.pep_file_url_template % date) roles.set_classes(options) #~ from django.conf import settings #~ shown_text = settings.SITE.dtos(date) env = inliner.document.settings.env if not has_explicit_title: title = date.strftime(env.settings.get('today_fmt', '%Y-%m-%d')) title = utils.unescape(title) return [nodes.reference(rawtext, title, refuri=get_blog_url(date), **options)], []
def coderef_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) has_explicit_title, title, target = split_explicit_title(text) try: modname, name = target.rsplit('.', 1) except ValueError: raise Exception("Don't know how to import name %s" % target) mod = import_module(modname) try: value = getattr(mod, name, None) except AttributeError: raise Exception("No name '%s' in module '%s'" % (name, modname)) #~ raise Exception("20130908 %s " % lines) if isinstance(value, type): if value.__module__ != modname: raise Exception("20130908 %r != %r" % (value.__module__, modname)) url = srcref(mod) lines, line_no = inspect.getsourcelines(value) if line_no: url += "#" + str(line_no) if not has_explicit_title: pass pnode = nodes.reference(title, title, internal=False, refuri=url) return [pnode], []
def make_link_node(rawtext, app, type, slug, options): """Create a link to a github resource. :param rawtext: Text being replaced with link node. :param app: Sphinx application context :param type: Link type (issues, changeset, etc.) :param slug: ID of the thing to link to :param options: Options dictionary passed to role func. """ try: base = app.config.github_project_url if not base: raise AttributeError if not base.endswith('/'): base += '/' except AttributeError as err: raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) ref = base + type + '/' + slug + '/' set_classes(options) prefix = "#" if type == 'pull': prefix = "PR " + prefix node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref, **options) return node
def make_target_footnote(self, refuri, refs, notes): if refuri in notes: # duplicate? footnote = notes[refuri] assert len(footnote['names']) == 1 footnote_name = footnote['names'][0] else: # original footnote = nodes.footnote() footnote_id = self.document.set_id(footnote) # Use uppercase letters and a colon; they can't be # produced inside names by the parser. footnote_name = 'TARGET_NOTE: ' + footnote_id footnote['auto'] = 1 footnote['names'] = [footnote_name] footnote_paragraph = nodes.paragraph() footnote_paragraph += nodes.reference('', refuri, refuri=refuri) footnote += footnote_paragraph self.document.note_autofootnote(footnote) self.document.note_explicit_target(footnote, footnote) for ref in refs: if isinstance(ref, nodes.target): continue refnode = nodes.footnote_reference(refname=footnote_name, auto=1) refnode['classes'] += self.classes self.document.note_autofootnote_ref(refnode) self.document.note_footnote_ref(refnode) index = ref.parent.index(ref) + 1 reflist = [refnode] if not utils.get_trim_footnote_ref_space(self.document.settings): if self.classes: reflist.insert(0, nodes.inline(text=' ', Classes=self.classes)) else: reflist.insert(0, nodes.Text(' ')) ref.parent.insert(index, reflist) return footnote
def generate_uri_role( role_name, aliases, anchor_text, base_url, interpret_url, validator): '''Creates and register a uri based "interpreted role". Those are similar to the RFC, and PEP ones, and take role_name: name that will be registered aliases: list of alternate names anchor_text: text that will be used, together with the role base_url: base url for the link interpret_url: this, modulo the validated text, will be added to it validator: should return the validated text, or raise ValueError ''' def uri_reference_role(role, rawtext, text, lineno, inliner, options={}, content=[]): try: valid_text = validator(text) except ValueError, e: msg = inliner.reporter.error( e.message % dict(text=text), line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] ref = base_url + interpret_url % valid_text set_classes(options) node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref, **options) return [node], []
def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Link to a GitHub commit. 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. :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. """ app = inliner.document.settings.env.app #app.info('user link %r' % text) try: base = app.config.github_project_url if not base: raise AttributeError if not base.endswith('/'): base += '/' except AttributeError as err: raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) ref = base + text node = nodes.reference(rawtext, text[:6], refuri=ref, **options) return [node], []
def build_contents(self, node, level=0): level += 1 sections = [sect for sect in node if isinstance(sect, nodes.section)] entries = [] autonum = 0 depth = self.startnode.details.get('depth', sys.maxsize) for section in sections: title = section[0] auto = title.get('auto') # May be set by SectNum. entrytext = self.copy_and_filter(title) reference = nodes.reference('', '', refid=section['ids'][0], *entrytext) ref_id = self.document.set_id(reference) entry = nodes.paragraph('', '', reference) item = nodes.list_item('', entry) if ( self.backlinks in ('entry', 'top') and title.next_node(nodes.reference) is None): if self.backlinks == 'entry': title['refid'] = ref_id elif self.backlinks == 'top': title['refid'] = self.toc_id if level < depth: subsects = self.build_contents(section, level) item += subsects entries.append(item) if entries: contents = nodes.bullet_list('', *entries) if auto: contents['classes'].append('auto-toc') return contents else: return []
def _replace_pattern(self, pattern, url_format): project = self.document.settings.env.config.github_project for node in self.document.traverse(nodes.Text): parent = node.parent if isinstance(parent, (nodes.literal, nodes.FixedTextElement)): continue text = str(node) new_nodes = [] last_ref_end = 0 for match in pattern.finditer(text): head = text[last_ref_end:match.start()] if head: new_nodes.append(nodes.Text(head)) last_ref_end = match.end() ref = url_format.format(project, match.group(1)) link = nodes.reference( match.group(0), match.group(0), refuri=ref ) new_nodes.append(link) if not new_nodes: continue tail = text[last_ref_end:] if tail: new_nodes.append(nodes.Text(tail)) parent.replace(node, new_nodes)
def user_role(name, rawtext, text, lineno, inliner, options=None, content=None): """Sphinx role for linking to a user profile. Defaults to linking to Github profiles, but the profile URIS can be configured via the ``issues_user_uri`` config value. Examples: :: :user:`sloria` Anchor text also works: :: :user:`Steven Loria <sloria>` """ options = options or {} content = content or [] has_explicit_title, title, target = split_explicit_title(text) target = utils.unescape(target).strip() title = utils.unescape(title).strip() config = inliner.document.settings.env.app.config if config.issues_user_uri: ref = config.issues_user_uri.format(user=target) else: ref = "https://github.com/{0}".format(target) if has_explicit_title: text = title else: text = "@{0}".format(target) link = nodes.reference(text=text, refuri=ref, **options) return [link], []
def resolve_api_name(n, rawtext, text, lineno, inliner, options={}, content=[]): if docutils is None: raise AssertionError('requires docutils') # Check if there's separate text & targets m = _TARGET_RE.match(text) if m: text, target = m.groups() else: target = text # node in monotype font text = utils.unescape(text) node = nodes.literal(rawtext, text, **options) # Get the resolver from the register and create an url from it. try: url = api_register[name].get_url(target) except IndexError as exc: msg = inliner.reporter.warning(str(exc), line=lineno) if problematic: prb = inliner.problematic(rawtext, text, msg) return [prb], [msg] else: return [node], [] if url is not None: node = nodes.reference(rawtext, '', node, refuri=url, **options) return [node], []
def process_req_nodes(app, doctree, fromdocname): for node in doctree.traverse(req): if not app.config.req_include_reqs: node.parent.remove(node) # Replace all reqtrace nodes with a list of the collected reqs. # Augment each req with a backlink to the original location. env = app.builder.env for node in doctree.traverse(reqtrace): if not app.config.req_include_reqs: node.replace_self([]) continue content = [] reqtable = nodes.table(classes=['reqtable']) tgroup = nodes.tgroup(cols=3) reqtable += tgroup tgroup += nodes.colspec(colwidth=15, classes=['reqid']) tgroup += nodes.colspec(colwidth=15, classes=['section']) tgroup += nodes.colspec(colwidth=70, classes=['evidence']) thead = nodes.thead() tgroup += thead append_row(thead, ['Req', 'Section', 'Evidence']) tbody = nodes.tbody() tgroup += tbody sorted_req = sorted(env.req_all_reqs, key=lambda req: req['reqid']) for req_info in sorted_req: refpara = nodes.paragraph() refpara += nodes.Text('', '') # Create a reference try: newnode = nodes.reference('', '') section = req_info['section'] section_name = '' pprint(section) if section.get('secnumber'): section_name += (('%s' + self.secnumber_suffix) % '.'.join(map(str, node['secnumber']))) section_name += section[section.first_child_matching_class( title)][0].astext() innernode = nodes.emphasis(section_name, section_name) newnode['refdocname'] = req_info['docname'] newnode['refuri'] = app.builder.get_relative_uri( fromdocname, req_info['docname']) newnode['refuri'] += '#' + req_info['target']['refid'] newnode.append(innernode) refpara += newnode refpara += nodes.Text('', '') except: continue append_row(tbody, [req_info['reqid'], refpara, req_info['evidence']]) content.append(reqtable) node.replace_self(content)
def commit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): ref = 'https://github.com/scrapy/scrapy/commit/' + text set_classes(options) node = nodes.reference(rawtext, 'commit ' + text, refuri=ref, **options) return [node], []
def rev_role(name, rawtext, text, lineno, inliner, options={}, content=[]): ref = 'http://hg.scrapy.org/scrapy/changeset/' + text set_classes(options) node = nodes.reference(rawtext, 'r' + text, refuri=ref, **options) return [node], []
def view_meta_admonition(admonition_name, name=None): """List all found admonition from all the rst files found in directory view_meta_admonition is called by the 'meta' url: /__XXXXXXX__ where XXXXXXX represents and admonition name, like: * todo * warning * danger * ... .. note:: this function may works for any docutils node, not only admonition Keyword Arguments: :admonition_name: (str) -- name of the admonition """ print(("meta admo: %s - %s" % (admonition_name, name))) admonition = None if admonition_name == 'todo': admonition = todo elif admonition_name == 'done': admonition = done elif hasattr(nodes, admonition_name): admonition = getattr(nodes, admonition_name) else: return abort(404) doc2_content = "" doc2_output, doc2_pub = docutils.core.publish_programmatically( source_class=io.StringInput, source=doc2_content, source_path=None, destination_class=io.StringOutput, destination=None, destination_path=None, reader=None, reader_name='standalone', parser=None, parser_name='restructuredtext', writer=HisWriter(), writer_name=None, settings=None, settings_spec=None, settings_overrides=None, config_section=None, enable_exit_status=False) section1 = nodes.section("{0}_list_file".format(admonition_name)) doc2_pub.reader.document.append(section1) title1 = nodes.title("{0} LIST".format(admonition_name.upper()), "{0} LIST".format(admonition_name.upper())) doc2_pub.reader.document.append(title1) if name is None: rst_files = [ filename[2:-4] for filename in sorted(glob.glob("./*.rst")) ] rst_files.reverse() else: rst_files = [ filename[2:-4] for filename in sorted(glob.glob("./{0}.rst".format(name))) ] for file in rst_files: file_title = False file_handle = open(file + '.rst', 'r', encoding='utf-8') file_content = file_handle.read() file_handle.close() file_content = file_content output, pub = docutils.core.publish_programmatically( source_class=io.StringInput, source=file_content, source_path=None, destination_class=io.StringOutput, destination=None, destination_path=None, reader=None, reader_name='standalone', parser=None, parser_name='restructuredtext', writer=None, writer_name='html', settings=None, settings_spec=None, settings_overrides=None, config_section=None, enable_exit_status=False) my_settings = pub.get_settings() parser = docutils.parsers.rst.Parser() document = docutils.utils.new_document('test', my_settings) parser.parse(file_content, document) for node in document.traverse(admonition): if not file_title: file_title = True # new section section2 = nodes.section(file) doc2_pub.reader.document.append(section2) # add link to the originating file paragraph = nodes.paragraph() file_target = nodes.target(ids=[file], names=[file], refuri="/" + file) file_ref = nodes.reference(file, file, name=file, refuri="/" + file) paragraph.append(nodes.Text("in ")) paragraph.append(file_ref) paragraph.append(file_target) paragraph.append(nodes.Text(":")) doc2_pub.reader.document.append(paragraph) #doc2_pub.reader.document.append(file_target) doc2_pub.reader.document.append(node) doc2_pub.apply_transforms() doc2_pub.writer.write(doc2_pub.document, doc2_pub.destination) doc2_pub.writer.assemble_parts() if name is None: display_file_name = '__{0}__'.format(admonition_name) extended_name = None else: display_file_name = '{0}'.format(name) extended_name = '__{0}__'.format(admonition_name) return template('page', type="view", name=display_file_name, content=doc2_pub.writer.parts['html_body'])
def github_link_node(name, rawtext, options=()): try: base = github_project_url if not base: raise AttributeError except AttributeError, err: raise ValueError( 'github_project_url configuration value is not set (%s)' % str(err)) slash = '/' if base[-1] != '/' else '' ref = base + slash + rawtext if not options: options = {} set_classes(options) node = nodes.reference(name, utils.unescape(name), refuri=ref, **options) return node # Return filename for example ex in the current language. def xapian_code_example_filename(ex): return "code/%s/%s%s" % (highlight_language, ex, ext) # Return the command to show in the generated docs. def xapian_code_example_command(ex): if highlight_language == 'lua': return "lua %s" % xapian_code_example_filename(ex) elif highlight_language == 'perl': return "perl %s" % xapian_code_example_filename(ex) elif highlight_language == 'php':
def assemble_doctree(self, docname, title, author, appendices): # FIXME: use the new inline_all_trees from Sphinx. # check how the LaTeX builder does it. self.docnames = set([docname]) self.info(darkgreen(docname) + " ", nonl=1) def process_tree(docname, tree): tree = tree.deepcopy() for toctreenode in tree.traverse(addnodes.toctree): newnodes = [] includefiles = map(str, toctreenode['includefiles']) for includefile in includefiles: try: self.info(darkgreen(includefile) + " ", nonl=1) subtree = process_tree( includefile, self.env.get_doctree(includefile)) self.docnames.add(includefile) except Exception: self.warn('%s: toctree contains ref to nonexisting file %r'\ % (docname, includefile)) else: sof = addnodes.start_of_file(docname=includefile) sof.children = subtree.children newnodes.append(sof) toctreenode.parent.replace(toctreenode, newnodes) return tree tree = self.env.get_doctree(docname) tree = process_tree(docname, tree) self.docutils_languages = {} if self.config.language: self.docutils_languages[self.config.language] = \ get_language_available(self.config.language)[2] if self.opts.get('pdf_use_index', self.config.pdf_use_index): # Add index at the end of the document # This is a hack. create_index creates an index from # ALL the documents data, not just this one. # So, we preserve a copy, use just what we need, then # restore it. #from pudb import set_trace; set_trace() t = copy(self.env.indexentries) try: self.env.indexentries = { docname: self.env.indexentries[docname + '-gen'] } except KeyError: self.env.indexentries = {} for dname in self.docnames: self.env.indexentries[dname] = t.get(dname, []) genindex = self.env.create_index(self) self.env.indexentries = t # EOH (End Of Hack) if genindex: # No point in creating empty indexes index_nodes = genindex_nodes(genindex) tree.append( nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.append(index_nodes) # This is stolen from the HTML builder's prepare_writing function self.domain_indices = [] # html_domain_indices can be False/True or a list of index names indices_config = self.config.pdf_domain_indices if indices_config and hasattr(self.env, 'domains'): for domain in self.env.domains.itervalues(): for indexcls in domain.indices: indexname = '%s-%s' % (domain.name, indexcls.name) if isinstance(indices_config, list): if indexname not in indices_config: continue # deprecated config value if indexname == 'py-modindex' and \ not self.config.pdf_use_modindex: continue content, collapse = indexcls(domain).generate() if content: self.domain_indices.append( (indexname, indexcls, content, collapse)) # self.domain_indices contains a list of indices to generate, like # this: # [('py-modindex', # <class 'sphinx.domains.python.PythonModuleIndex'>, # [(u'p', [[u'parrot', 0, 'test', u'module-parrot', 'Unix, Windows', # '', 'Analyze and reanimate dead parrots.']])], True)] # Now this in the HTML builder is passed onto write_domain_indices. # We handle it right here for indexname, indexcls, content, collapse in self.domain_indices: indexcontext = dict( indextitle=indexcls.localname, content=content, collapse_index=collapse, ) # In HTML this is handled with a Jinja template, domainindex.html # We have to generate docutils stuff right here in the same way. self.info(' ' + indexname, nonl=1) print output = ['DUMMY', '=====', '', '.. _modindex:\n\n'] t = indexcls.localname t += '\n' + '=' * len(t) + '\n' output.append(t) for letter, entries in content: output.append('.. cssclass:: heading4\n\n%s\n\n' % letter) for (name, grouptype, page, anchor, extra, qualifier, description) in entries: if qualifier: q = '[%s]' % qualifier else: q = '' if extra: e = '(%s)' % extra else: e = '' output.append('`%s <#%s>`_ %s %s' % (name, anchor, e, q)) output.append(' %s' % description) output.append('') dt = docutils.core.publish_doctree('\n'.join(output))[1:] dt.insert(0, nodes.raw(text='OddPageBreak twoColumn', format='pdf')) tree.extend(dt) if appendices: tree.append( nodes.raw(text='OddPageBreak %s' % self.page_template, format='pdf')) self.info() self.info('adding appendixes...', nonl=1) for docname in appendices: self.info(darkgreen(docname) + " ", nonl=1) appendix = self.env.get_doctree(docname) appendix['docname'] = docname tree.append(appendix) self.info('done') self.info() self.info("resolving references...") #print tree #print '--------------' self.env.resolve_references(tree, docname, self) #print tree for pendingnode in tree.traverse(addnodes.pending_xref): # This needs work, need to keep track of all targets # so I don't replace and create hanging refs, which # crash if pendingnode.get('reftarget',None) == 'genindex'\ and self.config.pdf_use_index: pendingnode.replace_self( nodes.reference(text=pendingnode.astext(), refuri=pendingnode['reftarget'])) # FIXME: probably need to handle dangling links to domain-specific indexes else: # FIXME: This is from the LaTeX builder and I still don't understand it # well, and doesn't seem to work # resolve :ref:s to distant tex files -- we can't add a cross-reference, # but append the document name docname = pendingnode['refdocname'] sectname = pendingnode['refsectname'] newnodes = [nodes.emphasis(sectname, sectname)] for subdir, title in self.titles: if docname.startswith(subdir): newnodes.append(nodes.Text(_(' (in '), _(' (in '))) newnodes.append(nodes.emphasis(title, title)) newnodes.append(nodes.Text(')', ')')) break else: pass pendingnode.replace_self(newnodes) #else: #pass return tree
def _build_summary(self, matrix, content): """Constructs the docutils content for the summary of the support matrix. The summary consists of a giant table, with one row for each feature, and a column for each backend driver. It provides an 'at a glance' summary of the status of each driver """ summary_title = nodes.subtitle(text="Summary") summary = nodes.table() cols = len(matrix.targets.keys()) cols += 2 summary_group = nodes.tgroup(cols=cols) summary_body = nodes.tbody() summary_head = nodes.thead() for i in range(cols): summary_group.append(nodes.colspec(colwidth=1)) summary_group.append(summary_head) summary_group.append(summary_body) summary.append(summary_group) content.append(summary_title) content.append(summary) # This sets up all the column headers - two fixed # columns for feature name & status header = nodes.row() blank = nodes.entry() blank.append(nodes.emphasis(text="Feature")) header.append(blank) blank = nodes.entry() blank.append(nodes.emphasis(text="Status")) header.append(blank) summary_head.append(header) # then one column for each backend driver impls = matrix.targets.keys() impls = sorted(impls) for key in impls: target = matrix.targets[key] implcol = nodes.entry() header.append(implcol) if target.link: uri = target.link target_ref = nodes.reference("", refuri=uri) target_txt = nodes.inline() implcol.append(target_txt) target_txt.append(target_ref) target_ref.append(nodes.strong(text=target.title)) else: implcol.append(nodes.strong(text=target.title)) # We now produce the body of the table, one row for # each feature to report on for feature in matrix.features: item = nodes.row() # the hyperlink target name linking to details feature_id = re.sub(RE_PATTERN, "_", feature.key) # first the fixed columns for title/status key_col = nodes.entry() item.append(key_col) key_ref = nodes.reference(refid=feature_id) key_txt = nodes.inline() key_col.append(key_txt) key_txt.append(key_ref) key_ref.append(nodes.strong(text=feature.title)) status_col = nodes.entry() item.append(status_col) status_col.append( nodes.inline(text=feature.status, classes=["sp_feature_" + feature.status])) # and then one column for each backend driver impls = matrix.targets.keys() impls = sorted(impls) for key in impls: target = matrix.targets[key] impl = feature.implementations[key] impl_col = nodes.entry() item.append(impl_col) key_id = re.sub(RE_PATTERN, "_", "{}_{}".format(feature.key, key)) impl_ref = nodes.reference(refid=key_id) impl_txt = nodes.inline() impl_col.append(impl_txt) impl_txt.append(impl_ref) status = STATUS_DICT.get(impl.status, "") impl_ref.append( nodes.literal( text=status, classes=["sp_impl_summary", "sp_impl_" + impl.status])) summary_body.append(item)
def make_document(self, doc_strings): """make doctree representation of collected fragments""" opt = self.opt big_doc = publish_doctree("") self.document = big_doc big_doc += nodes.title(text="Plugins listing generated %s" % time.asctime()) contents = nodes.container() if opt.include_contents: big_doc += nodes.topic('', nodes.title(text='Contents'), contents) if not opt.no_summary: def_list = nodes.definition_list() alpha_list = nodes.paragraph() big_doc += nodes.section('', nodes.title(text="Plugins summary"), alpha_list, def_list) last_alpha = '' for doc in doc_strings: section = nodes.section() big_doc += section section += nodes.title(text=doc[0]) self.add_ids(section) if not opt.no_summary: firstpara = (self.first_text(doc[2]) or nodes.paragraph(text='No summary found')) reference = nodes.reference('', refid=section['ids'][0], name=doc[0], anonymous=1) reference += nodes.Text(doc[0]) def_list += nodes.definition_list_item( '', nodes.term('', '', reference), nodes.definition('', firstpara)) # add letter quick index entry if needed if doc[0][0].upper() != last_alpha: last_alpha = doc[0][0].upper() self.add_ids(reference) alpha_list += nodes.reference('', nodes.Text(last_alpha + ' '), refid=reference['ids'][0], name=doc[0], anonymous=1) for element in doc[2]: # if the docstring has titles, we need another level if element.tagname == 'title': subsection = nodes.section() section += subsection section = subsection break for element in doc[2]: try: section += element.deepcopy() except TypeError: err('Element.deepcopy() failed, dropped element for %s\n' % doc[0]) if opt.include_contents: contents.details = {'text': 'Contents here'} self.add_ids(big_doc) transform = Contents(big_doc, contents) transform.apply() return big_doc
def role(name, rawtext, text, lineno, inliner, options={}, content=[]): url = urlpattern.format(text) xtext = textpattern.format(text) node = nodes.reference(rawtext, xtext, refuri=url, **options) return [node], []
def get_javadoc_ref(app, rawtext, text): javadoc_url_map = app.config.javadoc_url_map # Add default Java SE sources if not javadoc_url_map.get("java"): javadoc_url_map["java"] = ("http://docs.oracle.com/javase/6/docs/api", 'javadoc') if not javadoc_url_map.get("javax"): javadoc_url_map["javax"] = ("http://docs.oracle.com/javase/6/docs/api", 'javadoc') if not javadoc_url_map.get("org.xml"): javadoc_url_map["org.xml"] = ( "http://docs.oracle.com/javase/6/docs/api", 'javadoc') if not javadoc_url_map.get("org.w3c"): javadoc_url_map["org.w3c"] = ( "http://docs.oracle.com/javase/6/docs/api", 'javadoc') source = None package = '' method = None if '(' in text: # If the javadoc contains a line like this: # {@link #sort(List)} # there is no package so the text.rindex will fail try: split_point = text.rindex('.', 0, text.index('(')) method = text[split_point + 1:] text = text[:split_point] except ValueError: pass for pkg, (baseurl, ext_type) in javadoc_url_map.items(): if text.startswith(pkg + '.') and len(pkg) > len(package): source = baseurl, ext_type package = pkg if not source: return None baseurl, ext_type = source package_parts = [] cls_parts = [] for part in text.split('.'): if cls_parts or part[0].isupper(): cls_parts.append(part) else: package_parts.append(part) package = '.'.join(package_parts) cls = '.'.join(cls_parts) if not baseurl.endswith('/'): baseurl = baseurl + '/' if ext_type == 'javadoc': if not cls: cls = 'package-summary' source = baseurl + package.replace('.', '/') + '/' + cls + '.html' if method: source = source + '#' + method elif ext_type == 'sphinx': if not cls: cls = 'package-index' source = baseurl + package.replace('.', '/') + '/' + cls.replace( '.', '-') + '.html' if method: source = source + '#' + package + '.' + cls + '.' + method else: raise ValueError('invalid target specifier ' + ext_type) title = '.'.join(filter(None, (package, cls, method))) node = nodes.reference(rawtext, '') node['refuri'] = source node['reftitle'] = title return node
def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): has_t, title, target = split_explicit_title(text) title = utils.unescape(title) target = utils.unescape(target) refnode = nodes.reference(title, title, refuri=SOURCE_URI % target) return [refnode], []
def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): issue = utils.unescape(text) text = 'bpo-' + issue refnode = nodes.reference(text, text, refuri=ISSUE_URI % issue) return [refnode], []
def get_reference_node(self, ref): node = nodes.inline(' ', ' ', classes=[ref.type, 'bibcite']) namestyler = pybtex.style.names.plain.NameStyle() namestyler = pybtex.style.names.lastfirst.NameStyle() plaintext = pybtex.backends.plaintext.Backend() # Authors authors = ref.persons.get('author', []) for i, author in enumerate(authors): authortext = namestyler.format( author, abbr=True).format().render(plaintext) authortext = authortext.replace('{', '') authortext = authortext.replace('}', '') authortext = authortext.decode('latex') text = authortext text = text.strip() auth_node = latex_to_nodes(text) auth_node['classes'].append('author') node += auth_node if i + 1 < len(authors): node += nodes.inline(', ', ', ') else: ending = '%s ' % ('' if text.endswith('.') else '.') node += nodes.inline(ending, ending) # Title title = ref.fields.get('title') if title is None: title = ref.fields.get('key') if title: title = title.decode('latex') title = title.replace('{', '') title = title.replace('}', '') node += nodes.inline(title, title, classes=['bib_title']) node += nodes.inline('. ', '. ') # @phdthesis if ref.type == 'phdthesis': school = ref.fields.get('school') school = school.decode('latex') text = 'PhD Thesis, %s, ' % school node += nodes.inline(text, text) # Publication pub = ref.fields.get('journal') if not pub: pub = ref.fields.get('booktitle') if pub: pub = pub.decode('latex') pub = pub.replace('{', '') pub = pub.replace('}', '') node += nodes.emphasis(pub, pub, classes=['publication']) node += nodes.inline(' ', ' ') vol = ref.fields.get('volume') pages = ref.fields.get('pages') year = ref.fields.get('year') url = ref.fields.get('url') if pub is None: howpub = ref.fields.get('howpublished') if howpub is not None and howpub.startswith('\url{'): url = howpub[5:-1] refnode = nodes.reference('', '', internal=False, refuri=url) refnode += nodes.Text(url, url) node += refnode if vol or pages or year: node += nodes.inline(', ', ', ') if vol: vol = vol.decode('latex') node += nodes.inline(vol, vol, classes=['bib_vol']) node += nodes.inline(':', ':') if pages: pages = pages.decode('latex') node += nodes.inline(pages, pages, classes=['pages']) if year: year = year.decode('latex') node += nodes.inline(' (', ' (') node += nodes.inline(year, year, classes=['year']) node += nodes.inline(')', ')') if pub is not None and url: if url.startswith('{') and url.endswith('}'): url = url[1:-1] refnode = nodes.reference('', '', internal=False, refuri=url) node += nodes.inline(' ', ' ') refnode += nodes.Text(url, url) node += refnode node += nodes.inline('.', '.') return node
def url_role(name, rawtext, text, lineno, inliner, options={}, content=[]): uri = text display = 'url' node = nodes.literal('', '') node += nodes.reference(rawtext, name, refuri=uri, **options) return [node], []
def run(self): """ builds the todo text """ sett = self.state.document.settings language_code = sett.language_code lineno = self.lineno env = self.state.document.settings.env if hasattr( self.state.document.settings, "env") else None docname = None if env is None else env.docname if docname is not None: docname = docname.replace("\\", "/").split("/")[-1] legend = "{0}:{1}".format(docname, lineno) else: legend = '' if not self.options.get('class'): self.options['class'] = ['admonition-todoext'] # link to issue issue = self.options.get('issue', "").strip() if issue is not None and len(issue) > 0: if hasattr(sett, "extlinks"): extlinks = sett.extlinks elif env is not None and hasattr(env.config, "extlinks"): extlinks = env.config.extlinks else: # pragma: no cover available = "\n".join(sorted(sett.__dict__.keys())) available2 = "\n".join(sorted( env.config.__dict__.keys())) if env is not None else "-" mes = ( "extlinks (wih a key 'issue') is not defined in the " "documentation settings, available in sett\n{0}\nCONFIG\n{1}" ) raise ValueError( # pragma: no cover mes.format(available, available2)) if "issue" not in extlinks: raise KeyError( # pragma: no cover "key 'issue' is not present in extlinks") url, label = extlinks["issue"] url = url % str(issue) lab = label.format(issue) linkin = nodes.reference(lab, locale_(lab), refuri=url) link = nodes.paragraph() link += linkin else: link = None # cost cost = self.options.get('cost', "").strip() if cost: # pragma: no cover try: fcost = float(cost) except ValueError: raise ValueError( "unable to convert cost '{0}' into float".format(cost)) else: fcost = 0.0 # priority prio = self.options.get('priority', "").strip() # hidden hidden = self.options.get( 'hidden', "false").strip().lower() in {'true', '1', ''} # body (todoext, ) = super(TodoExt, self).run() if isinstance(todoext, nodes.system_message): return [todoext] # link if link: todoext += link # title title = self.options.get('title', "").strip() todotag = self.options.get('tag', '').strip() if len(title) > 0: title = ": " + title # prefix prefix = TITLES[language_code]["todo"] tododate = self.options.get('date', "").strip() todorelease = self.options.get('release', "").strip() infos = [] if len(todotag) > 0: infos.append(todotag) if len(prio) > 0: infos.append('P=%s' % prio) if fcost > 0: if int(fcost) == fcost: infos.append('C=%d' % int(fcost)) else: infos.append('C=%1.1f' % fcost) if todorelease: infos.append('v{0}'.format(todorelease)) if tododate: infos.append(tododate) if infos: prefix += "({0})".format(" - ".join(infos)) # main node title = nodes.title(text=locale_(prefix + title)) todoext.insert(0, title) todoext['todotag'] = todotag todoext['todocost'] = fcost todoext['todoprio'] = prio todoext['todohidden'] = hidden todoext['tododate'] = tododate todoext['todorelease'] = todorelease todoext['todotitle'] = self.options.get('title', "").strip() set_source_info(self, todoext) if hidden: todoext['todoext_copy'] = todoext.deepcopy() todoext.clear() if env is not None: targetid = 'indextodoe-%s' % env.new_serialno('indextodoe') targetnode = nodes.target(legend, '', ids=[targetid]) set_source_info(self, targetnode) self.state.add_target(targetid, '', targetnode, lineno) # index node index = self.options.get('index', None) if index is not None: indexnode = addnodes.index() indexnode['entries'] = ne = [] indexnode['inline'] = False set_source_info(self, indexnode) for entry in index.split(","): ne.extend(process_index_entry(entry, targetid)) else: indexnode = None else: targetnode = None indexnode = None return [a for a in [indexnode, targetnode, todoext] if a is not None]
def missing_reference(app, env, node, contnode): # type: (Sphinx, BuildEnvironment, nodes.Node, nodes.Node) -> None """Attempt to resolve a missing reference via intersphinx references.""" target = node['reftarget'] inventories = InventoryAdapter(env) objtypes = None # type: List[unicode] if node['reftype'] == 'any': # we search anything! objtypes = ['%s:%s' % (domain.name, objtype) for domain in env.domains.values() for objtype in domain.object_types] domain = None else: domain = node.get('refdomain') if not domain: # only objects in domains are in the inventory return objtypes = env.get_domain(domain).objtypes_for_role(node['reftype']) if not objtypes: return objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] if 'std:cmdoption' in objtypes: # until Sphinx-1.6, cmdoptions are stored as std:option objtypes.append('std:option') to_try = [(inventories.main_inventory, target)] if domain: full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) if full_qualified_name: to_try.append((inventories.main_inventory, full_qualified_name)) in_set = None if ':' in target: # first part may be the foreign doc set name setname, newtarget = target.split(':', 1) if setname in inventories.named_inventory: in_set = setname to_try.append((inventories.named_inventory[setname], newtarget)) if domain: node['reftarget'] = newtarget full_qualified_name = env.get_domain(domain).get_full_qualified_name(node) if full_qualified_name: to_try.append((inventories.named_inventory[setname], full_qualified_name)) for inventory, target in to_try: for objtype in objtypes: if objtype not in inventory or target not in inventory[objtype]: continue proj, version, uri, dispname = inventory[objtype][target] if '://' not in uri and node.get('refdoc'): # get correct path in case of subdirectories uri = path.join(relative_path(node['refdoc'], '.'), uri) if version: reftitle = _('(in %s v%s)') % (proj, version) else: reftitle = _('(in %s)') % (proj,) newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle=reftitle) if node.get('refexplicit'): # use whatever title was given newnode.append(contnode) elif dispname == '-' or \ (domain == 'std' and node['reftype'] == 'keyword'): # use whatever title was given, but strip prefix title = contnode.astext() if in_set and title.startswith(in_set + ':'): newnode.append(contnode.__class__(title[len(in_set) + 1:], title[len(in_set) + 1:])) else: newnode.append(contnode) else: # else use the given display name (used for :ref:) newnode.append(contnode.__class__(dispname, dispname)) return newnode # at least get rid of the ':' in the target if no explicit title given if in_set is not None and not node.get('refexplicit', True): if len(contnode) and isinstance(contnode[0], nodes.Text): contnode[0] = nodes.Text(newtarget, contnode[0].rawsource)
def cite(self, cmd, refuri, global_keys=None): """ Return a docutils Node consisting of properly formatted citations children nodes. """ if global_keys is not None: self.global_keys = global_keys bo, bc = self.config['brackets'] sep = u'%s ' % self.config['separator'] style = self.config['style'] all_auths = (cmd.endswith('s')) alt = (cmd.startswith('alt') or \ (cmd.startswith('alp')) or \ (style == 'citeyear')) if (cmd.startswith('p') or cmd == 'yearpar') and style != 'super': node = nodes.inline(bo, bo, classes=['citation']) else: node = nodes.inline('', '', classes=['citation']) if self.pre: pre = u"%s " % self.pre.decode('latex') node += nodes.inline(pre, pre, classes=['pre']) for i, ref in enumerate(self.refs): authors = ref.persons.get('author', []) author_text = self.get_author(authors, all_auths).decode('latex') lrefuri = refuri + '#citation-' + nodes.make_id(ref.key) if i > 0 and i < len(self.refs): if style == "authoryear": node += nodes.inline(sep, sep) else: if style == "super": node += nodes.superscript(', ', ', ') else: node += nodes.inline(', ', ', ') if cmd == 'title': title = ref.fields.get('title') if title is None: title = ref.fields.get('key', '') author_text = title if (style == "authoryear" and (cmd.startswith('p') or cmd.startswith('alp'))) or \ (cmd.startswith('t') or cmd.startswith('alt') or cmd.startswith('author')): node += nodes.reference(author_text, author_text, internal=True, refuri=lrefuri) if cmd.startswith('p') or cmd.startswith('alp'): node += nodes.inline(', ', ', ') else: node += nodes.inline(' ', ' ') # Add in either the year or the citation number if cmd == 'title': pass elif cmd.startswith('author'): pass else: if style != 'authoryear': num = self.get_ref_num(ref.key) else: num = ref.fields.get('year') refnode = nodes.reference(str(num), str(num), internal=True, refuri=lrefuri) if cmd.startswith('t') and style != 'super': node += nodes.inline(bo, bo) if style == 'super': node += nodes.superscript('', '', refnode) else: node += refnode if cmd.startswith('t') and style != 'super': node += nodes.inline(bc, bc) if self.post: post = u", %s" % self.post.decode('latex') node += nodes.inline(post, post, classes=['post']) if (cmd.startswith('p') or cmd == 'yearpar') and style != 'super': node += nodes.inline(bc, bc, classes=['citation']) return node
def run(self): env = self.state.document.settings.env items = [] data = list(csv.reader(self.content)) for row in data: if not row: continue name, page, image = row link = page.strip() if not link.startswith('http') and not link.startswith('/'): link = '/{}'.format(link) if '.html' not in link: link += '.html' items.append({ 'name': name.strip(), 'link': link, 'image': '/images/{}'.format(image.strip()), }) col_widths = self.get_column_widths(3) title, messages = self.make_title() table = nodes.table() # Set up column specifications based on widths tgroup = nodes.tgroup(cols=3) table += tgroup tgroup.extend( nodes.colspec(colwidth=col_width) for col_width in col_widths) tbody = nodes.tbody() tgroup += tbody rows = [] for value in grouper(3, items): trow = nodes.row() for cell in value: entry = nodes.entry() if cell is None: entry += nodes.paragraph() trow += entry continue name = cell['name'] link = cell['link'] image = cell['image'] reference_node = nodes.reference(refuri=link) img = nodes.image(uri=directives.uri(image), alt=name) img['classes'].append('component-image') reference_node += img para = nodes.paragraph() para += reference_node entry += para trow += entry rows.append(trow) trow = nodes.row() for cell in value: entry = nodes.entry() if cell is None: entry += nodes.paragraph() trow += entry continue name = cell['name'] link = cell['link'] ref = nodes.reference(name, name, refuri=link) para = nodes.paragraph() para += ref entry += para trow += entry rows.append(trow) tbody.extend(rows) table['classes'] += [] self.add_name(table) if title: table.insert(0, title) return [table] + messages
def pegboard_directive(*args): pegtable = build_pegtable() pegtable.sort(pegcmp) # Python doesn't like this, as 'class' is reserved # table = nodes.table(class='pegboard') table = nodes.table() table['class'] = 'pegboard' tgroup = nodes.tgroup(cols=6) table += tgroup thead = nodes.thead() tgroup += thead row = nodes.row() thead += row for col in ['Status', 'Name', 'Topic', 'Authors', 'Stakeholders', 'Files']: entry = nodes.entry() row += entry para = nodes.paragraph() entry += para para += nodes.Text(col) tbody = nodes.tbody() tgroup += tbody for peg in pegtable: status = peg['status'].split() row = nodes.row() if status: peg_class = 'peg-' + status[0].lower() # Python doesn't like this, as 'class' is reserved # row = nodes.row(class=peg_class) row['class'] = peg_class tbody += row def get_author(s): if config.pegboard_authors.has_key(s): return config.pegboard_authors[s] else: return s _authors = [get_author(s) for s in peg['authors']] _stakeholders = [get_author(s) for s in peg['stakeholders']] ref = nodes.reference(refuri=peg['dir']+'/'+peg['html']) text = nodes.Text(peg['dir'].split('--')[0]) ref += text status_field = peg['status'].split() status_comment = nodes.Text(string.join(status_field[1:])) status_emph = nodes.emphasis() status_emph += status_comment status = [ nodes.Text(status_field[0] + ' '), status_emph ] # massive uglification here because cpython doesn't like # the use of the reserved word 'class'. ;-/. Gotta think of # something cuter. #row += td(status, class='peg_status_field') #row += td(ref, class='peg_name_field') #row += td(peg['topic'].split(':')[-1], class='peg_topic_field') #row += td(string.join(_authors, ', '), class='peg_authors_field') #row += td(string.join(_stakeholders, ', '), class='peg_stakeholders_field') temp = td(status); temp['class'] = 'peg_status_field' row += temp temp = td(ref); temp['class'] = 'peg_name_field' row += temp temp = td(peg['topic'].split(':')[-1]); temp['class'] = 'peg_topic_field' row += temp temp = td(string.join(_authors, ', ')); temp['class'] = 'peg_authors_field' row += temp temp = td(string.join(_stakeholders, ', ')); temp['class'] = 'peg_stakeholders_field' row += temp row += make_files(peg) return [table]
def process_todoext_nodes(app, doctree, fromdocname): """ process_todoext_nodes """ if not app.config['todoext_include_todosext']: for node in doctree.traverse(todoext_node): node.parent.remove(node) # Replace all todoextlist nodes with a list of the collected todosext. # Augment each todoext with a backlink to the original location. env = app.builder.env if hasattr(env, "settings") and hasattr(env.settings, "language_code"): lang = env.settings.language_code else: lang = "en" orig_entry = TITLES[lang]["original entry"] todomes = TITLES[lang]["todomes"] allowed_tsort = {'date', 'prio', 'title', 'release', 'source'} if not hasattr(env, 'todoext_all_todosext'): env.todoext_all_todosext = [] for ilist, node in enumerate(doctree.traverse(todoextlist)): if 'ids' in node: node['ids'] = [] if not app.config['todoext_include_todosext']: node.replace_self([]) continue nbtodo = 0 fcost = 0 content = [] todotag = node["todotag"] tsort = node["todosort"] if tsort == '': tsort = 'source' if tsort not in allowed_tsort: raise ValueError("option sort must in {0}, '{1}' is not".format( allowed_tsort, tsort)) double_list = [(info.get('todo%s' % tsort, ''), info.get('todotitle', ''), info) for info in env.todoext_all_todosext] double_list.sort(key=lambda x: x[:2]) for n, todoext_info_ in enumerate(double_list): todoext_info = todoext_info_[2] if todoext_info["todotag"] != todotag: continue nbtodo += 1 fcost += todoext_info.get("todocost", 0.0) para = nodes.paragraph(classes=['todoext-source']) if app.config['todoext_link_only']: description = locale_('<<%s>>' % orig_entry) else: description = ( locale_(todomes) % (orig_entry, os.path.split( todoext_info['source'])[-1], todoext_info['lineno'])) desc1 = description[:description.find('<<')] desc2 = description[description.find('>>') + 2:] para += nodes.Text(desc1, desc1) # Create a reference newnode = nodes.reference('', '', internal=True) innernode = nodes.emphasis('', locale_(orig_entry)) try: newnode['refuri'] = app.builder.get_relative_uri( fromdocname, todoext_info['docname']) try: newnode['refuri'] += '#' + todoext_info['target']['refid'] except Exception as e: # pragma: no cover raise KeyError("refid in not present in '{0}'".format( todoext_info['target'])) from e except NoUri: # pragma: no cover # ignore if no URI can be determined, e.g. for LaTeX output pass newnode.append(innernode) para += newnode para += nodes.Text(desc2, desc2) # (Recursively) resolve references in the todoext content todoext_entry = todoext_info.get('todoext_copy', None) if todoext_entry is None: todoext_entry = todoext_info['todoext'] todoext_entry["ids"] = ["index-todoext-%d-%d" % (ilist, n)] # it apparently requires an attributes ids if not hasattr(todoext_entry, "settings"): todoext_entry.settings = Values() todoext_entry.settings.env = env # If an exception happens here, see blog 2017-05-21 from the # documentation. env.resolve_references(todoext_entry, todoext_info['docname'], app.builder) # Insert into the todoextlist content.append(todoext_entry) content.append(para) if fcost > 0: # pragma: no cover cost = nodes.paragraph() lab = "{0} items, cost: {1}".format(nbtodo, fcost) cost += nodes.Text(lab) content.append(cost) else: cost = nodes.paragraph() lab = "{0} items".format(nbtodo) cost += nodes.Text(lab) content.append(cost) node.replace_self(content)
def process_postlist(app, doctree, docname): """Replace `PostList` nodes with lists of posts. Also, register all posts if they have not been registered yet.""" blog = Blog(app) if not blog: register_posts(app) for node in doctree.traverse(PostList): colls = [] for cat in ['tags', 'author', 'category', 'location', 'language']: for coll in node[cat]: if coll in blog.catalogs[cat].collections: colls.append(blog.catalogs[cat].collections[coll]) if colls: posts = set(blog.posts) for coll in colls: posts = posts & set(coll) posts = list(posts) posts.sort(reverse=True) posts = posts[:node.attributes['length']] else: posts = list(blog.recent(node.attributes['length'], docname, **node.attributes)) if node.attributes['sort']: posts.sort() # in reverse chronological order, so no reverse=True fmts = list(Formatter().parse(node.attributes['format'])) not_in = set(['date', 'title', 'author', 'location', 'language', 'category', 'tags', None]) for text, key, __, __ in fmts: if key not in not_in: raise KeyError('{} is not recognized in postlist format' .format(key)) excerpts = node.attributes['excerpts'] date_format = node.attributes['date'] or _(blog.post_date_format_short) bl = nodes.bullet_list() bl.attributes['classes'].append('postlist-style-' + node['list-style']) bl.attributes['classes'].append('postlist') for post in posts: bli = nodes.list_item() bl.append(bli) par = nodes.paragraph() bli.append(par) for text, key, __, __ in fmts: if text: par.append(nodes.Text(text)) if key is None: continue if key == 'date': par.append(nodes.Text(post.date.strftime(date_format))) else: if key == 'title': items = [post] else: items = getattr(post, key) for i, item in enumerate(items, start=1): if key == 'title': ref = nodes.reference() ref['refuri'] = app.builder.get_relative_uri(docname, item.docname) ref['ids'] = [] ref['backrefs'] = [] ref['dupnames'] = [] ref['classes'] = [] ref['names'] = [] ref['internal'] = True ref.append(nodes.Text(text_type(item))) else: ref = _missing_reference(app, item.xref, docname) par.append(ref) if i < len(items): par.append(nodes.Text(', ')) if excerpts and post.excerpt: for enode in post.excerpt: enode = enode.deepcopy() revise_pending_xrefs(enode, docname) app.env.resolve_references(enode, docname, app.builder) enode.parent = bli.parent bli.append(enode) node.replace_self(bl)
def role(name, rawtext, text, lineno, inliner, options={}, content=[]): url = pattern % (text, ) node = nodes.reference(rawtext, text, refuri=url, **options) return [node], []
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): # Extension code starts here. for tabnode in traverse_in_section( sectionnode, nxt_tab_head): if tabnode.tab_toc: nodetext = [nodes.Text(tabnode)] anchorname = '#' + tabnode.label_id numentries[0] += 1 reference = nodes.reference( '', '', internal=True, refuri=docname, anchorname=anchorname, *nodetext) para = addnodes.compact_paragraph('', '', reference) item = nodes.list_item('', para) entries.append(item) # Extension code ends here. 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 find_sage_dangling_links(app, env, node, contnode): """ Try to find dangling link in local module imports or all.py. """ debug_inf(app, "==================== find_sage_dangling_links ") reftype = node['reftype'] reftarget = node['reftarget'] try: doc = node['refdoc'] except KeyError: debug_inf(app, "-- no refdoc in node %s"%node) return None debug_inf(app, "Searching %s from %s"%(reftarget, doc)) # Workaround: in Python's doc 'object', 'list', ... are documented as a # function rather than a class if reftarget in base_class_as_func and reftype == 'class': node['reftype'] = 'func' res = call_intersphinx(app, env, node, contnode) if res: debug_inf(app, "++ DONE %s"%(res['refuri'])) return res if node.get('refdomain') != 'py': # not a python file return None try: module = node['py:module'] cls = node['py:class'] except KeyError: debug_inf(app, "-- no module or class for :%s:%s"%(reftype, reftarget)) return None basename = reftarget.split(".")[0] try: target_module = getattr(sys.modules['sage.all'], basename).__module__ except AttributeError: debug_inf(app, "-- %s not found in sage.all"%(basename)) return None if target_module is None: target_module = "" debug_inf(app, "?? found in None !!!") debug_inf(app, "++ found %s using sage.all in %s"%(basename, target_module)) newtarget = target_module+'.'+reftarget node['reftarget'] = newtarget # adapted from sphinx/domains/python.py builder = app.builder searchmode = node.hasattr('refspecific') and 1 or 0 matches = builder.env.domains['py'].find_obj( builder.env, module, cls, newtarget, reftype, searchmode) if not matches: debug_inf(app, "?? no matching doc for %s"%newtarget) return call_intersphinx(app, env, node, contnode) elif len(matches) > 1: env.warn(target_module, 'more than one target found for cross-reference ' '%r: %s' % (newtarget, ', '.join(match[0] for match in matches)), node.line) name, obj = matches[0] debug_inf(app, "++ match = %s %s"%(name, obj)) from docutils import nodes newnode = nodes.reference('', '', internal=True) if name == target_module: newnode['refid'] = name else: newnode['refuri'] = builder.get_relative_uri(node['refdoc'], obj[0]) newnode['refuri'] += '#' + name debug_inf(app, "++ DONE at URI %s"%(newnode['refuri'])) newnode['reftitle'] = name newnode.append(contnode) return newnode
def run(self): repo = self.arguments[0] env = self.state.document.settings.env try: repo_user, repo_name = repo.split('/') repo = gh.repository(repo_user, repo_name) except Exception as e: raise self.error("GitHub API error: %s" % e.message) tpl = gh_repo_tpl html = tpl.format(**repo.__dict__) if not hasattr(env, 'github_repo_all_repos'): env.github_repo_all_repos = [] env.github_repo_all_repos.append({ 'docname': env.docname, 'lineno': self.lineno, 'repo': repo, }) repo_link = nodes.reference('', 'github', refuri=repo.html_url) title = nodes.paragraph() title += repo_link, if 'travis' in self.options: title += nodes.inline('', ' - ') title += nodes.reference( '', 'travis', refuri=self.options.get('travis')) if 'docs' in self.options: title += nodes.inline('', ' - ') title += nodes.reference( '', 'docs', refuri=self.options.get('docs')) if 'api' in self.options: title += nodes.inline('', ' - ') title += nodes.reference( '', 'api', refuri=self.options.get('api')) if 'pypi' in self.options: title += nodes.inline('', ' - ') title += nodes.reference( '', 'pypi', refuri=self.options.get('pypi')) if 'homepage' in self.options: title += nodes.inline('', ' - ') title += nodes.reference( '', 'homepage', refuri=self.options.get('homepage')) if repo.watchers > 10: title += nodes.inline('', ' - %s watchers' % str(repo.watchers)) if repo.forks > 10: title += nodes.inline('', ' - %s forks' % str(repo.forks)) new_nodes = [title] if 'use_gh_description' in self.options: new_nodes.append(nodes.paragraph('', repo.description)) return new_nodes
def apply(self): if not len(self.document): # @@@ replace these DataErrors with proper system messages raise DataError('Document tree is empty.') header = self.document[0] if not isinstance(header, nodes.field_list) or \ 'rfc2822' not in header['classes']: raise DataError('Document does not begin with an RFC-2822 ' 'header; it is not a PEP.') pep = None for field in header: if field[0].astext().lower() == 'pep': # should be the first field value = field[1].astext() try: pep = int(value) cvs_url = self.pep_cvs_url % pep except ValueError: pep = value cvs_url = None msg = self.document.reporter.warning( '"PEP" header must contain an integer; "%s" is an ' 'invalid value.' % pep, base_node=field) msgid = self.document.set_id(msg) prb = nodes.problematic(value, value or '(none)', refid=msgid) prbid = self.document.set_id(prb) msg.add_backref(prbid) if len(field[1]): field[1][0][:] = [prb] else: field[1] += nodes.paragraph('', '', prb) break if pep is None: raise DataError('Document does not contain an RFC-2822 "PEP" ' 'header.') if pep == 0: # Special processing for PEP 0. pending = nodes.pending(PEPZero) self.document.insert(1, pending) self.document.note_pending(pending) if len(header) < 2 or header[1][0].astext().lower() != 'title': raise DataError('No title!') for field in header: name = field[0].astext().lower() body = field[1] if len(body) > 1: raise DataError('PEP header field body contains multiple ' 'elements:\n%s' % field.pformat(level=1)) elif len(body) == 1: if not isinstance(body[0], nodes.paragraph): raise DataError('PEP header field body may only contain ' 'a single paragraph:\n%s' % field.pformat(level=1)) elif name == 'last-modified': date = time.strftime( '%d-%b-%Y', time.localtime(os.stat(self.document['source'])[8])) if cvs_url: body += nodes.paragraph( '', '', nodes.reference('', date, refuri=cvs_url)) else: # empty continue para = body[0] if name == 'author': for node in para: if isinstance(node, nodes.reference): node.replace_self(mask_email(node)) elif name == 'discussions-to': for node in para: if isinstance(node, nodes.reference): node.replace_self(mask_email(node, pep)) elif name in ('replaces', 'replaced-by', 'requires'): newbody = [] space = nodes.Text(' ') for refpep in re.split(r',?\s+', body.astext()): pepno = int(refpep) newbody.append(nodes.reference( refpep, refpep, refuri=(self.document.settings.pep_base_url + self.pep_url % pepno))) newbody.append(space) para[:] = newbody[:-1] # drop trailing space elif name == 'last-modified': utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions) if cvs_url: date = para.astext() para[:] = [nodes.reference('', date, refuri=cvs_url)] elif name == 'content-type': pep_type = para.astext() uri = self.document.settings.pep_base_url + self.pep_url % 12 para[:] = [nodes.reference('', pep_type, refuri=uri)] elif name == 'version' and len(body): utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions)
def github_pr_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Here are some docs. :param rawtext: Text being replaced with link node. :param app: Sphinx application context :param type: Link type (issue, changeset, etc.) :param slug: ID of the thing to link to :param options: Options dictionary passed to role func. """ try: pr = text if not pr or len(pr) <= 0 or not isinstance(text, basestring): raise ValueError except ValueError: msg = inliner.reporter.error( 'pull request should be in the format of /:user/:repo/pull/:pull_id' '"%s" is invalid.' % text, line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] set_classes(options) repo_user, repo_name, pull, pull_id = pr.split('/') repo = gh.repository(repo_user, repo_name) pull = repo.pull_request(pull_id) tpl = gh_pr_tpl attributes = pull.__dict__ attributes['repo_name'] = pull.repository[1] pr_details = gh_pr_tpl.format(attributes) # <a href={{repo.html_url}}>repo_name</a> repo_link = nodes.reference( rawtext, repo_name, refuri=repo.html_url, **options) # <em>pull.title</em> pr_title_emphasized = nodes.emphasis(rawtext, pull.title, **options) # ./tpl/gh_pr.rst pr_details_node = nodes.emphasis(rawtext, pr_details, **options) pr_number_link = nodes.reference(rawtext, '#' + str( pull.number), refuri=pull.html_url, **options) pr_additions = nodes.inline(rawtext, str(pull.additions) + ' additions(+)') pr_deletions = nodes.inline(rawtext, str(pull.deletions) + ' deletions(-)') pr_created_at = nodes.inline(rawtext, pull.created_at.strftime('%Y-%m-%d')) title = nodes.paragraph() title += repo_link, title += nodes.inline(rawtext, ' ') title += nodes.inline(rawtext, ' (') title += pr_number_link title += nodes.inline(rawtext, ') ') title += nodes.inline(rawtext, ' '), title += pr_title_emphasized, details = nodes.paragraph() details += pr_additions details += nodes.inline(rawtext, ', ') details += pr_deletions details += nodes.inline(rawtext, ' '), details += pr_created_at return [title, details], []
def missing_reference(app, env, node, contnode): """Attempt to resolve a missing reference via intersphinx references.""" target = node['reftarget'] if node['reftype'] == 'any': # we search anything! objtypes = [ '%s:%s' % (domain.name, objtype) for domain in env.domains.values() for objtype in domain.object_types ] domain = None elif node['reftype'] == 'doc': domain = 'std' # special case objtypes = ['std:doc'] else: domain = node.get('refdomain') if not domain: # only objects in domains are in the inventory return elif domain == 'mongodb': if node['reftype'] in mdb_objs['prepend']: node['reftarget'] = '.'.join( [mdb_objs['prepend'][node['reftype']], node['reftarget']]) if node['reftype'] == 'program': node['reftype'] = 'binary' objtypes = env.domains[domain].objtypes_for_role(node['reftype']) if not objtypes: return objtypes = ['%s:%s' % (domain, objtype) for objtype in objtypes] to_try = [(env.intersphinx_inventory, target)] in_set = None if ':' in target: # first part may be the foreign doc set name setname, newtarget = target.split(':', 1) if setname in env.intersphinx_named_inventory: in_set = setname to_try.append( (env.intersphinx_named_inventory[setname], newtarget)) for inventory, target in to_try: for objtype in objtypes: if objtype not in inventory or target not in inventory[objtype]: continue proj, version, uri, dispname = inventory[objtype][target] if '://' not in uri and node.get('refdoc'): # get correct path in case of subdirectories uri = path.join(relative_path(node['refdoc'], env.srcdir), uri) newnode = nodes.reference('', '', internal=False, refuri=uri, reftitle=_('(in %s v%s)') % (proj, version)) if node.get('refexplicit'): # use whatever title was given newnode.append(contnode) elif dispname == '-' or \ (domain == 'std' and node['reftype'] == 'keyword'): # use whatever title was given, but strip prefix title = contnode.astext() if in_set and title.startswith(in_set + ':'): newnode.append( contnode.__class__(title[len(in_set) + 1:], title[len(in_set) + 1:])) else: newnode.append(contnode) else: # else use the given display name (used for :ref:) newnode.append(contnode.__class__(dispname, dispname)) return newnode # at least get rid of the ':' in the target if no explicit title given if in_set is not None and not node.get('refexplicit', True): if len(contnode) and isinstance(contnode[0], nodes.Text): contnode[0] = nodes.Text(newtarget, contnode[0].rawsource)
def process_audit_events(app, doctree, fromdocname): for node in doctree.traverse(audit_event_list): break else: return env = app.builder.env table = nodes.table(cols=3) group = nodes.tgroup( '', nodes.colspec(colwidth=30), nodes.colspec(colwidth=55), nodes.colspec(colwidth=15), cols=3, ) head = nodes.thead() body = nodes.tbody() table += group group += head group += body row = nodes.row() row += nodes.entry('', nodes.paragraph('', nodes.Text('Audit event'))) row += nodes.entry('', nodes.paragraph('', nodes.Text('Arguments'))) row += nodes.entry('', nodes.paragraph('', nodes.Text('References'))) head += row for name in sorted(getattr(env, "all_audit_events", ())): audit_event = env.all_audit_events[name] row = nodes.row() node = nodes.paragraph('', nodes.Text(name)) row += nodes.entry('', node) node = nodes.paragraph() for i, a in enumerate(audit_event['args']): if i: node += nodes.Text(", ") node += nodes.literal(a, nodes.Text(a)) row += nodes.entry('', node) node = nodes.paragraph() backlinks = enumerate(sorted(set(audit_event['source'])), start=1) for i, (doc, label) in backlinks: if isinstance(label, str): ref = nodes.reference("", nodes.Text("[{}]".format(i)), internal=True) try: ref['refuri'] = "{}#{}".format( app.builder.get_relative_uri(fromdocname, doc), label, ) except NoUri: continue node += ref row += nodes.entry('', node) body += row for node in doctree.traverse(audit_event_list): node.replace_self(table)
def make_headerlink_node(attribute_name, options): ref = '#' + attribute_name node = nodes.reference('', '¶', refuri=ref, reftitle="Permalink to this headline", classes=['headerlink'], **options) return node