def run(self): env = self.state.document.settings.env config = env.config repodir = env.srcdir + '/' + config["git_repository_root"] doc_path = env.srcdir + '/' + env.docname + config["source_suffix"] if self.options.get('dir', False) == None: doc_path = '/'.join(doc_path.split('/')[:-1]) repo = Repo(repodir) commits = repo.iter_commits(paths=doc_path) l = nodes.bullet_list() revisions_to_display = self.options.get('revisions', 10) for commit in list(commits)[:revisions_to_display]: date_str = datetime.fromtimestamp(commit.authored_date) if '\n' in commit.message: message, detailed_message = commit.message.split('\n', 1) else: message = commit.message detailed_message = None item = nodes.list_item() item += [ nodes.strong(text=message), nodes.inline(text=" by "), nodes.emphasis(text=str(commit.author)), nodes.inline(text=" at "), nodes.emphasis(text=str(date_str)) ] if detailed_message: item.append(nodes.caption(text=detailed_message.strip())) l.append(item) return [l]
def run(self): author = self.options.get('author') date = self.options.get('date') for format in ["%Y-%m-%d", "%Y-%m-%d %H:%M", "%Y-%m-%d %H:%M:%S"]: try: date = datetime.datetime.strptime(date, format) except ValueError: pass else: break else: return [doc.reporter.error("invalid date `%s`" % date, lineno=self.lineno)] meta_node = entrymeta(classes=['feed-meta']) meta_node += nodes.Text('Published') if author: meta_node += nodes.Text(' by ') author_node = nodes.emphasis(classes=['feed-author']) author_node += nodes.Text(author) meta_node += author_node if date: meta_node += nodes.Text(' on ') date_node = nodes.emphasis(classes=['feed-date']) if not date.time(): date_node += nodes.Text(date.date()) else: date_node += nodes.Text(date) meta_node += date_node meta_node['author'] = author meta_node['date'] = date return [meta_node]
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 handle_signature(self, sig, signode): match = re.match(r'(\S+)\s+' r'(\(.*\)|)\s*' r'([^"]*?)\s*' r'(".*"|)\s*' r'$', sig + ' ') if not match: raise ValueError name, stack, flags, say = match.groups() self.stack = stack # Process flags text flags, messages = self.state.inline_text(flags, self.lineno) signode += extras(0) signode += addnodes.desc_name(name, name) signode += extras(1) for s in stack.split(): if s in ['(', '--', ')'] or s.endswith(':'): signode += nodes.inline(s, s) else: signode += nodes.emphasis(s, s) signode += nodes.inline(' ', ' ') signode += extras(2) signode += flags signode += nodes.inline(' ', ' ') signode += nodes.emphasis(say, say) signode += extras(3) return name
def run(self): env = self.state.document.settings.env repo = Repo(env.srcdir) commits = repo.iter_commits() l = nodes.bullet_list() for commit in list(commits)[:10]: date_str = datetime.fromtimestamp(commit.authored_date) if '\n' in commit.message: message, detailed_message = commit.message.split('\n', 1) else: message = commit.message detailed_message = None item = nodes.list_item() item += [ nodes.strong(text=message), nodes.inline(text=" by "), nodes.emphasis(text=str(commit.author)), nodes.inline(text=" at "), nodes.emphasis(text=str(date_str)) ] if detailed_message: item.append(nodes.caption(text=detailed_message.strip())) l.append(item) return [l]
def contribute_property(self, prop_list, prop_key, prop): prop_item = nodes.definition_list_item( '', nodes.term('', prop_key)) prop_list.append(prop_item) prop_item.append(nodes.classifier('', prop.type)) definition = nodes.definition() prop_item.append(definition) if not prop.implemented: para = nodes.inline('', _('Not implemented.')) warning = nodes.note('', para) definition.append(warning) return if prop.description: para = nodes.paragraph('', prop.description) definition.append(para) if prop.update_allowed: para = nodes.paragraph('', _('Can be updated without replacement.')) definition.append(para) else: para = nodes.paragraph('', _('Updates cause replacement.')) definition.append(para) if prop.required: para = nodes.paragraph('', _('Required property.')) elif prop.default is not None: para = nodes.paragraph( '', _('Optional property, defaults to "%s".') % prop.default) else: para = nodes.paragraph('', _('Optional property.')) definition.append(para) for constraint in prop.constraints: para = nodes.paragraph('', str(constraint)) definition.append(para) sub_schema = None if prop.schema and prop.type == properties.MAP: para = nodes.emphasis('', _('Map properties:')) definition.append(para) sub_schema = prop.schema elif prop.schema and prop.type == properties.LIST: para = nodes.emphasis( '', _('List contents:')) definition.append(para) sub_schema = prop.schema if sub_schema: sub_prop_list = nodes.definition_list() definition.append(sub_prop_list) for sub_prop_key in sorted(sub_schema.keys()): sub_prop = sub_schema[sub_prop_key] self.contribute_property(sub_prop_list, sub_prop_key, sub_prop)
def _build_markup(self, commits): list_node = nodes.bullet_list() for commit in commits: date_str = datetime.fromtimestamp(commit.authored_date) if '\n' in commit.message: message, detailed_message = commit.message.split('\n', 1) else: message = commit.message detailed_message = None item = nodes.list_item() item += [ nodes.strong(text=message), nodes.inline(text=" by "), nodes.emphasis(text=six.text_type(commit.author)), nodes.inline(text=" at "), nodes.emphasis(text=str(date_str)) ] if detailed_message: detailed_message = detailed_message.strip() if self.options.get('detailed-message-pre', False): item.append( nodes.literal_block(text=detailed_message)) else: item.append(nodes.paragraph(text=detailed_message)) list_node.append(item) return [list_node]
def add_annotations(self, app, doctree): for node in doctree.traverse(addnodes.desc_content): par = node.parent if par['domain'] != 'c': continue if par['stableabi']: node.insert(0, nodes.emphasis(' Part of the stable ABI.', ' Part of the stable ABI.', classes=['stableabi'])) if par['objtype'] != 'function': continue if not par[0].has_key('names') or not par[0]['names']: continue name = par[0]['names'][0] if name.startswith("c."): name = name[2:] entry = self.get(name) if not entry: continue elif entry.result_type not in ("PyObject*", "PyVarObject*"): continue if entry.result_refs is None: rc = 'Return value: Always NULL.' elif entry.result_refs: rc = 'Return value: New reference.' else: rc = 'Return value: Borrowed reference.' node.insert(0, nodes.emphasis(rc, rc, classes=['refcount']))
def handle_item(fieldarg, content): par = nodes.paragraph() if self.prefix: par += self.namefmt(self.prefix, self.prefix) par += self.make_xref(self.rolename, domain, fieldarg, self.namefmt, modname=modname, typename=typename) #par += self.namefmt(fieldarg, fieldarg) fieldtype = types.pop(fieldarg, None) fieldshape = shapes and shapes.pop(fieldarg, None) fieldattrs = attrs and attrs.pop(fieldarg, None) if fieldshape: shape = parse_shape(fieldshape[0].astext()) #par += nodes.Text(' %s'%shape) add_shape(par, shape, modname=modname) if fieldtype or fieldattrs: par += nodes.emphasis(' [',' [' ) if fieldtype: if len(fieldtype) == 1 and isinstance(fieldtype[0], nodes.Text): thistypename = fieldtype[0].astext() #typename = u''.join(n.astext() for n in fieldtype) par += self.make_xref(self.typerolename, domain, thistypename, modname=modname, typename=typename) else: par += fieldtype if fieldattrs: if fieldtype: par += nodes.emphasis(',',',') par += fieldattrs if fieldtype or fieldattrs: par += nodes.emphasis(']',']') if content: par += nodes.Text(' :: ') par += content return par
def attach_function(self, node, func): owner, name = func.name.split_owner() # Olaf: Never show Class:: owner = None if owner is not None: owner = unicode(owner) + '::' node += addnodes.desc_addname(owner, owner) # cast operator is special. in this case the return value # is reversed. if isinstance(name, CastOpDefExpr): node += addnodes.desc_name('operator', 'operator') node += nodes.Text(u' ') self.attach_type(node, name.typename) else: funcname = unicode(name) node += addnodes.desc_name(funcname, funcname) paramlist = addnodes.desc_parameterlist() for arg in func.signature: param = addnodes.desc_parameter('', '', noemph=True) if arg.type is not None: self.attach_type(param, arg.type) param += nodes.Text(u' ') param += nodes.emphasis(unicode(arg.name), unicode(arg.name)) if arg.default is not None: def_ = u'=' + unicode(arg.default) param += nodes.emphasis(def_, def_) paramlist += param node += paramlist if func.const: node += addnodes.desc_addname(' const', ' const') if func.pure_virtual: node += addnodes.desc_addname(' = 0', ' = 0')
def _parse(self, tree): if isinstance(tree, minidom.Document): return self._parse(tree.childNodes[0]) if isinstance(tree, minidom.Text): return nodes.Text(tree.data) # Get children. children = [self._parse(c) for c in tree.childNodes] if tree.tagName == 'epytext': return children if tree.tagName == 'para': return nodes.paragraph('','', *children) if tree.tagName == 'section': return nodes.section('', *children) if tree.tagName == 'heading': return nodes.title('','', *children) if tree.tagName == 'fieldlist': return nodes.field_list('', *children) if tree.tagName == 'field': return nodes.field('', *self._parse_field(tree, children)) if tree.tagName == 'literalblock': return nodes.literal_block('','', *children) if tree.tagName == 'doctestblock': return nodes.doctest_block('','', *children) if tree.tagName == 'ulist': return nodes.bullet_list('', *children) if tree.tagName == 'olist': return nodes.enumerated_list('', *children) if tree.tagName == 'li': return nodes.list_item('', *children) if tree.tagName == 'link': # [XX] discards link target. name, target = children return nodes.title_reference('','', name) if tree.tagName == 'uri': name, target = children return nodes.reference('','', name, refuid=target.astext()) if tree.tagName == 'code': return nodes.literal('','', *children) if tree.tagName == 'math': return nodes.emphasis('','', *children) if tree.tagName == 'italic': return nodes.emphasis('','', *children) if tree.tagName == 'bold': return nodes.strong('','', *children) if tree.tagName == 'indexed': # [XX] doesn't mark the fact that it's indexedd return nodes.emphasis('','', *children) if tree.tagName == 'symbol': # use substitutions. # [XX] this needs to be fixed! return nodes.Text(children[0]) elif tree.tagName in ('tag', 'arg', 'name', 'target'): return children[0] else: raise ValueError, ('unknown %s' % tree.tagName)
def foobar(argument, is_last, param): parts = argument.replace('[]', '()').split(' ') if len(parts) != 4: raise ValueError("Argument '{0}' has unexpected format".format(argument)) param += addnodes.desc_type(parts[0] + ' ', parts[0] + ' ') param += nodes.emphasis(parts[1] + ' ', parts[1] + ' ') param += addnodes.desc_type(' '.join(parts[2:]), ' '.join(parts[2:])) if not is_last: param += nodes.emphasis(', ', ', ')
def append_parameters(self, node, params): pnodes = addnodes.desc_parameterlist() for param in params: pnode = addnodes.desc_parameter('', '', noemph=True) self.append_type(pnode, param.type) pnode += nodes.Text(u' ') pnode += nodes.emphasis(param.name, param.name) if param.default is not None: default = u' = ' + param.default pnode += nodes.emphasis(default, default) pnodes += pnode node += pnodes
def foobar(argument, is_last, param): parts = argument.split(':') name = parts[0].split(' ') if len(name) > 1: param += addnodes.desc_type(name[0] + ' ', name[0] + ' ') param += nodes.emphasis(' '.join(name[1:]) + ': ', ' '.join(name[1:]) + ': ') else: param += nodes.emphasis(name[0] + ': ', name[0] + ': ') param += addnodes.desc_type(parts[-1], parts[-1]) if not is_last: param += nodes.emphasis('; ', '; ')
def assemble_doctree(self, indexfile, toctree_only, appendices): self.docnames = set([indexfile] + appendices) self.info(darkgreen(indexfile) + " ", nonl=1) tree = self.env.get_doctree(indexfile) tree['docname'] = indexfile if toctree_only: # extract toctree nodes from the tree and put them in a # fresh document new_tree = new_document('<latex output>') new_sect = nodes.section() new_sect += nodes.title(u'<Set title in conf.py>', u'<Set title in conf.py>') new_tree += new_sect for node in tree.traverse(addnodes.toctree): new_sect += node tree = new_tree largetree = inline_all_toctrees(self, self.docnames, indexfile, tree, darkgreen) largetree['docname'] = indexfile for docname in appendices: appendix = self.env.get_doctree(docname) appendix['docname'] = docname largetree.append(appendix) self.info() self.info("resolving references...") #for node in largetree.traverse(nodes.target): # print node self.env.resolve_references(largetree, indexfile, self) # resolve :ref:s to distant tex files -- we can't add a cross-reference, # but append the document name for pendingnode in largetree.traverse(addnodes.pending_xref): 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) # for node in largetree.traverse(nodes.reference): # print node return largetree
def make_item_ref(app, env, fromdocname, item_info): """ Creates a reference node for an item, embedded in a paragraph. Reference text adds also a caption if it exists. """ id = item_info['target']['refid'] if item_info['caption'] != '': caption = ', ' + item_info['caption'] else: caption = '' para = nodes.paragraph() newnode = nodes.reference('', '') innernode = nodes.emphasis(id + caption, id + caption) newnode['refdocname'] = item_info['docname'] try: newnode['refuri'] = app.builder.get_relative_uri(fromdocname, item_info['docname']) newnode['refuri'] += '#' + id except NoUri: # ignore if no URI can be determined, e.g. for LaTeX output :( pass newnode.append(innernode) para += newnode return para
def status_role(name, rawtext, text, lineno, inliner, options=None, content=[]): status = utils.unescape(text) options = options or {} options.setdefault('classes', []) options['classes'] += ['status', status] node = nodes.emphasis(rawtext, status, **options) return [node], []
def run(self): env = self.state.document.settings.env # Default language language = self.options.get('language') # Build the file text cwd = self.options.get('cwd', self.default_cwd) # Get the filename, possibly from first line of contents fname_raw, content = self.get_filename() file_content = u'\n'.join(content) + '\n' # Write the file if not fname_raw.startswith('/'): if cwd == '/': fname_sphinx = cwd + fname_raw else: fname_sphinx = cwd + '/' + fname_raw else: fname_sphinx = fname_raw _, fname = env.relfn2path(fname_sphinx) with open(fname, 'wt') as fobj: fobj.write(file_content) if 'hide' in self.options: return [nodes.comment(file_content, file_content)] literal = nodes.literal_block(file_content, file_content) literal['language'] = (self.options['highlighter'] if 'highlighter' in self.options else 'none' if language is None else language) literal['linenos'] = 'linenos' in self.options para = FileContents() para += nodes.emphasis(text='Contents of ') para += nodes.literal(text=fname_raw) para += literal return [para]
def handle_signature(self, sig, signode): m = sig.split() name = m[0] args = m[1:] if len(m) > 1 else [] for a in args: if a.startswith("t:"): signode += addnodes.literal_emphasis("", a[2:]) elif a.startswith("a:"): signode += addnodes.literal_emphasis("", a[2:]) elif a.startswith("op:"): signode += nodes.literal("", a[3:]) elif a.startswith("x:"): signode += nodes.emphasis("", a[2:].replace("-", " ")) elif a == "<sp>": signode += nodes.inline("", " ") else: signode += nodes.inline("", a) return name
def handle_signature(self, sig, signode): """Transform a C signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) if m is None: m = c_sig_re.match(sig) if m is None: raise ValueError('no match') rettype, name, arglist, const = m.groups() signode += addnodes.desc_type('', '') self._parse_type(signode[-1], rettype) try: classname, funcname = name.split('::', 1) classname += '::' signode += addnodes.desc_addname(classname, classname) signode += addnodes.desc_name(funcname, funcname) # name (the full name) is still both parts except ValueError: signode += addnodes.desc_name(name, name) # clean up parentheses from canonical name m = c_funcptr_name_re.match(name) if m: name = m.group(1) typename = self.env.temp_data.get('c:type') if self.name == 'c:member' and typename: fullname = typename + '.' + name else: fullname = name if not arglist: if self.objtype == 'function': # for functions, add an empty parameter list signode += addnodes.desc_parameterlist() if const: signode += addnodes.desc_addname(const, const) return fullname paramlist = addnodes.desc_parameterlist() arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup # this messes up function pointer types, but not too badly ;) args = arglist.split(',') for arg in args: arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: ctype, argname = arg.rsplit(' ', 1) except ValueError: # no argument name given, only the type self._parse_type(param, arg) else: self._parse_type(param, ctype) # separate by non-breaking space in the output param += nodes.emphasis(' '+argname, u'\xa0'+argname) paramlist += param signode += paramlist if const: signode += addnodes.desc_addname(const, const) return fullname
def role(name, rawtext, text, lineno, inliner, options={}, content=[]): #version = self.arguments[0] #summary = self.arguments[1] version, summary = text.split(':', 1) summary = summary.strip() indexstring = 'bareos-{}; {}'.format(version, summary) idstring = 'bareos-{}-{}'.format(version, summary) _id = nodes.make_id(idstring) # Generic index entries indexnode = addnodes.index() indexnode['entries'] = [] indexnode['entries'].append([ 'pair', indexstring, _id, '', None ]) targetnode = nodes.target('', '', ids=[_id]) #text_node = nodes.Text(text='Version >= {}'.format(version)) #text_node = nodes.strong(text='Version >= {}'.format(version)) text_node = nodes.emphasis(text='Version >= {}'.format(version)) # target does not work with generated. #text_node = nodes.generated(text='Version >= {}'.format(version)) return [targetnode, text_node, indexnode], []
def _build_markup(self): field_list = nodes.field_list() item = nodes.paragraph() item.append(field_list) if 'branch' in self.options: name = nodes.field_name(text="Branch") body = nodes.field_body() body.append(nodes.emphasis(text=self.branch_name)) field = nodes.field() field += [name, body] field_list.append(field) if 'commit' in self.options: name = nodes.field_name(text="Commit") body = nodes.field_body() if 'no_github_link' in self.options: body.append(self._commit_text_node()) else: body.append(self._github_link()) field = nodes.field() field += [name, body] field_list.append(field) if 'uncommitted' in self.options and self.repo.is_dirty(): item.append(nodes.warning('', nodes.inline( text="There were uncommitted changes when this was compiled." ))) if 'untracked' in self.options and self.repo.untracked_files: item.append(nodes.warning('', nodes.inline( text="There were untracked files when this was compiled." ))) return [item]
def run(self): env = self.state.document.settings.env modname = self.arguments[0].strip() noindex = 'noindex' in self.options env.temp_data['tcpip:module'] = modname env.domaindata['tcpip']['modules'][modname] = \ (env.docname, self.options.get('synopsis', ''), self.options.get('platform', ''), 'deprecated' in self.options) targetnode = nodes.target('', '', ids=['module-' + modname], ismod=True) self.state.document.note_explicit_target(targetnode) ret = [targetnode] # XXX this behavior of the module directive is a mess... if 'platform' in self.options: platform = self.options['platform'] node = nodes.paragraph() node += nodes.emphasis('', _('Platforms: ')) node += nodes.Text(platform, platform) ret.append(node) # the synopsis isn't printed; in fact, it is only used in the # modindex currently if not noindex: indextext = _('%s (module)') % modname inode = addnodes.index(entries=[('single', indextext, 'module-' + modname, modname)]) ret.append(inode) return ret
def run(self): if self.name in self.state.document.settings.dir_ignore: return [] children = [] if self.name not in self.state.document.settings.dir_notitle: children.append(nodes.strong(self.name, u"%s: " % self.name)) # keep the arguments, drop the options for a in self.arguments: if a.startswith(':') and a.endswith(':'): break children.append(nodes.emphasis(a, u"%s " % a)) if self.name in self.state.document.settings.dir_nested: if self.content: container = nodes.Element() self.state.nested_parse(self.content, self.content_offset, container) children.extend(container.children) else: content = u'\n'.join(self.content) children.append(nodes.literal_block(content, content)) node = any_directive(self.block_text, '', *children, dir_name=self.name) return [node]
def handle_signature(self, sig, signode): m = sig_pattern.match(sig) if m is None: raise ValueError() return_type, method_name, arglist = m.groups() arguments = [] if arglist: for arg in arglist.split(","): m = arg_pattern.match(arg) if m is None: raise ValueError() arguments.append(m.groups()) class_name = self.env.temp_data.get("java:class") if not class_name: self.env.warn( self.env.docname, "Java method description of %s outside of class is not supported" % sig, self.lineno ) raise ValueError() if return_type is not None: # will be absent for constructors self._parse_type(return_type, signode) signode += nodes.Text(" ", " ") signode += addnodes.desc_name(method_name, method_name) signode += addnodes.desc_parameterlist() for type, name in arguments: signode[-1] += addnodes.desc_parameter("", "", noemph=True) self._parse_type(type, signode[-1][-1]) signode[-1][-1] += nodes.Text(" ", " ") signode[-1][-1] += nodes.emphasis(name, name) return "%s#%s(%s)" % (class_name, method_name, ", ".join(type for type, name in arguments))
def handle_constructor_signature(self, sig, signode): try: member = javalang.parse.parse_constructor_signature(sig) except javalang.parser.JavaSyntaxError: raise self.error("syntax error in constructor signature") if not isinstance(member, javalang.tree.ConstructorDeclaration): raise self.error("expected constructor declaration") mods = formatter.output_modifiers(member.modifiers).build() signode += nodes.Text(mods + ' ', mods + ' ') signode += addnodes.desc_name(member.name, member.name) paramlist = addnodes.desc_parameterlist() for parameter in member.parameters: param = addnodes.desc_parameter('', '', noemph=True) param += self._build_type_node(parameter.type) if parameter.varargs: param += nodes.Text('...', '') param += nodes.emphasis(' ' + parameter.name, ' ' + parameter.name) paramlist += param signode += paramlist param_reprs = [formatter.output_type(param.type, with_generics=False).build() for param in member.parameters] return '%s(%s)' % (member.name, ', '.join(param_reprs))
def run(self): env = self.state.document.settings.env node = nodes.Element() node.document = self.state.document self.state.nested_parse(self.content, self.content_offset, node) entries = [] for i, child in enumerate(node): if isinstance(child, nodes.literal_block): # add a title (the language name) before each block #targetid = "configuration-block-%d" % env.new_serialno('configuration-block') #targetnode = nodes.target('', '', ids=[targetid]) #targetnode.append(child) if 'language' in child: language = child['language'] else: language = env.app.config.highlight_language innernode = nodes.emphasis(self.formats[language], self.formats[language]) para = nodes.paragraph() para += [innernode, child] entry = nodes.list_item('') entry.append(para) entries.append(entry) resultnode = configurationblock() resultnode.append(nodes.bullet_list('', *entries)) return [resultnode]
def ref_role(name, raw_text, text, lineno, inliner, options=None, content=None): link_resolver = inliner.document.settings.link_resolver cur_module = inliner.document.settings.cur_module cur_module_components = cur_module.split(".") if options is None: options = {} if content is None: content = [] text_components = text.split(".") rel_distance = len(cur_module_components) - len(text_components) + 1 link = None for i in range(rel_distance): l = len(cur_module_components) - i potential_name = ".".join(cur_module_components[:l] + [text]) link = link_resolver.get_named_link(potential_name) if link: break if link is None: link = link_resolver.get_named_link(text) if link is None: node = nodes.emphasis(text, text) else: node = nodes.reference(link.title, link.title, refuri=link.get_link(), **options) return [node], []
def tag_role(name, rawtext, text, lineno, inliner, options=None, content=[]): status = utils.unescape(text.strip().replace(' ','_')) options = options or {} options.setdefault('classes', []) options['classes'] += ['taglist_tag_%s'%status, 'taglist_tag'] node = nodes.emphasis(rawtext, status, **options) return [node], []
def run(self): subnode = nodes.paragraph() subnode += [nodes.emphasis(text='Source: ')] inodes, messages = self.state.inline_text(self.arguments[0], self.lineno) subnode.extend(inodes) return [subnode] + messages
def run(self): from docutils import nodes node = nodes.paragraph() node += addnodes.desc_name(self.arguments[0], self.arguments[0]) shape = self.options.get('shape') if shape: #node += nodes.Text(shape, shape) add_shape(node, shape) type = self.options.get('type') attrs = self.options.get('attrs') if type or attrs: node += nodes.Text(' :: ', ' :: ') if type: node += nodes.emphasis('', type) if attr: node += nodes.literal('', '[' + attr + ']') if self.content: node += nodes.Text(': ', ': ') argnodes, msgs = self.state.inline_text(' '.join(self.content), self.lineno) node += argnodes node += msgs ret = [node] # env = self.state.document.settings.env # env.note_versionchange(node['type'], node['version'], node, self.lineno) return ret
def autolink_role( typ: str, rawtext: str, etext: str, lineno: int, inliner: Inliner, options: Dict = {}, content: List[str] = []) -> Tuple[List[Node], List[system_message]]: """Smart linking role. Expands to ':obj:`text`' if `text` is an object that can be imported; otherwise expands to '*text*'. """ warnings.warn('autolink_role() is deprecated.', RemovedInSphinx40Warning, stacklevel=2) env = inliner.document.settings.env pyobj_role = env.get_domain('py').role('obj') objects, msg = pyobj_role('obj', rawtext, etext, lineno, inliner, options, content) if msg != []: return objects, msg assert len(objects) == 1 pending_xref = cast(addnodes.pending_xref, objects[0]) prefixes = get_import_prefixes_from_env(env) try: name, obj, parent, modname = import_by_name(pending_xref['reftarget'], prefixes) except ImportError: literal = cast(nodes.literal, pending_xref[0]) objects[0] = nodes.emphasis(rawtext, literal.astext(), classes=literal['classes']) return objects, msg
def parse_c_signature(signode, sig, desctype): """Transform a C-language signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) if m is None: m = c_sig_re.match(sig) if m is None: raise ValueError('no match') rettype, name, arglist = m.groups() parse_c_type(signode, rettype) signode += addnodes.desc_name(name, name) if not arglist: if desctype == 'cfunction': # for functions, add an empty parameter list signode += addnodes.desc_parameterlist() return name paramlist = addnodes.desc_parameterlist() arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup # this messes up function pointer types, but not too badly ;) args = arglist.split(',') for arg in args: arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: ctype, argname = arg.rsplit(' ', 1) except ValueError: # no argument name given, only the type parse_c_type(param, arg) else: parse_c_type(param, ctype) param += nodes.emphasis(' ' + argname, ' ' + argname) paramlist += param signode += paramlist return name
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) if typ == "menuselection": text = text.replace("-->", "\N{TRIANGULAR BULLET}") spans = _amp_re.split(text) node = nodes.emphasis(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace("&&", "&") if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node["classes"].append("accelerator") node += accel_node textnode = nodes.Text(span[1:]) node += textnode node["classes"].append(typ) return [node], []
def process_todolist(app, doctree, fromdocname): # Replace all todolist nodes with a list of the collected todos. # Augment each todo with a backlink to the original location. env = app.builder.env for node in doctree.traverse(todolist): if not app.config['todo_include_todos']: node.replace_self([]) continue content = [] for todo_info in env.todo_all_todos: para = nodes.paragraph() filename = env.doc2path(todo_info['docname'], base=None) description = ( _('(The original entry is located in %s, line %d and can be found ') % (filename, todo_info['lineno'])) para += nodes.Text(description, description) # Create a reference newnode = nodes.reference('', '') innernode = nodes.emphasis(_('here'), _('here')) newnode['refdocname'] = todo_info['docname'] newnode['refuri'] = app.builder.get_relative_uri( fromdocname, todo_info['docname']) newnode['refuri'] += '#' + todo_info['target']['refid'] newnode.append(innernode) para += newnode para += nodes.Text('.)', '.)') # Insert into the todolist content.append(todo_info['todo']) content.append(para) node.replace_self(content)
def menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): text = utils.unescape(text) if typ == 'menuselection': text = text.replace('-->', u'\N{TRIANGULAR BULLET}') spans = _amp_re.split(text) node = nodes.emphasis(rawtext=rawtext) for i, span in enumerate(spans): span = span.replace('&&', '&') if i == 0: if len(span) > 0: textnode = nodes.Text(span) node += textnode continue accel_node = nodes.inline() letter_node = nodes.Text(span[0]) accel_node += letter_node accel_node['classes'].append('accelerator') node += accel_node textnode = nodes.Text(span[1:]) node += textnode node['classes'].append(typ) return [node], []
def add_shape_and_attrs(self, signode, modname, ftype, shape, attrs): # add shape if shape: add_shape(signode, shape, modname=modname) #signode += nodes.Text(' '+shape) # add type ('float', 'interger', etc) if ftype or attrs: signode += nodes.emphasis(' [', ' [') if ftype: refnode = addnodes.pending_xref( '', refdomain='f', reftype='type', reftarget=ftype, modname=modname,) refnode += nodes.emphasis(ftype, ftype) signode += refnode #tnode = addnodes.desc_type(ftype, ftype) # tnode += #signode += addnodes.desc_type(ftype, ftype) # signode += # signode += addnodes.desc_type('', '') # self._parse_type(signode[-1], ftype) if attrs: if ftype: signode += nodes.emphasis(',', ',') for iatt, att in enumerate(re.split(r'\s*,\s*', attrs)): if iatt: signode += nodes.emphasis(',', ',') if att.startswith('parameter'): value = att.split('=')[1] signode += nodes.emphasis('parameter=', 'parameter=') convert_arithm(signode, value, modname=modname) else: signode += nodes.emphasis(att, att) #signode += nodes.emphasis(attrs, attrs) if ftype or attrs: signode += nodes.emphasis(']', ']')
def _commit_text_node(self): return nodes.emphasis(text=self.commit.hexsha[:self.sha_length])
def emphasis(role, rawtext, text, lineno, inliner, options={}, content=[]): rawtext.find('`') text = rawtext.split('`')[1] node = nodes.emphasis(rawtext, text) return [node], []
def handle_signature(self, sig, signode): # type: (unicode, addnodes.desc_signature) -> unicode """Transform a C signature into RST nodes.""" # first try the function pointer signature regex, it's more specific m = c_funcptr_sig_re.match(sig) # type: ignore if m is None: m = c_sig_re.match(sig) # type: ignore if m is None: raise ValueError('no match') rettype, name, arglist, const = m.groups() signode += addnodes.desc_type('', '') self._parse_type(signode[-1], rettype) try: classname, funcname = name.split('::', 1) classname += '::' signode += addnodes.desc_addname(classname, classname) signode += addnodes.desc_name(funcname, funcname) # name (the full name) is still both parts except ValueError: signode += addnodes.desc_name(name, name) # clean up parentheses from canonical name m = c_funcptr_name_re.match(name) if m: name = m.group(1) typename = self.env.ref_context.get('c:type') if self.name == 'c:member' and typename: fullname = typename + '.' + name else: fullname = name if not arglist: if self.objtype == 'function': # for functions, add an empty parameter list signode += addnodes.desc_parameterlist() if const: signode += addnodes.desc_addname(const, const) return fullname paramlist = addnodes.desc_parameterlist() arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup # this messes up function pointer types, but not too badly ;) for arg in self._parse_arglist(arglist): arg = arg.strip() param = addnodes.desc_parameter('', '', noemph=True) try: m = c_funcptr_arg_sig_re.match(arg) # type: ignore if m: self._parse_type(param, m.group(1) + '(') param += nodes.emphasis(m.group(2), m.group(2)) self._parse_type(param, ')(' + m.group(3) + ')') if m.group(4): param += addnodes.desc_addname(m.group(4), m.group(4)) else: ctype, argname = arg.rsplit(' ', 1) self._parse_type(param, ctype) # separate by non-breaking space in the output param += nodes.emphasis(' ' + argname, u'\xa0' + argname) except ValueError: # no argument name given, only the type self._parse_type(param, arg) paramlist += param signode += paramlist if const: signode += addnodes.desc_addname(const, const) return fullname
def create_hoverlist(app, doctree, fromdocname): # If translationlists are set to not appear, replace them with empty nodes. if not app.config.hover_translationList: for node in doctree.traverse(hoverlist): if not app.config.hover_translationList: node.replace_self([]) return # Words is a dictionary with translated terms as keys and translations as values. words = {} content = [] #with codecs.open("LIST_OF_HOVER_TERMS", encoding = "utf-8") as listfile: listfile = open("LIST_OF_HOVER_TERMS", 'r') listcontents = listfile.readlines() listfile.close() for line in listcontents: # Clean up the strings. line = line.split(";") for idx, entry in enumerate(line): beginindex = entry.find("'") newentry = entry[beginindex + 1:] line[idx] = newentry citationform = line[2] translation = line[3] if citationform in words: continue words[citationform] = translation # Add words and translations (sorted) to nodes. for key, value in sorted(words.items()): wordnode = nodes.emphasis(key, key) translationstring = " : " + value # Add linebreak if smaller version of list is used. if app.config.hover_miniTranslationList: translationstring += "\n" translationnode = nodes.Text(translationstring) # If the larger version of list is requested, create new paragraph. if not app.config.hover_miniTranslationList: para = nodes.paragraph() # If the smaller version of list is requested, create a new line. else: para = nodes.line() # Append the line/paragraph. para += wordnode para += translationnode content.append(para) # Replace all hoverlist nodes with the translations for node in doctree.traverse(hoverlist): # If hover_translation userconfig is set to 0 remove all hoverlist nodes. if not app.config.hover_translationList: node.replace_self([]) continue node.replace_self(content) return
def visit_em(self, node): return nodes.emphasis()
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.spinx_logger.info(darkgreen(docname) + " ") 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.spinx_logger.info(darkgreen(includefile) + " ") 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. 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 = IndexEntries(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.values(): 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.spinx_logger.info(' ' + indexname) 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.spinx_logger.info() self.spinx_logger.info('adding appendixes...') for docname in appendices: self.spinx_logger.info(darkgreen(docname) + " ") appendix = self.env.get_doctree(docname) appendix['docname'] = docname tree.append(appendix) self.spinx_logger.info('done') # Replace Sphinx's HighlightLanguageTransform with our own for Spinx version between 1.8.0 & less than 2.0.0 as # Sphinx's HighlightLanguageTransform breaks linenothreshold setting in the highlight directive (See issue #721) # This code can be removed when we drop support for Python 2 if sphinx.__version__ > '1.7.9' and sphinx.__version__ < '2.0.0': for i in range(len(self.env.app.registry.post_transforms)): if self.env.app.registry.post_transforms[i].__name__ == 'HighlightLanguageTransform': self.env.app.registry.post_transforms[i] = HighlightLanguageTransform break self.spinx_logger.info("resolving references...") self.env.resolve_references(tree, docname, self) 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 menusel_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): return [ nodes.emphasis( rawtext, utils.unescape(text).replace('-->', u'\N{TRIANGULAR BULLET}')) ], []
def emph(inlines): emph_node = nodes.emphasis() append_inlines(emph_node, inlines) return emph_node
def contribute_property(self, prop_list, prop_key, prop): prop_item = nodes.definition_list_item( '', nodes.term('', prop_key)) prop_list.append(prop_item) prop_item.append(nodes.classifier('', prop.type)) definition = nodes.definition() prop_item.append(definition) if prop.support_status.status != support.SUPPORTED: sstatus = prop.support_status.to_dict() msg = _('%(status)s') if sstatus['message'] is not None: msg = _('%(status)s - %(message)s') para = nodes.inline('', msg % sstatus) warning = nodes.note('', para) definition.append(warning) if not prop.implemented: para = nodes.inline('', _('Not implemented.')) warning = nodes.note('', para) definition.append(warning) return if prop.description: para = nodes.paragraph('', prop.description) definition.append(para) if prop.update_allowed: para = nodes.paragraph('', _('Can be updated without replacement.')) definition.append(para) else: para = nodes.paragraph('', _('Updates cause replacement.')) definition.append(para) if prop.required: para = nodes.paragraph('', _('Required property.')) elif prop.default is not None: para = nodes.paragraph( '', _('Optional property, defaults to "%s".') % prop.default) else: para = nodes.paragraph('', _('Optional property.')) definition.append(para) for constraint in prop.constraints: para = nodes.paragraph('', str(constraint)) definition.append(para) sub_schema = None if prop.schema and prop.type == properties.Schema.MAP: para = nodes.emphasis('', _('Map properties:')) definition.append(para) sub_schema = prop.schema elif prop.schema and prop.type == properties.Schema.LIST: para = nodes.emphasis( '', _('List contents:')) definition.append(para) sub_schema = prop.schema if sub_schema: sub_prop_list = nodes.definition_list() definition.append(sub_prop_list) for sub_prop_key, sub_prop in sorted(sub_schema.items(), self.cmp_prop): self.contribute_property( sub_prop_list, sub_prop_key, sub_prop)
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() 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'])) for text, key, __, __ in fmts: if key not in { 'date', 'title', 'author', 'location', 'language', 'category', 'tags' }: 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() 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 == '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): 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 par.append(ref) emp = nodes.emphasis() ref.append(emp) emp.append(nodes.Text(str(item))) if i + 1 < len(items): par.append(nodes.Text(', ')) if excerpts: bli.extend(post.excerpt) node.replace_self(bl)
def row_col_maker(app, fromdocname, all_needs, need_info, need_key, make_ref=False, ref_lookup=False, prefix=''): """ Creates and returns a column. :param app: current sphinx app :param fromdocname: current document :param all_needs: Dictionary of all need objects :param need_info: need_info object, which stores all related need data :param need_key: The key to access the needed data from need_info :param make_ref: If true, creates a reference for the given data in need_key :param ref_lookup: If true, it uses the data to lookup for a related need and uses its data to create the reference :param prefix: string, which is used as prefix for the text output :return: column object (nodes.entry) """ row_col = nodes.entry() para_col = nodes.paragraph() if need_key in need_info and need_info[need_key] is not None: if not isinstance(need_info[need_key], (list, set)): data = [need_info[need_key]] else: data = need_info[need_key] for index, datum in enumerate(data): link_id = datum link_part = None link_list = [] for link_type in app.env.config.needs_extra_links: link_list.append(link_type["option"]) link_list.append(link_type["option"] + '_back') if need_key in link_list: if '.' in datum: link_id = datum.split('.')[0] link_part = datum.split('.')[1] datum_text = prefix + datum text_col = nodes.Text(datum_text, datum_text) if make_ref or ref_lookup: try: ref_col = nodes.reference("", "") if not ref_lookup: ref_col['refuri'] = app.builder.get_relative_uri( fromdocname, need_info['docname']) ref_col['refuri'] += "#" + datum else: temp_need = all_needs[link_id] ref_col['refuri'] = app.builder.get_relative_uri( fromdocname, temp_need['docname']) ref_col['refuri'] += "#" + temp_need["id"] if link_part is not None: ref_col['refuri'] += '.' + link_part except KeyError: para_col += text_col else: ref_col.append(text_col) para_col += ref_col else: para_col += text_col if index + 1 < len(data): para_col += nodes.emphasis("; ", "; ") row_col += para_col return row_col
def visit_emph(self, _): n = nodes.emphasis() self.current_node.append(n) self.current_node = n
def process_todo_nodes(app, doctree, fromdocname): # type: (Sphinx, nodes.document, str) -> None node = None # type: nodes.Element if not app.config['todo_include_todos']: for node in doctree.traverse(todo_node): node.parent.remove(node) # Replace all todolist nodes with a list of the collected todos. # Augment each todo with a backlink to the original location. env = app.builder.env if not hasattr(env, 'todo_all_todos'): env.todo_all_todos = [] # type: ignore for node in doctree.traverse(todolist): if node.get('ids'): content = [nodes.target()] # type: List[nodes.Element] else: content = [] if not app.config['todo_include_todos']: node.replace_self(content) continue for todo_info in env.todo_all_todos: # type: ignore para = nodes.paragraph(classes=['todo-source']) if app.config['todo_link_only']: description = _('<<original entry>>') else: description = ( _('(The <<original entry>> is located in %s, line %d.)') % (todo_info['source'], todo_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(_('original entry'), _('original entry')) try: newnode['refuri'] = app.builder.get_relative_uri( fromdocname, todo_info['docname']) if 'refid' in todo_info['target']: newnode['refuri'] += '#' + todo_info['target']['refid'] else: newnode['refuri'] += '#' + todo_info['target']['ids'][0] except NoUri: # ignore if no URI can be determined, e.g. for LaTeX output pass newnode.append(innernode) para += newnode para += nodes.Text(desc2, desc2) todo_entry = todo_info['todo'] # Remove targetref from the (copied) node to avoid emitting a # duplicate label of the original entry when we walk this node. if 'targetref' in todo_entry: del todo_entry['targetref'] # (Recursively) resolve references in the todo content env.resolve_references(todo_entry, todo_info['docname'], app.builder) # Insert into the todolist content.append(todo_entry) content.append(para) node.replace_self(content)
def get_reference_node(self, ref): node = nodes.inline('', '', classes=[ref.type, 'reference']) namestyler = pybtex.style.names.plain.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 = fromlatex(authortext) 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 = fromlatex(title) node += nodes.inline(title, title, classes=['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 = fromlatex(pub) 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') doi = ref.fields.get('doi') 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 = fromlatex(vol) node += nodes.inline(vol, vol, classes=['volume']) node += nodes.inline(':', ':') if pages: pages = fromlatex(pages) node += nodes.inline(pages, pages, classes=['pages']) node += nodes.inline(', ', ', ') if year: year = fromlatex(year) node += nodes.inline('(', '(') node += nodes.inline(year, year, classes=['year']) node += nodes.inline(')', ')') if url: url = fromlatex(url) refnode = nodes.reference('', '', internal=False, refuri=url) refnode += nodes.Text(url, url) node += nodes.inline(', ', ', ') node += refnode elif doi: url = fromlatex("{http://dx.doi.org/%s" % doi) refnode = nodes.reference('', '', internal=False, refuri=url) refnode += nodes.Text(url, url) node += nodes.inline(', ', ', ') node += refnode return node
def process_needfilters(app, doctree, fromdocname): # Replace all needlist nodes with a list of the collected needs. # Augment each need with a backlink to the original location. env = app.builder.env # NEEDFILTER for node in doctree.traverse(Needfilter): if not app.config.needs_include_needs: # Ok, this is really dirty. # If we replace a node, docutils checks, if it will not lose any attributes. # But this is here the case, because we are using the attribute "ids" of a node. # However, I do not understand, why losing an attribute is such a big deal, so we delete everything # before docutils claims about it. for att in ('ids', 'names', 'classes', 'dupnames'): node[att] = [] node.replace_self([]) continue id = node.attributes["ids"][0] current_needlist = env.need_all_needlists[id] all_needs = env.need_all_needs if current_needlist["layout"] == "list": content = [] elif current_needlist["layout"] == "diagram": content = [] try: if "sphinxcontrib.plantuml" not in app.config.extensions: raise ImportError from sphinxcontrib.plantuml import plantuml except ImportError: content = nodes.error() para = nodes.paragraph() text = nodes.Text("PlantUML is not available!", "PlantUML is not available!") para += text content.append(para) node.replace_self(content) continue plantuml_block_text = ".. plantuml::\n" \ "\n" \ " @startuml" \ " @enduml" puml_node = plantuml(plantuml_block_text, **dict()) puml_node["uml"] = "@startuml\n" puml_connections = "" elif current_needlist["layout"] == "table": content = nodes.table() tgroup = nodes.tgroup() id_colspec = nodes.colspec(colwidth=5) title_colspec = nodes.colspec(colwidth=15) type_colspec = nodes.colspec(colwidth=5) status_colspec = nodes.colspec(colwidth=5) links_colspec = nodes.colspec(colwidth=5) tags_colspec = nodes.colspec(colwidth=5) tgroup += [ id_colspec, title_colspec, type_colspec, status_colspec, links_colspec, tags_colspec ] tgroup += nodes.thead( '', nodes.row('', nodes.entry('', nodes.paragraph('', 'ID')), nodes.entry('', nodes.paragraph('', 'Title')), nodes.entry('', nodes.paragraph('', 'Type')), nodes.entry('', nodes.paragraph('', 'Status')), nodes.entry('', nodes.paragraph('', 'Links')), nodes.entry('', nodes.paragraph('', 'Tags')))) tbody = nodes.tbody() tgroup += tbody content += tgroup all_needs = list(all_needs.values()) if current_needlist["sort_by"] is not None: if current_needlist["sort_by"] == "id": all_needs = sorted(all_needs, key=lambda node: node["id"]) elif current_needlist["sort_by"] == "status": all_needs = sorted(all_needs, key=status_sorter) for need_info in all_needs: status_filter_passed = False if need_info["status"] is None or \ need_info["status"] in current_needlist["status"] or \ len(current_needlist["status"]) == 0: status_filter_passed = True tags_filter_passed = False if len(set(need_info["tags"]) & set(current_needlist["tags"])) > 0 or len( current_needlist["tags"]) == 0: tags_filter_passed = True type_filter_passed = False if need_info["type"] in current_needlist["types"] \ or need_info["type_name"] in current_needlist["types"] \ or len(current_needlist["types"]) == 0: type_filter_passed = True if current_needlist["filter"] is None: python_filter_passed = True else: python_filter_passed = False filter_context = { "tags": need_info["tags"], "status": need_info["status"], "type": need_info["type"], "id": need_info["id"], "title": need_info["title"], "links": need_info["links"], "content": need_info["content"], "search": re.search } try: # python_filter_passed = eval(current_needlist["filter"], globals(), filter_context) python_filter_passed = eval(current_needlist["filter"], None, filter_context) except Exception as e: print("Filter {0} not valid: Error: {1}".format( current_needlist["filter"], e)) if status_filter_passed and tags_filter_passed and type_filter_passed and python_filter_passed: if current_needlist["layout"] == "list": para = nodes.line() description = "%s: %s" % (need_info["id"], need_info["title"]) if current_needlist["show_status"] and need_info[ "status"] is not None: description += " (%s)" % need_info["status"] if current_needlist["show_tags"] and need_info[ "tags"] is not None: description += " [%s]" % "; ".join(need_info["tags"]) title = nodes.Text(description, description) # Create a reference if not need_info["hide"]: ref = nodes.reference('', '') ref['refdocname'] = need_info['docname'] ref['refuri'] = app.builder.get_relative_uri( fromdocname, need_info['docname']) ref['refuri'] += '#' + need_info['target_node']['refid'] ref.append(title) para += ref else: para += title content.append(para) elif current_needlist["layout"] == "table": row = nodes.row() row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "id", make_ref=True) row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "title") row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "type_name") row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "status") row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "links", ref_lookup=True) row += row_col_maker(app, fromdocname, env.need_all_needs, need_info, "tags") tbody += row elif current_needlist["layout"] == "diagram": # Link calculation # All links we can get from docutils functions will be relative. # But the generated link in the svg will be relative to the svg-file location # (e.g. server.com/docs/_images/sqwxo499cnq329439dfjne.svg) # and not to current documentation. Therefore we need to add ../ to get out of the _image folder. try: link = "../" + app.builder.get_target_uri(need_info['docname']) \ + "?highlight={0}".format(urlParse(need_info['title'])) \ + "#" \ + need_info['target_node']['refid'] \ # Gets mostly called during latex generation except NoUri: link = "" diagram_template = Template( env.config.needs_diagram_template) node_text = diagram_template.render(**need_info) puml_node[ "uml"] += '{style} "{node_text}" as {id} [[{link}]] {color}\n'.format( id=need_info["id"], node_text=node_text, link=link, color=need_info["type_color"], style=need_info["type_style"]) for link in need_info["links"]: puml_connections += '{id} --> {link}\n'.format( id=need_info["id"], link=link) if current_needlist["layout"] == "diagram": puml_node["uml"] += puml_connections # Create a legend if current_needlist["show_legend"]: puml_node["uml"] += "legend\n" puml_node["uml"] += "|= Color |= Type |\n" for need in app.config.needs_types: puml_node[ "uml"] += "|<back:{color}> {color} </back>| {name} |\n".format( color=need["color"], name=need["title"]) puml_node["uml"] += "endlegend\n" puml_node["uml"] += "@enduml" puml_node["incdir"] = os.path.dirname(current_needlist["docname"]) puml_node["filename"] = os.path.split( current_needlist["docname"])[1] # Needed for plantuml >= 0.9 content.append(puml_node) if len(content) == 0: nothing_found = "No needs passed the filters" para = nodes.line() nothing_found_node = nodes.Text(nothing_found, nothing_found) para += nothing_found_node content.append(para) if current_needlist["show_filters"]: para = nodes.paragraph() filter_text = "Used filter:" filter_text += " status(%s)" % " OR ".join( current_needlist["status"]) if len( current_needlist["status"]) > 0 else "" if len(current_needlist["status"]) > 0 and len( current_needlist["tags"]) > 0: filter_text += " AND " filter_text += " tags(%s)" % " OR ".join( current_needlist["tags"]) if len( current_needlist["tags"]) > 0 else "" if (len(current_needlist["status"]) > 0 or len(current_needlist["tags"]) > 0) and len( current_needlist["types"]) > 0: filter_text += " AND " filter_text += " types(%s)" % " OR ".join( current_needlist["types"]) if len( current_needlist["types"]) > 0 else "" filter_node = nodes.emphasis(filter_text, filter_text) para += filter_node content.append(para) node.replace_self(content)
def render_em_open(self, token): node = nodes.emphasis() self.add_line_and_source_path(node, token) with self.current_node_context(node, append=True): self.render_children(token)
def process_blogtree(app, doctree, fromdocname): env = app.builder.env if env.config.disqus_shortname and doctree.traverse(published_para): node = disqus(classes=['blog-disqus']) node['shortname'] = env.config.disqus_shortname node['identifier'] = "/%s" % fromdocname node['title'] = env.titles[fromdocname][0] node['developer'] = env.config.disqus_developer doctree += node for node in doctree.traverse(blogtree): rss_output = node['output'] rss_title = node['title'] rss_link = node['link'] rss_description = node['description'] rss_items = [] replacement = [] for docname in node['entries']: blogentry = env.get_doctree(docname) for published in blogentry.traverse(published_para): section_node = nodes.section() title = env.titles[docname] section_node['ids'] = blogentry[0]['ids'] author = published['author'] date = published['date'] title_node = nodes.title() ref_node = nodes.reference(classes=['blog-ref']) ref_node['internal'] = True ref_node['refdocname'] = docname ref_node['refuri'] = \ app.builder.get_relative_uri(fromdocname, docname) ref_node['refuri'] += '#' + section_node['ids'][0] ref_node += title[0] title_node += ref_node section_node += title_node para_node = nodes.paragraph(classes=['blog-published']) para_node += nodes.Text(u'Published') if author: para_node += nodes.Text(u' by ') author_node = nodes.emphasis(classes=['blog-author']) author_node += nodes.Text(author) para_node += author_node if date: para_node += nodes.Text(u' on ') date_node = nodes.emphasis(classes=['blog-date']) date_node += nodes.Text(date) para_node += date_node section_node += para_node for subnode in blogentry[0]: if isinstance(subnode, (nodes.title, published_para, disqus)): continue if isinstance(subnode, blogcut): para_node = nodes.paragraph() ref_node = nodes.reference(classes=['blog-more']) ref_node['internal'] = True ref_node['refdocname'] = docname ref_node['refuri'] = \ app.builder.get_relative_uri(fromdocname, docname) ref_node['refuri'] += '#' + section_node['ids'][0] ref_node += nodes.Text(u'Read more\u2026') para_node += ref_node section_node += para_node break section_node += subnode.deepcopy() env.resolve_references(section_node, fromdocname, app.builder) replacement.append(section_node) if rss_output: rss_item_title = title[0] rss_item_link = rss_link + app.builder.get_target_uri( docname) rss_item_description = nodes.compound() for subnode in blogentry[0]: if isinstance(subnode, (nodes.title, published_para, disqus)): continue if isinstance(subnode, blogcut): break rss_item_description += subnode.deepcopy() env.resolve_references(rss_item_description, docname, app.builder) rss_item_description = app.builder.render_partial( rss_item_description)['body'] if date: match = re.match(r'^(\d{4})-(\d{2})-(\d{2})$', date) assert match is not None rss_item_date = datetime.datetime( int(match.group(1)), int(match.group(2)), int(match.group(3))) rss_item = PyRSS2Gen.RSSItem( title=rss_item_title, link=rss_item_link, description=rss_item_description, guid=PyRSS2Gen.Guid(rss_item_link), pubDate=rss_item_date) rss_items.append(rss_item) node.replace_self(replacement) if rss_output: rss_path = os.path.join(app.builder.outdir, rss_output) rss = PyRSS2Gen.RSS2(title=rss_title, link=rss_link, description=rss_description, lastBuildDate=datetime.datetime.utcnow(), items=rss_items) rss.write_xml(open(rss_path, "w"), encoding="utf-8")
def contribute_property(self, prop_list, prop_key, prop): prop_item = nodes.definition_list_item( '', nodes.term('', prop_key)) prop_list.append(prop_item) prop_item.append(nodes.classifier('', prop.type)) definition = nodes.definition() prop_item.append(definition) if prop.support_status.status != support.SUPPORTED: para = nodes.paragraph('', self._status_str(prop.support_status)) note = nodes.note('', para) definition.append(note) if (prop.support_status.status == support.SUPPORTED and prop.support_status.version is not None): tag = prop.support_status.version.title() message = (_('Available since %s.') % self._version_str(tag)) para = nodes.paragraph('', message) note = nodes.note('', para) definition.append(note) if not prop.implemented: para = nodes.paragraph('', _('Not implemented.')) note = nodes.note('', para) definition.append(note) return if prop.description: para = nodes.paragraph('', prop.description) definition.append(para) if prop.update_allowed: para = nodes.paragraph('', _('Can be updated without replacement.')) definition.append(para) elif prop.immutable: para = nodes.paragraph('', _('Updates are not supported. ' 'Resource update will fail on any ' 'attempt to update this property.')) definition.append(para) else: para = nodes.paragraph('', _('Updates cause replacement.')) definition.append(para) if prop.required: para = nodes.paragraph('', _('Required property.')) elif prop.default is not None: para = nodes.paragraph( '', _('Optional property, defaults to "%s".') % prop.default) else: para = nodes.paragraph('', _('Optional property.')) definition.append(para) for constraint in prop.constraints: para = nodes.paragraph('', str(constraint)) definition.append(para) sub_schema = None if prop.schema and prop.type == properties.Schema.MAP: para = nodes.paragraph() emph = nodes.emphasis('', _('Map properties:')) para.append(emph) definition.append(para) sub_schema = prop.schema elif prop.schema and prop.type == properties.Schema.LIST: para = nodes.paragraph() emph = nodes.emphasis('', _('List contents:')) para.append(emph) definition.append(para) sub_schema = prop.schema if sub_schema: sub_prop_list = nodes.definition_list() definition.append(sub_prop_list) for sub_prop_key, sub_prop in sorted(sub_schema.items(), self.cmp_prop): self.contribute_property( sub_prop_list, sub_prop_key, sub_prop)
def abstract_name(self, name): self._current_node += nodes.emphasis(text=name, rawsource=name)
def list_role(self, role, rawtext, text, lineno): return [nodes.emphasis(rawtext, text)], []
def handle_doc_fields(self, node): """ Convert field lists with known keys inside the description content into better-looking equivalents. """ # don't traverse, only handle field lists that are immediate children for child in node.children: if not isinstance(child, nodes.field_list): continue params = [] pfield = None param_nodes = {} param_types = {} new_list = nodes.field_list() for field in child: fname, fbody = field try: typ, obj = fname.astext().split(None, 1) typdesc = _(self.doc_fields_with_arg[typ]) if _is_only_paragraph(fbody): children = fbody.children[0].children else: children = fbody.children if typdesc == '%param': if not params: # add the field that later gets all the parameters pfield = nodes.field() new_list += pfield dlitem = nodes.list_item() dlpar = nodes.paragraph() dlpar += nodes.emphasis(obj, obj) dlpar += nodes.Text(' -- ', ' -- ') dlpar += children param_nodes[obj] = dlpar dlitem += dlpar params.append(dlitem) elif typdesc == '%type': typenodes = fbody.children if _is_only_paragraph(fbody): typenodes = ([nodes.Text(' (')] + typenodes[0].children + [nodes.Text(')')]) param_types[obj] = typenodes else: fieldname = typdesc + ' ' nfield = nodes.field() nfieldname = nodes.field_name(fieldname, fieldname) nfield += nfieldname node = nfieldname if typ in self.doc_fields_with_linked_arg: node = addnodes.pending_xref( obj, reftype='obj', refcaption=False, reftarget=obj, modname=self.env.currmodule, classname=self.env.currclass) nfieldname += node node += nodes.Text(obj, obj) nfield += nodes.field_body() nfield[1] += fbody.children new_list += nfield except (KeyError, ValueError): fnametext = fname.astext() try: typ = _(self.doc_fields_without_arg[fnametext]) except KeyError: # at least capitalize the field name typ = fnametext.capitalize() fname[0] = nodes.Text(typ) new_list += field if params: if len(params) == 1: pfield += nodes.field_name('', _('Parameter')) pfield += nodes.field_body() pfield[1] += params[0][0] else: pfield += nodes.field_name('', _('Parameters')) pfield += nodes.field_body() pfield[1] += nodes.bullet_list() pfield[1][0].extend(params) for param, type in param_types.iteritems(): if param in param_nodes: param_nodes[param][1:1] = type child.replace_self(new_list)
def construct_meta(need_data, env): """ Constructs the node-structure for the status container :param need_data: need_info container :return: node """ hide_options = env.config.needs_hide_options if not isinstance(hide_options, list): raise SphinxError( 'Config parameter needs_hide_options must be of type list') node_meta = nodes.line_block(classes=['needs_meta']) # need parameters param_status = "status: " param_tags = "tags: " if need_data["status"] is not None and 'status' not in hide_options: status_line = nodes.line(classes=['status']) # node_status = nodes.line(param_status, param_status, classes=['status']) node_status = nodes.inline(param_status, param_status, classes=['status']) status_line.append(node_status) status_line.append( nodes.inline(need_data["status"], need_data["status"], classes=["needs-status", str(need_data['status'])])) node_meta.append(status_line) if need_data["tags"] and 'tags' not in hide_options: tag_line = nodes.line(classes=['tags']) # node_tags = nodes.line(param_tags, param_tags, classes=['tags']) node_tags = nodes.inline(param_tags, param_tags, classes=['tags']) tag_line.append(node_tags) for tag in need_data['tags']: # node_tags.append(nodes.inline(tag, tag, classes=["needs-tag", str(tag)])) # node_tags.append(nodes.inline(' ', ' ')) tag_line.append( nodes.emphasis(tag, tag, classes=["needs-tag", str(tag)])) tag_line.append(nodes.inline(" ", " ")) node_meta.append(tag_line) # Links incoming if need_data['links_back'] and 'links_back' not in hide_options: node_incoming_line = nodes.line(classes=['links', 'incoming']) prefix = "links incoming: " node_incoming_prefix = nodes.inline(prefix, prefix) node_incoming_line.append(node_incoming_prefix) node_incoming_links = Need_incoming(reftarget=need_data['id']) node_incoming_links.append( nodes.inline(need_data['id'], need_data['id'])) node_incoming_line.append(node_incoming_links) node_meta.append(node_incoming_line) # # Links outgoing if need_data['links'] and 'links' not in hide_options: node_outgoing_line = nodes.line(classes=['links', 'outgoing']) prefix = "links outgoing: " node_outgoing_prefix = nodes.inline(prefix, prefix) node_outgoing_line.append(node_outgoing_prefix) node_outgoing_links = Need_outgoing(reftarget=need_data['id']) node_outgoing_links.append( nodes.inline(need_data['id'], need_data['id'])) node_outgoing_line.append(node_outgoing_links) node_meta.append(node_outgoing_line) extra_options = getattr(env.config, 'needs_extra_options', {}) node_extra_options = [] for key, value in extra_options.items(): if key in hide_options: continue param_data = need_data[key] if param_data is None or not param_data: continue param_option = '{}: '.format(key) option_line = nodes.line(classes=['extra_option']) option_line.append( nodes.inline(param_option, param_option, classes=['extra_option'])) option_line.append( nodes.inline(param_data, param_data, classes=["needs-extra-option", str(key)])) node_extra_options.append(option_line) node_meta += node_extra_options global_options = getattr(env.config, 'needs_global_options', {}) node_global_options = [] for key, value in global_options.items(): # If a global option got locally overwritten, it must already part of extra_options. # In this skipp output, as this is done during extra_option handling if key in extra_options or key in hide_options: continue param_data = need_data[key] if param_data is None or not param_data: continue param_option = '{}: '.format(key) global_option_line = nodes.line(classes=['global_option']) global_option_line.append( nodes.inline(param_option, param_option, classes=['global_option'])) global_option_line.append( nodes.inline(param_data, param_data, classes=["needs-global-option", str(key)])) node_global_options.append(global_option_line) node_meta += node_global_options return node_meta
def contribute_property(self, parent, prop_key, prop, upd_para=None, id_pattern_prefix=None, sub_prop=False): if not id_pattern_prefix: id_pattern_prefix = '%s-prop' id_pattern = id_pattern_prefix + '-' + prop_key definition = self._prop_section(parent, prop_key, id_pattern) self._status_str(prop.support_status, definition) if not prop.implemented: para = nodes.line('', _('Not implemented.')) note = nodes.note('', para) definition.append(note) return if sub_prop and prop.type not in (properties.Schema.LIST, properties.Schema.MAP): if prop.required: para = nodes.line('', _('Required.')) definition.append(para) else: para = nodes.line('', _('Optional.')) definition.append(para) if prop.description: para = nodes.line('', prop.description) definition.append(para) type = nodes.line('', _('%s value expected.') % prop.type) definition.append(type) if upd_para is not None: definition.append(upd_para) else: if prop.update_allowed: upd_para = nodes.line( '', _('Can be updated without replacement.')) definition.append(upd_para) elif prop.immutable: upd_para = nodes.line('', _('Updates are not supported. ' 'Resource update will fail on ' 'any attempt to update this ' 'property.')) definition.append(upd_para) else: upd_para = nodes.line('', _('Updates cause replacement.')) definition.append(upd_para) if prop.default is not None: para = nodes.line('', _('Defaults to ')) default = nodes.literal('', json.dumps(prop.default)) para.append(default) definition.append(para) for constraint in prop.constraints: para = nodes.line('', str(constraint)) definition.append(para) sub_schema = None if prop.schema and prop.type == properties.Schema.MAP: para = nodes.line() emph = nodes.emphasis('', _('Map properties:')) para.append(emph) definition.append(para) sub_schema = prop.schema elif prop.schema and prop.type == properties.Schema.LIST: para = nodes.line() emph = nodes.emphasis('', _('List contents:')) para.append(emph) definition.append(para) sub_schema = prop.schema if sub_schema: indent = nodes.definition_list() definition.append(indent) for _key, _prop in sorted(sub_schema.items(), key=cmp_to_key(self.cmp_prop)): if _prop.support_status.status != support.HIDDEN: self.contribute_property( indent, _key, _prop, upd_para, id_pattern, sub_prop=True)