def run(self): if not (self.state_machine.match_titles or isinstance(self.state_machine.node, nodes.sidebar)): raise self.error('The "%s" directive may not be used within ' "topics or body elements." % self.name) document = self.state_machine.document language = languages.get_language(document.settings.language_code) if self.arguments: title_text = self.arguments[0] text_nodes, messages = self.state.inline_text(title_text, self.lineno) title = nodes.title(title_text, "", *text_nodes) else: messages = [] if self.options.has_key("local"): title = None else: title = nodes.title("", language.labels["contents"]) topic = nodes.topic(classes=["contents"]) topic["classes"] += self.options.get("class", []) if self.options.has_key("local"): topic["classes"].append("local") if title: name = title.astext() topic += title else: name = language.labels["contents"] name = nodes.fully_normalize_name(name) if not document.has_name(name): topic["names"].append(name) document.note_implicit_target(topic) pending = nodes.pending(parts.Contents, rawsource=self.block_text) pending.details.update(self.options) document.note_pending(pending) topic += pending return [topic] + messages
def _render_service(self, path, service, methods): env = self.state.document.settings.env service_id = "service-%d" % env.new_serialno('service') service_node = nodes.section(ids=[service_id]) service_node += nodes.title(text='Service at %s' % service.route_name) if service.description is not None: service_node += rst2node(_dedent(service.description)) for method, info in methods.items(): method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) node = rst2node(_dedent(info['docstring'])) if node is not None: method_node += node renderer = info['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node
def test_ids_generated(self): from docutils import utils, nodes from docutils.core import publish_from_doctree doc = utils.new_document('<program>') docsect = nodes.section('') docsect['classes'] = ('c1 c2',) docsect['ids'] = ('my-test-id',) docsect['target-ids'] = ('my-test-id',) docsect.append(nodes.title('', '', nodes.Text('Title'))) docsect.append(nodes.paragraph('', '', nodes.Text('some text.'))) docsect.append( nodes.section( '', nodes.title('', '', nodes.Text('Sub-Title')), nodes.paragraph('', '', nodes.Text('some more text')))) doc.append(docsect) chk = '''\ .. class:: c1 c2 .. _`my-test-id`: ====== Title ====== some text. --------- Sub-Title --------- some more text ''' out = publish_from_doctree(doc, writer=rst.Writer()) self.assertMultiLineEqual(out, chk)
def depart_Resource(self, node): if node['identifier']: node.insert(0, nodes.title(text=node['identifier'])) else: node.insert(0, nodes.title(text=node['uri'])) replace_nodeclass(node, nodes.section)
def formatComponent(self, moduleName, name, X): # no class bases available from repository scanner CLASSNAME = self.formatClassStatement(name, X.bases) CLASSDOC = self.docString(X.doc) INBOXES = self.boxes(name,"Inboxes", X.inboxes) OUTBOXES = self.boxes(name,"Outboxes", X.outboxes) if self.config.includeMethods and len(X.listAllFunctions()): METHODS = [ nodes.section('', nodes.title('', 'Methods defined here'), boxright('', nodes.paragraph('', '', nodes.strong('', nodes.Text("Warning!")) ), nodes.paragraph('', '', nodes.Text("You should be using the inbox/outbox interface, not these methods (except construction). This documentation is designed as a roadmap as to their functionalilty for maintainers and new component developers.") ), ), * self.formatMethodDocStrings(name,X) ) ] else: METHODS = [] return \ nodes.section('', * [ nodes.title('', CLASSNAME, ids=["symbol-"+name]) ] + CLASSDOC + [ INBOXES, OUTBOXES ] + METHODS + [ self.formatInheritedMethods(name,X) ] )
def _render_service(self, path, service, methods): env = self.state.document.settings.env service_id = "service-%d" % env.new_serialno('service') service_node = nodes.section(ids=[service_id]) service_node += nodes.title(text='Service at %s' % service.route_name) if service.description is not None: service_node += rst2node(_dedent(service.description)) for method, info in methods.items(): method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) docstring = info['func'].__doc__ or "" if 'validator' in info: validators = to_list(info['validator']) for validator in validators: if validator.__doc__ is not None: if docstring is not None: docstring += '\n' + validator.__doc__.strip() if 'accept' in info: accept = info['accept'] if callable(accept): if accept.__doc__ is not None: docstring += accept.__doc__.strip() else: accept = to_list(accept) accept_node = nodes.strong(text='Accepted content types:') node_accept_list = nodes.bullet_list() accept_node += node_accept_list for item in accept: temp = nodes.list_item() temp += nodes.inline(text=item) node_accept_list += temp method_node += accept_node node = rst2node(docstring) if node is not None: method_node += node renderer = info['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node
def render(service, service_id): service_node = nodes.section(ids=[service_id]) title = "%s service" % service.baseRouteName service_node += nodes.title(text=title) if service.description is not None: service_node += create_node(trim(service.description)) for pattern, route_kw, view_kw, func, schema in service.methods: method = route_kw.get('request_method', 'GET') method_id = "%s_%s" % (service_id, method) method_node = nodes.section(ids=[method_id]) desc = func.__doc__ title = None if desc: # use the first line as title for the endpoint sp = desc.split('\n', 1) title = sp[0].strip() if len(sp) > 1: desc = sp[1].strip() else: desc = '' if not title: title = '%s - %s' % (method, pattern) method_node += nodes.title(text=title) url = "::\n\n \n %s - %s\n\n" % (method, pattern) method_node += create_node(url) # render description from docstring if desc: method_node += create_node(trim(desc)) accept = route_kw.get('accept') content_type = route_kw.get('content_type') # Render Accept Header documentation if accept: accept_desc = 'Accept: %s' % accept method_node += create_node(accept_desc) # Render Content-Type Header documentation if content_type: content_desc = 'Content-Type: %s' % content_type method_node += create_node(content_desc) # Render Validator if schema: schema_id = "%s_%s_%s" % (service_id, method, 'validator') node = nodes.section(ids=[schema_id]) title = nodes.title(text='Validation Schema') node += title text = json.dumps(schema, indent=4) # indent the text block text = '\n '.join([l for l in text.splitlines()]) text = '::\n\n ' + text + '\n\n' node += create_node(text) method_node += node service_node += method_node return service_node
def print_subcommands(data, nested_content, markDownHelp=False, settings=None): """ Each subcommand is a dictionary with the following keys: ['usage', 'action_groups', 'bare_usage', 'name', 'help'] In essence, this is all tossed in a new section with the title 'name'. Apparently there can also be a 'description' entry. """ definitions = map_nested_definitions(nested_content) items = [] if 'children' in data: subCommands = nodes.section(ids=["Sub-commands:"]) subCommands += nodes.title('Sub-commands:', 'Sub-commands:') for child in data['children']: sec = nodes.section(ids=[child['name']]) sec += nodes.title(child['name'], child['name']) if 'description' in child and child['description']: desc = [child['description']] elif child['help']: desc = [child['help']] else: desc = ['Undocumented'] # Handle nested content subContent = [] if child['name'] in definitions: classifier, s, subContent = definitions[child['name']] if classifier == '@replace': desc = [s] elif classifier == '@after': desc.append(s) elif classifier == '@before': desc.insert(0, s) for element in renderList(desc, markDownHelp): sec += element sec += nodes.literal_block(text=child['bare_usage']) for x in print_action_groups(child, nested_content + subContent, markDownHelp, settings=settings): sec += x for x in print_subcommands(child, nested_content + subContent, markDownHelp, settings=settings): sec += x if 'epilog' in child and child['epilog']: for element in renderList([child['epilog']], markDownHelp): sec += element subCommands += sec items.append(subCommands) return items
def run(self): minimal = self.options.get('minimal') module = self.arguments[0] template_args = {} template_args.update(get_authors()) get_argparser = __import__(str(module), fromlist=[str('get_argparser')]).get_argparser parser = get_argparser(AutoManParser) if minimal: container = nodes.container() container += parser.automan_usage(self.options['prog']) container += parser.automan_description() return [container] synopsis_section = nodes.section( '', nodes.title(text='Synopsis'), ids=['synopsis-section'], ) synopsis_section += parser.automan_usage(self.options['prog']) description_section = nodes.section( '', nodes.title(text='Description'), ids=['description-section'], ) description_section += parser.automan_description() author_section = nodes.section( '', nodes.title(text='Author'), nodes.paragraph( '', nodes.Text('Written by {authors} and contributors. The glyphs in the font patcher are created by {glyphs_author}.'.format( **get_authors() )) ), ids=['author-section'] ) issues_url = 'https://github.com/powerline/powerline/issues' reporting_bugs_section = nodes.section( '', nodes.title(text='Reporting bugs'), nodes.paragraph( '', nodes.Text('Report {prog} bugs to '.format( prog=self.options['prog'])), nodes.reference( issues_url, issues_url, refuri=issues_url, internal=False, ), nodes.Text('.'), ), ids=['reporting-bugs-section'] ) return [synopsis_section, description_section, author_section, reporting_bugs_section]
def build_http_method_section(self, resource, http_method): doc = self.get_doc_for_http_method(resource, http_method) http_method_func = self.get_http_method_func(resource, http_method) # Description text returned_nodes = [ parse_text(self, doc, where='HTTP %s doc' % http_method) ] # Request Parameters section required_fields = getattr(http_method_func, 'required_fields', []) optional_fields = getattr(http_method_func, 'optional_fields', []) if required_fields or optional_fields: all_fields = dict(required_fields) all_fields.update(optional_fields) fields_section = nodes.section(ids=['%s_params' % http_method]) returned_nodes.append(fields_section) fields_section += nodes.title(text='Request Parameters') table = self.build_fields_table(all_fields, required_fields=required_fields, show_requirement_labels=True) fields_section += table # Errors section errors = getattr(http_method_func, 'response_errors', []) if errors: errors_section = nodes.section(ids=['%s_errors' % http_method]) returned_nodes.append(errors_section) errors_section += nodes.title(text='Errors') bullet_list = nodes.bullet_list() errors_section += bullet_list for error in sorted(errors, key=lambda x: x.code): item = nodes.list_item() bullet_list += item paragraph = nodes.paragraph() item += paragraph paragraph += get_ref_to_error(error) return returned_nodes
def contents(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): """ Table of contents. The table of contents is generated in two passes: initial parse and transform. During the initial parse, a 'pending' element is generated which acts as a placeholder, storing the TOC title and any options internally. At a later stage in the processing, the 'pending' element is replaced by a 'topic' element, a title and the table of contents proper. """ if not (state_machine.match_titles or isinstance(state_machine.node, nodes.sidebar)): error = state_machine.reporter.error( 'The "%s" directive may not be used within topics ' 'or body elements.' % name, nodes.literal_block(block_text, block_text), line=lineno) return [error] document = state_machine.document language = languages.get_language(document.settings.language_code) if arguments: title_text = arguments[0] text_nodes, messages = state.inline_text(title_text, lineno) title = nodes.title(title_text, '', *text_nodes) else: messages = [] if options.has_key('local'): title = None else: title = nodes.title('', language.labels['contents']) topic = nodes.topic(classes=['contents']) topic['classes'] += options.get('class', []) if options.has_key('local'): topic['classes'].append('local') if title: name = title.astext() topic += title else: name = language.labels['contents'] name = nodes.fully_normalize_name(name) if not document.has_name(name): topic['names'].append(name) document.note_implicit_target(topic) pending = nodes.pending(parts.Contents, rawsource=block_text) pending.details.update(options) document.note_pending(pending) topic += pending return [topic] + messages
def topic(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine, node_class=nodes.topic): if not (state_machine.match_titles or isinstance(state_machine.node, nodes.sidebar)): error = state_machine.reporter.error( 'The "%s" directive may not be used within topics ' 'or body elements.' % name, nodes.literal_block(block_text, block_text), line=lineno) return [error] if not content: warning = state_machine.reporter.warning( 'Content block expected for the "%s" directive; none found.' % name, nodes.literal_block(block_text, block_text), line=lineno) return [warning] title_text = arguments[0] textnodes, messages = state.inline_text(title_text, lineno) titles = [nodes.title(title_text, '', *textnodes)] # sidebar uses this code if options.has_key('subtitle'): textnodes, more_messages = state.inline_text(options['subtitle'], lineno) titles.append(nodes.subtitle(options['subtitle'], '', *textnodes)) messages.extend(more_messages) text = '\n'.join(content) node = node_class(text, *(titles + messages)) node['classes'] += options.get('class', []) if text: state.nested_parse(content, content_offset, node) return [node]
def _section(self, parent, title, id_pattern): id = id_pattern % self.resource_type section = nodes.section(ids=[id]) parent.append(section) title = nodes.title('', title) section.append(title) return section
def apply(self): doc = self.document i = len(doc) - 1 refsect = copyright = None while i >= 0 and isinstance(doc[i], nodes.section): title_words = doc[i][0].astext().lower().split() if 'references' in title_words: refsect = doc[i] break elif 'copyright' in title_words: copyright = i i -= 1 if not refsect: refsect = nodes.section() refsect += nodes.title('', 'References') doc.set_id(refsect) if copyright: # Put the new "References" section before "Copyright": doc.insert(copyright, refsect) else: # Put the new "References" section at end of doc: doc.append(refsect) pending = nodes.pending(references.TargetNotes) refsect.append(pending) self.document.note_pending(pending, 0) pending = nodes.pending(misc.CallBack, details={'callback': self.cleanup_callback}) refsect.append(pending) self.document.note_pending(pending, 1)
def render_cmd(app, node, usage, description): title = node.get('title') titleid = idregex.sub('-', title).lower() section = nodes.section('', ids=[titleid]) if title: section.append(nodes.title(title, title)) output = "$ {}".format(usage) new_node = nodes.literal_block(output, output) new_node['language'] = 'text' section.append(new_node) settings = docutils.frontend.OptionParser( components=(docutils.parsers.rst.Parser,) ).get_default_values() document = docutils.utils.new_document('', settings) parser = docutils.parsers.rst.Parser() description = inline_literal_regex.sub('``', description) description = link_regex.sub(r'`\1 <\2>`_', description) description = flag_default_regex.sub(r'\1 (\2)', description) parser.parse(description, document) for el in document.children: section.append(el) node.replace_self(section)
def new_subsection(self, level, title, lineno, messages): """Append new subsection to document tree. On return, check level.""" memo = self.memo mylevel = memo.section_level memo.section_level += 1 section_node = nodes.section() self.parent += section_node textnodes, title_messages = self.inline_text(title, lineno) titlenode = nodes.title(title, '', *textnodes) name = normalize_name(titlenode.astext()) section_node['names'].append(name) section_node += titlenode section_node += messages section_node += title_messages self.document.note_implicit_target(section_node, section_node) offset = self.state_machine.line_offset + 1 absoffset = self.state_machine.abs_line_offset() + 1 newabsoffset = self.nested_parse( self.state_machine.input_lines[offset:], input_offset=absoffset, node=section_node, match_titles=1) self.goto_line(newabsoffset) if memo.section_level <= mylevel: # can't handle next section? raise EOFError # bubble up to supersection # reset section_level; next pass will detect it properly memo.section_level = mylevel
def run(self): language = self.arguments[0] indexed_languages = self.options.get('index_as') or language index_specs = ['pair: {}; language'.format(l) for l in indexed_languages.splitlines()] name = nodes.fully_normalize_name(language) target = 'language-{}'.format(name) targetnode = nodes.target('', '', ids=[target]) self.state.document.note_explicit_target(targetnode) indexnode = addnodes.index() indexnode['entries'] = [] indexnode['inline'] = False set_source_info(self, indexnode) for spec in index_specs: indexnode['entries'].extend(process_index_entry(spec, target)) sectionnode = nodes.section() sectionnode['names'].append(name) title, messages = self.state.inline_text(language, self.lineno) titlenode = nodes.title(language, '', *title) sectionnode += titlenode sectionnode += messages self.state.document.note_implicit_target(sectionnode, sectionnode) self.state.nested_parse(self.content, self.content_offset, sectionnode) return [indexnode, targetnode, sectionnode]
def visit_admonition(self, node, type=None): clss = { # ???: 'alert-success', 'note': 'alert-info', 'hint': 'alert-info', 'tip': 'alert-info', 'seealso': 'alert-go_to', 'warning': 'alert-warning', 'attention': 'alert-warning', 'caution': 'alert-warning', 'important': 'alert-warning', 'danger': 'alert-danger', 'error': 'alert-danger', 'exercise': 'alert-exercise', } self.body.append(self.starttag(node, 'div', role='alert', CLASS='alert {}'.format( clss.get(type, '') ))) if 'alert-dismissible' in node.get('classes', []): self.body.append( u'<button type="button" class="close" data-dismiss="alert" aria-label="Close">' u'<span aria-hidden="true">×</span>' u'</button>') if type: node.insert(0, nodes.title(type, admonitionlabels[type]))
def run(self): classes = self.options.get('class', []) classes.extend(self.options.get('header_class', '').split(' ')) self.options['class'] = classes set_classes(self.options) self.assert_has_content() text = '\n'.join(self.content) admonition_node = self.node_class(text, **self.options) self.add_name(admonition_node) if self.node_class is nodes.admonition: title_text = self.arguments[0] textnodes, messages = self.state.inline_text(title_text, self.lineno) admonition_node += nodes.title(title_text, '', *textnodes) admonition_node += messages if not 'classes' in self.options: admonition_node['classes'] += [ 'admonition-' + nodes.make_id(title_text) ] body = nodes.container( classes=self.options.get('body_class', '').split(' ') ) self.state.nested_parse(self.content, self.content_offset, body) return [admonition_node, body]
def run(self): env = self.state.document.settings.env # getting the options pkg = self.options['package'] service_name = self.options.get('service') all_services = service_name is None # listing the services for the package services = self._get_services(pkg) if all_services: # we want to list all of them services_id = "services-%d" % env.new_serialno('services') services_node = nodes.section(ids=[services_id]) services_node += nodes.title(text='Services') services_ = [(service.index, path, service, methods) \ for (path, service), methods in services.items()] services_.sort() for _, path, service, methods in services_: services_node += self._render_service(path, service, methods) return [services_node] else: # we just want a single service # # XXX not efficient for (path, service), methods in services.items(): if service.name != service_name: continue return [self._render_service(path, service, methods)] return []
def visit_admonition(self, node, name=''): # type: (nodes.Node, unicode) -> None self.body.append(self.starttag( node, 'div', CLASS=('admonition ' + name))) if name: node.insert(0, nodes.title(name, admonitionlabels[name])) self.set_first_last(node)
def make_title_ref(title_text, link): ref = make_reference(' (details)', link) t = nodes.Text(title_text) # A title can only contain text and inline elements. # Therefore, the text and reference elements need to be passed directly # as children and not combined in a paragraph or other element. return nodes.title('', '', t, ref)
def run(self): # largely lifted from the superclass in order to make titles work set_classes(self.options) # self.assert_has_content() text = '\n'.join(self.content) admonition_node = self.node_class(text, **self.options) self.add_name(admonition_node) if self.arguments: title_text = self.arguments[0] textnodes, messages = self.state.inline_text(title_text, self.lineno) admonition_node += nodes.title(title_text, '', *textnodes) admonition_node += messages else: # no title, make something up so we have an ID title_text = str(hash(' '.join(self.content))) if not 'classes' in self.options: admonition_node['classes'] += ['admonition-' + nodes.make_id(title_text)] self.state.nested_parse(self.content, self.content_offset, admonition_node) return [admonition_node]
def _notes(self, device): """Extract and combine notes from a device Returns a section, including a title or ``None`` if there are no notes. """ section = nodes.section(ids=[device['name'] + '-notes'], names=[device['name'] + '\\ notes']) section += nodes.title(text='Notes') result = ViewList() has_notes = False if 'notes' in device: has_notes = True for line in device['notes']: result.append(line, device['source_file'], device['source_line']) if 'mode_info' in device: for mode in device['mode_info']: if 'notes' in mode: has_notes = True for line in mode['notes']: result.append(line, device['source_file'], device['source_line']) if 'cmd_info' in device: for cmd in device['cmd_info']: if 'notes' in cmd: has_notes = True for line in cmd['notes']: result.append(line, device['source_file'], device['source_line']) self.state.nested_parse(result, 0, section) return has_notes and section or None
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 _make_title_node(self, node, increment=True): """Generate a new title node for ``node``. ``node`` is a ``nextslide`` node. The title will use the node's parent's title, or the title specified as an argument. """ parent_title_node = node.parent.next_node(nodes.title) nextslide_info = getattr( parent_title_node, 'nextslide_info', (parent_title_node.astext(), 1), ) nextslide_info = ( nextslide_info[0], nextslide_info[1] + 1, ) if node.args: title_text = node.args[0] elif 'increment' in node.attributes: # autogenerating titles; title_text = '%s (%d)' % nextslide_info else: title_text = nextslide_info[0] new_title = nodes.title( '', title_text, ) new_title.nextslide_info = nextslide_info return new_title
def _build_program_options(self, parser, custom_content): """ Build list of program options :param parser: pre-configured ArgumentParser instance :param custom_content: custom content for options :return: node forming program options """ result = nodes.container() if self.ignore_option_groups: actions = parser._get_positional_actions() + parser._get_optional_actions() actions = [a for a in actions if a.help is not SUPPRESS] for action in actions: cc = [v for k, v in custom_content.items() if k in action.option_strings] result.append(self._build_option(parser, action, cc[0] if cc else None)) else: for group in parser._action_groups: actions = [a for a in group._group_actions if a.help is not SUPPRESS] if actions: title = nodes.title(text=group.title.capitalize()) options = nodes.container() for action in actions: cc = [v for k, v in custom_content.items() if k in action.option_strings] options.append(self._build_option(parser, action, cc[0] if cc else None)) result.append(nodes.section('', title, options, ids=[group.title.lower()])) return result
def apply(self): if self.document.form_processor.messages: messages = nodes.section() messages += nodes.title('','Form messages') messages += self.document.form_processor.messages self.document += messages self.document.form_processor.messages[:] = []
def _construct_main_sections(self, parser): """ Construct Synopsis, Description and Options sections :param parser: pre-configured ArgumentParser instance :return: list of section nodes """ cc_sections, cc_options = self._get_custom_content() result = [] for section in ['synopsis', 'description', 'options']: method = '_build_program_{}'.format(section) method = getattr(self, method) args = [parser] if section == 'options': args.append(cc_options) title = nodes.title(text=section.upper()) content = method(*args) if section in cc_sections: cc = cc_sections[section] if cc['action'] == 'append': content.extend(cc['content'].children) elif cc['action'] == 'prepend': content[0:0] = cc['content'].children elif cc['action'] == 'replace': content[:] = cc['content'] else: # append empty paragraph to ensure separation from consecutive section content.append(nodes.paragraph(text='')) result.append(nodes.section('', title, content, ids=[section.lower()])) return result
def html_add_content(app, doctree, docname): field_list = doctree.next_node(nodes.field_list) task_id = '' if field_list: for field in field_list.traverse(nodes.field): field_name = field.next_node(nodes.field_name).astext() if field_name == 'task_id': task_id = field.next_node(nodes.field_body).astext() field_list.parent.remove(field_list) builder = app.builder if not hasattr(builder, 'format') or builder.format != 'html': return h = hashlib.md5(str(doctree)).hexdigest() title = '' node = doctree for t in doctree.traverse(nodes.title): title = t.children[0].astext() node = t.parent break section = nodes.section(ids=["checker"], name=["checker"]) section += nodes.title(text=translations[language]['verify_title']) text = u'<div id="results" style="display: none;"></div>' if app.config.mcq_inginious_url and task_id: text += '<input type="submit" value="' + translations[language]['verify'] + '" id="submit" />' section += nodes.raw(format='html', text=text) node += section js = nodes.raw(format='html') js += nodes.Text(u'\n<script type="text/javascript">var language = "' + unicode(language) + '";' u' var upload_url = "' + unicode(app.config.mcq_upload_url) + '";' u' var hash = "' + unicode(h) + '"; var title = "' + unicode(title) + '";' u' var html_title = "' + unicode(app.config.html_title) + '";') if app.config.mcq_inginious_url and task_id: js += nodes.Text(u' var task_id = "' + unicode(task_id) + '"; var inginious_url = "' + unicode(app.config.mcq_inginious_url) + '";') js += nodes.Text(u'</script>'); doctree += js
def create_title(self, text: str): # title nodes may only be inserted as children of section nodes return nodes.title(text=text)
def title(node): """ A title node. It has no children """ return nodes.title(node.first_child.literal, node.first_child.literal)
def format_path(self, path_doc): container = n.section(ids=[n.make_id(path_doc["path"])], names=[]) container += n.title(text=path_doc["path"]) container.append(n.paragraph(text=path_doc["description"])) container.append(self.format_operation(path_doc["operations"])) return container
def fill_node(self, node, env, tag, p, language_code, targetnode, sharepost): """ Fill the node of an aggregated page. """ # add a label suffix_label = self.suffix_label() container = nodes.container() tnl = [".. _{0}{1}:".format(tag, suffix_label), ""] content = StringList(tnl) self.state.nested_parse(content, self.content_offset, container) node += container # id section if env is not None: mid = int(env.new_serialno('indexblog-u-%s' % p["date"][:4])) + 1 else: mid = -1 # add title sids = "y{0}-{1}".format(p["date"][:4], mid) section = nodes.section(ids=[sids]) section['year'] = p["date"][:4] section['blogmid'] = mid node += section textnodes, messages = self.state.inline_text(p["title"], self.lineno) section += nodes.title(p["title"], '', *textnodes) section += messages # add date and share buttons tnl = [":bigger:`::5:{0}`".format(p["date"])] if sharepost is not None: tnl.append(":sharenet:`{0}`".format(sharepost)) tnl.append('') content = StringList(tnl) content = content + self.content # parse the content into sphinx directive, # it adds it to section container = nodes.container() # nested_parse_with_titles(self.state, content, paragraph) self.state.nested_parse(content, self.content_offset, container) section += container # final p['blogpost'] = node self.exe_class = p.copy() p["content"] = content node['classes'] += ["blogpost"] # target # self.state.add_target(p['title'], '', targetnode, lineno) # index (see site-packages/sphinx/directives/code.py, class Index) if self.__class__.add_index: # it adds an index # self.state.document.note_explicit_target(targetnode) indexnode = addnodes.index() indexnode['entries'] = ne = [] indexnode['inline'] = False set_source_info(self, indexnode) for entry in set(p["keywords"] + p["categories"] + [p["date"]]): ne.extend(process_index_entry(entry, tag)) # targetid)) ns = [indexnode, targetnode, node] else: ns = [targetnode, node] return ns
def visit_exercise(self, node): self.body.append(self.starttag(node, 'div', CLASS=('admonition exercise'))) node.insert(0, nodes.title('exercise', 'Exercise')) self.set_first_last(node)
def visit_admonition(self, node: Element, name: str = '') -> None: self.body.append( self.starttag(node, 'div', CLASS=('admonition ' + name))) if name: node.insert(0, nodes.title(name, admonitionlabels[name])) self.set_first_last(node)
def visit_admonition(self, node, name=''): self.body.append(self.starttag( node, 'div', CLASS=('admonition ' + name))) if name and name != 'seealso': node.insert(0, nodes.title(name, admonitionlabels[name])) self.set_first_last(node)
class ErrorDirective(Directive): has_content = True final_argument_whitespace = True option_spec = { 'instance': directives.unchanged_required, 'example-data': directives.unchanged, 'title': directives.unchanged, } MIMETYPES = [ 'application/json', ] def run(self): try: error_obj = self.get_error_object(self.options['instance']) except ErrorNotFound, e: return e.error_node # Add the class's file and this extension to the dependencies. self.state.document.settings.env.note_dependency(__file__) self.state.document.settings.env.note_dependency( sys.modules[error_obj.__module__].__file__) docname = 'webapi2.0-error-%s' % error_obj.code error_title = self.get_error_title(error_obj) targetnode = nodes.target('', '', ids=[docname], names=[docname]) self.state.document.note_explicit_target(targetnode) main_section = nodes.section(ids=[docname]) # Details section main_section += nodes.title(text=error_title) main_section += self.build_details_table(error_obj) # Example section examples_section = nodes.section(ids=['examples']) examples_section += nodes.title(text='Examples') extra_params = {} if 'example-data' in self.options: extra_params = json.loads(self.options['example-data']) has_examples = False for mimetype in self.MIMETYPES: headers, data = \ fetch_response_data(WebAPIResponseError, mimetype, err=error_obj, extra_params=extra_params) example_node = build_example(headers, data, mimetype) if example_node: example_section = nodes.section(ids=['example_' + mimetype]) examples_section += example_section example_section += nodes.title(text=mimetype) example_section += example_node has_examples = True if has_examples: main_section += examples_section return [targetnode, main_section]
def _generate_nodes(self, name, command, parent=None, show_nested=False): """Generate the relevant Sphinx nodes. Format a `click.Group` or `click.Command`. :param name: Name of command, as used on the command line :param command: Instance of `click.Group` or `click.Command` :param parent: Instance of `click.Context`, or None :param show_nested: Whether subcommands should be included in output :returns: A list of nested docutil nodes """ ctx = click.Context(command, info_name=name, parent=parent) # Title # We build this with plain old docutils nodes section = nodes.section( '', nodes.title(text=name), ids=[nodes.make_id(ctx.command_path)], names=[nodes.fully_normalize_name(ctx.command_path)]) source_name = ctx.command_path result = statemachine.ViewList() # Description # We parse this as reStructuredText, allowing users to embed rich # information in their help messages if they so choose. if ctx.command.help: for line in statemachine.string2lines(ctx.command.help, tab_width=4, convert_whitespace=True): result.append(line, source_name) result.append('', source_name) # Summary if isinstance(command, click.Command): summary = _format_command(ctx, show_nested) else: # TODO(stephenfin): Do we care to differentiate? Perhaps we # shouldn't show usage for groups? summary = _format_command(ctx, show_nested) for line in summary: result.append(line, source_name) self.state.nested_parse(result, 0, section) # Commands if show_nested: commands = getattr(ctx.command, 'commands', {}) for command_name, command_obj in sorted(commands.items()): section.extend( self._generate_nodes(command_name, command_obj, ctx, show_nested)) return [section]
def visit_admonition(self, node, name=''): # type: (nodes.Element, str) -> None self.body.append( self.starttag(node, 'div', CLASS=('admonition ' + name))) if name: node.insert(0, nodes.title(name, admonitionlabels[name]))
def visit_gitusernote_html(self, node): # it is a simple div with a dedicated CSS class assigned self.body.append( self.starttag(node, 'div', CLASS=('admonition ' + 'gitusernote'))) node.insert(0, nodes.title('first', 'Note for Git users'))
def _render_service(self, service): service_id = "service-%d" % self.env.new_serialno('service') service_node = nodes.section(ids=[service_id]) service_node += nodes.title(text='Service at %s' % service.path) if service.description is not None: service_node += rst2node(trim(service.description)) for method, view, args in service.definitions: method_id = '%s-%s' % (service_id, method) method_node = nodes.section(ids=[method_id]) method_node += nodes.title(text=method) if is_string(view): if 'klass' in args: ob = args['klass'] view_ = getattr(ob, view.lower()) docstring = trim(view_.__doc__ or "") + '\n' else: docstring = trim(view.__doc__ or "") + '\n' if 'schema' in args: schema = args['schema'] attrs_node = nodes.inline() for location in ('header', 'querystring', 'body'): attributes = schema.get_attributes(location=location) if attributes: attrs_node += nodes.inline(text='values in the %s' % location) location_attrs = nodes.bullet_list() for attr in attributes: temp = nodes.list_item() desc = "%s : " % attr.name # Get attribute data-type if hasattr(attr, 'type'): attr_type = attr.type elif hasattr(attr, 'typ'): attr_type = attr.typ.__class__.__name__ desc += " %s, " % attr_type if attr.required: desc += "required " else: desc += "optional " temp += nodes.inline(text=desc) location_attrs += temp attrs_node += location_attrs method_node += attrs_node for validator in args.get('validators', ()): if validator.__doc__ is not None: docstring += trim(validator.__doc__) if 'accept' in args: accept = to_list(args['accept']) if callable(accept): if accept.__doc__ is not None: docstring += accept.__doc__.strip() else: accept_node = nodes.strong(text='Accepted content types:') node_accept_list = nodes.bullet_list() accept_node += node_accept_list for item in accept: temp = nodes.list_item() temp += nodes.inline(text=item) node_accept_list += temp method_node += accept_node node = rst2node(docstring) DocFieldTransformer(self).transform_all(node) if node is not None: method_node += node renderer = args['renderer'] if renderer == 'simplejson': renderer = 'json' response = nodes.paragraph() response += nodes.strong(text='Response: %s' % renderer) method_node += response service_node += method_node return service_node
def _generate_nodes(self, name, command, parent=None, show_nested=False, commands=None): """Generate the relevant Sphinx nodes. Format a `click.Group` or `click.Command`. :param name: Name of command, as used on the command line :param command: Instance of `click.Group` or `click.Command` :param parent: Instance of `click.Context`, or None :param show_nested: Whether subcommands should be included in output :param commands: Display only listed commands or skip the section if empty :returns: A list of nested docutil nodes """ ctx = click.Context(command, info_name=name, parent=parent) if CLICK_VERSION >= (7, 0) and command.hidden: return [] # Title item = nodes.section( "", nodes.title(text=name), ids=[nodes.make_id(ctx.command_path)], names=[nodes.fully_normalize_name(ctx.command_path)], ) # Summary source_name = ctx.command_path result = statemachine.ViewList() lines = _format_command(ctx, show_nested, commands) for line in lines: LOG.debug(line) result.append(line, source_name) self.state.nested_parse(result, 0, item) # Subcommands if not show_nested: return [item] commands = _filter_commands(ctx, commands) commands = self._sort_commands(command, commands) for help_section, subcommands in self._group_commands( command, commands): group_name = help_section.name if group_name == doc.UNSECTIONED: for subcommand in subcommands: item.extend( self._generate_nodes(subcommand.name, subcommand, ctx, show_nested)) self.state.nested_parse(result, 0, item) continue group_item = nodes.section( "", nodes.title(text=group_name), ids=[nodes.make_id(group_name)], names=[nodes.fully_normalize_name(group_name)], ) group_list = statemachine.ViewList() # pylint: disable=fixme # XXX This is supposed to add documentation lines to each group, but it doesn't seem to work. for line in help_section.doc.splitlines(): group_list.append(line, group_name) for subcommand in subcommands: group_item.extend( self._generate_nodes(subcommand.name, subcommand, ctx, show_nested)) self.state.nested_parse(group_list, 0, group_item) item += group_item return [item]
def process_posts(app, doctree): """Process posts and map posted document names to post details in the environment.""" env = app.builder.env if app.config.skip_pickling: env.topickle = lambda *args: env.warn( 'index', 'Environment is not being pickled.') if not hasattr(env, 'ablog_posts'): env.ablog_posts = {} post_nodes = list(doctree.traverse(PostNode)) if not post_nodes: return pdf = app.config['post_date_format'] docname = env.docname # mark the post as 'orphan' so that # "document isn't included in any toctree" warning is not issued app.env.metadata[docname]['orphan'] = True blog = Blog(app) auto_excerpt = blog.post_auto_excerpt multi_post = len(post_nodes) > 1 or blog.post_always_section for order, node in enumerate(post_nodes, start=1): # print node['excerpt'] if node['excerpt'] is None: node['excerpt'] = auto_excerpt if multi_post: # section title, and first few paragraphs of the section of post # are used when there are more than 1 posts section = node while True: if isinstance(section, nodes.section): break section = node.parent else: section = doctree # get updates here, in the section that post belongs to # Might there be orphan updates? update_nodes = list(section.traverse(UpdateNode)) update_dates = [] for un in update_nodes: try: update = datetime.strptime(un['date'], pdf) except ValueError: raise ValueError('invalid post update date in: ' + docname) un[0].replace_self( nodes.title(u'', un[0][0].astext() + u' ' + update.strftime(pdf))) # for now, let updates look like note un['classes'] = ['note', 'update'] update_dates.append(update) # Making sure that post has a title because all post titles # are needed when resolving post lists in documents title = node['title'] if not title: for title in section.traverse(nodes.title): break # A problem with the following is that title may contain pending # references, e.g. :ref:`tag-tips` title = title.astext() # creating a summary here, before references are resolved excerpt = [] if node.children: if node['exclude']: node.replace_self([]) else: node.replace_self(node.children) for child in node.children: excerpt.append(child.deepcopy()) elif node['excerpt']: count = 0 for nod in section.traverse(nodes.paragraph): excerpt.append(nod.deepcopy()) count += 1 if count >= (node['excerpt'] or 0): break node.replace_self([]) else: node.replace_self([]) nimg = node['image'] or blog.post_auto_image if nimg: for img, nod in enumerate(section.traverse(nodes.image), start=1): if img == nimg: excerpt.append(nod.deepcopy()) break date = node['date'] if date: try: date = datetime.strptime(date, pdf) except ValueError: raise ValueError('invalid post published date in: ' + docname) else: date = None #update = node['update'] #if update: # try: # update = datetime.strptime(update, app.config['post_date_format']) # except ValueError: # raise ValueError('invalid post update date in: ' + docname) #else: # update = date # if docname ends with `index` use folder name to reference the document # a potential problem here is that there may be files/folders with the # same name, so issuing a warning when that's the case may be a good idea folder, label = os.path.split(docname) if label == 'index': folder, label = os.path.split(folder) if not label: label = slugify(title) post_name = docname section_name = '' if multi_post and section.parent is not doctree: section_name = section.attributes['ids'][0] post_name = docname + '#' + section_name label += '-' + section_name else: # create a reference for the post # if it is posting the document # ! this does not work for sections app.env.domains['std'].data['labels'][label] = (docname, label, title) if section.parent is doctree: section_copy = section[0].deepcopy() else: section_copy = section.deepcopy() # multiple posting may result having post nodes for nn in section_copy.traverse(PostNode): if nn['exclude']: nn.replace_self([]) else: nn.replace_self(node.children) postinfo = { 'docname': docname, 'section': section_name, 'order': order, 'date': date, 'update': max(update_dates + [date]), 'title': title, 'excerpt': excerpt, 'tags': node['tags'], 'author': node['author'], 'category': node['category'], 'location': node['location'], 'language': node['language'], 'redirect': node['redirect'], 'image': node['image'], 'exclude': node['exclude'], 'doctree': section_copy } if docname not in env.ablog_posts: env.ablog_posts[docname] = [] env.ablog_posts[docname].append(postinfo) # instantiate catalogs and collections here # so that references are created and no warnings are issued for key in ['tags', 'author', 'category', 'location', 'language']: catalog = blog.catalogs[key] for label in postinfo[key]: catalog[label] if postinfo['date']: blog.archive[postinfo['date'].year]
def translate(self): visitor = PDFTranslator(self.document, self.builder) self.document.walkabout(visitor) lang = self.config.language or 'en' langmod = get_language_available(lang)[2] self.docutils_languages = {lang: langmod} # Generate Contents topic manually if self.use_toc: contents = nodes.topic(classes=['contents']) contents += nodes.title('') contents[0] += nodes.Text(langmod.labels['contents']) contents['ids'] = ['Contents'] pending = nodes.topic() contents.append(pending) pending.details = {} self.document.insert( 0, nodes.raw(text='SetPageCounter 1 arabic', format='pdf')) self.document.insert( 0, nodes.raw(text='OddPageBreak %s' % self.page_template, format='pdf')) self.document.insert(0, contents) self.document.insert( 0, nodes.raw(text='SetPageCounter 1 lowerroman', format='pdf')) contTrans = PDFContents(self.document) contTrans.toc_depth = self.toc_depth contTrans.startnode = pending contTrans.apply() if self.use_coverpage: # Generate cover page # FIXME: duplicate from createpdf, refactor! # Add the Sphinx template paths def add_template_path(path): return os.path.join(self.srcdir, path) jinja_env = jinja2.Environment( loader=jinja2.FileSystemLoader([ self.srcdir, os.path.expanduser('~/.rst2pdf'), os.path.join(self.PATH, 'templates'), ] + list(map(add_template_path, self.config.templates_path))), autoescape=jinja2.select_autoescape(['html', 'xml']), ) try: template = jinja_env.get_template( self.config.pdf_cover_template) except jinja2.TemplateNotFound: log.error("Can't find cover template %s, using default" % self.config.pdf_cover_template) template = jinja_env.get_template('sphinxcover.tmpl') # This is what's used in the python docs because # Latex does a manual linebreak. This sucks. authors = self.document.settings.author.split('\\') # Honour the "today" config setting if self.config.today: date = self.config.today else: date = time.strftime(self.config.today_fmt or _('%B %d, %Y')) # Feed data to the template, get restructured text. cover_text = template.render( title=self.document.settings.title or visitor.elements['title'], subtitle='%s %s' % (_('version'), self.config.version), authors=authors, date=date, ) cover_tree = docutils.core.publish_doctree(cover_text) self.document.insert(0, cover_tree) sio = BytesIO() if self.invariant: createpdf.patch_PDFDate() createpdf.patch_digester() createpdf.RstToPdf( sphinx=True, stylesheets=self.stylesheets, language=self.__language, breaklevel=self.breaklevel, breakside=self.breakside, fit_mode=self.fitmode, font_path=self.fontpath, inline_footnotes=self.inline_footnotes, highlightlang=self.highlightlang, splittables=self.splittables, style_path=self.style_path, repeat_table_rows=self.repeat_table_rows, basedir=self.srcdir, def_dpi=self.default_dpi, real_footnotes=self.real_footnotes, numbered_links=self.use_numbered_links, background_fit_mode=self.fit_background_mode, baseurl=self.baseurl, section_header_depth=self.section_header_depth, ).createPdf(doctree=self.document, output=sio, compressed=self.compressed) self.output = sio.getvalue()
def run(self): """ Builds the mathdef 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 hasattr(env, "settings") and hasattr(env.settings, "mathdef_link_number"): number_format = env.settings.mathdef_link_number elif hasattr(self.state.document.settings, "mathdef_link_number"): number_format = self.state.document.settings.mathdef_link_number elif hasattr(env, "config") and hasattr(env.config, "mathdef_link_number"): number_format = env.config.mathdef_link_number else: raise ValueError( "mathdef_link_number is not defined in the configuration") if not self.options.get('class'): self.options['class'] = ['admonition-mathdef'] # body (mathdef, ) = super(MathDef, self).run() if isinstance(mathdef, nodes.system_message): return [mathdef] # add a label lid = self.options.get('lid', self.options.get('label', None)) if lid: container = nodes.container() tnl = [".. _{0}:".format(lid), ""] content = StringList(tnl) self.state.nested_parse(content, self.content_offset, container) else: container = None # mid mathtag = self.options.get('tag', '').strip() if len(mathtag) == 0: raise ValueError("tag is empty") if env is not None: mid = int(env.new_serialno('indexmathe-u-%s' % mathtag)) + 1 else: mid = -1 # id of the section first_letter = mathtag[0].upper() number = mid try: label_number = number_format.format(number=number, first_letter=first_letter) except ValueError as e: raise Exception("Unable to interpret format '{0}'.".format( number_format)) from e # title title = self.options.get('title', "").strip() if len(title) > 0: title = "{0} {1} : {2}".format(mathtag, label_number, title) else: raise ValueError("title is empty") # main node ttitle = title title = nodes.title(text=_(title)) if container is not None: mathdef.insert(0, title) mathdef.insert(0, container) else: mathdef.insert(0, title) mathdef['mathtag'] = mathtag mathdef['mathmid'] = mid mathdef['mathtitle'] = ttitle set_source_info(self, mathdef) if env is not None: targetid = 'indexmathe-%s%s' % ( mathtag, env.new_serialno('indexmathe%s' % mathtag)) ids = [targetid] targetnode = nodes.target(legend, '', ids=ids[0]) set_source_info(self, targetnode) try: self.state.add_target(targetid, '', targetnode, lineno) except Exception as e: raise Exception( "Issue in\n File '{0}', line {1}\ntid={2}\ntnode={3}". format(None if env is None else env.docname, lineno, targetid, targetnode)) from e # index node index = self.options.get('index', None) imposed = ",".join(a for a in [mathtag, ttitle] if a) if index is None or len(index.strip()) == 0: index = imposed else: index += "," + imposed 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, mathdef] if a is not None]
def _create_section_with_title(section_id, title): node = nodes.section(ids=[_escape_id(section_id)]) jobs_title = nodes.title(text=title) node.append(jobs_title) return node
def run(self): node = mongodoc() title = 'See general MongoDB documentation' node += nodes.title(title, title) self.state.nested_parse(self.content, self.content_offset, node) return [node]
class ResourceDirective(Directive): has_content = True required_arguments = 0 option_spec = { 'classname': directives.unchanged_required, 'is-list': directives.flag, 'hide-links': directives.flag, 'hide-examples': directives.flag, } item_http_methods = set(['GET', 'DELETE', 'PUT']) list_http_methods = set(['GET', 'POST']) type_mapping = { int: 'Integer', str: 'String', bool: 'Boolean', dict: 'Dictionary', file: 'Uploaded File', } def run(self): try: resource_class = self.get_resource_class(self.options['classname']) except ResourceNotFound, e: return e.error_node # Add the class's file and this extension to the dependencies. self.state.document.settings.env.note_dependency(__file__) self.state.document.settings.env.note_dependency( sys.modules[resource_class.__module__].__file__) resource = get_resource_from_class(resource_class) is_list = 'is-list' in self.options docname = 'webapi2.0-%s-resource' % \ get_resource_docname(resource, is_list) resource_title = get_resource_title(resource, is_list) targetnode = nodes.target('', '', ids=[docname], names=[docname]) self.state.document.note_explicit_target(targetnode) main_section = nodes.section(ids=[docname]) # Details section main_section += nodes.title(text=resource_title) main_section += self.build_details_table(resource) # Fields section if (resource.fields and (not is_list or resource.singleton)): fields_section = nodes.section(ids=['fields']) main_section += fields_section fields_section += nodes.title(text='Fields') fields_section += self.build_fields_table(resource.fields) # Links section if 'hide-links' not in self.options: fields_section = nodes.section(ids=['links']) main_section += fields_section fields_section += nodes.title(text='Links') fields_section += self.build_links_table(resource) # HTTP method descriptions for http_method in self.get_http_methods(resource, is_list): method_section = nodes.section(ids=[http_method]) main_section += method_section method_section += nodes.title(text='HTTP %s' % http_method) method_section += self.build_http_method_section( resource, http_method) if 'hide-examples' not in self.options: examples_section = nodes.section(ids=['examples']) examples_section += nodes.title(text='Examples') has_examples = False if is_list: allowed_mimetypes = resource.allowed_list_mimetypes else: allowed_mimetypes = resource.allowed_item_mimetypes for mimetype in allowed_mimetypes: example_node = build_example( self.fetch_resource_data(resource, mimetype), mimetype) if example_node: example_section = nodes.section( ids=['example_' + mimetype]) examples_section += example_section example_section += nodes.title(text=mimetype) example_section += example_node has_examples = True if has_examples: main_section += examples_section return [targetnode, main_section]
def assemble_doctree(self, indexfile, toctree_only, appendices): self.docnames = set([indexfile] + appendices) self.info(darkgreen(indexfile) + " ", 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( 'toctree contains ref to nonexisting ' 'file %r' % includefile, self.env.doc2path(docname)) 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(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 = process_tree(indexfile, tree) 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...") 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) return largetree
def run(self): filename = self.arguments[0] cwd = os.getcwd() os.chdir(TMPDIR) parts = [] try: ff = AsdfFile() code = AsdfFile._open_impl(ff, filename, _get_yaml_content=True) code = '{0} {1}\n'.format(ASDF_MAGIC, version_string) + code.strip().decode('utf-8') literal = nodes.literal_block(code, code) literal['language'] = 'yaml' set_source_info(self, literal) parts.append(literal) with AsdfFile.open(filename) as ff: for i, block in enumerate(ff.blocks.internal_blocks): data = codecs.encode(block.data.tostring(), 'hex') if len(data) > 40: data = data[:40] + '...'.encode() allocated = block._allocated size = block._size data_size = block._data_size flags = block._flags if flags & BLOCK_FLAG_STREAMED: allocated = size = data_size = 0 lines = [] lines.append('BLOCK {0}:'.format(i)) human_flags = [] for key, val in FLAGS.items(): if flags & key: human_flags.append(val) if len(human_flags): lines.append(' flags: {0}'.format(' | '.join(human_flags))) if block.compression: lines.append(' compression: {0}'.format(block.compression)) lines.append(' allocated_size: {0}'.format(allocated)) lines.append(' used_size: {0}'.format(size)) lines.append(' data_size: {0}'.format(data_size)) lines.append(' data: {0}'.format(data)) code = '\n'.join(lines) literal = nodes.literal_block(code, code) literal['language'] = 'yaml' set_source_info(self, literal) parts.append(literal) internal_blocks = list(ff.blocks.internal_blocks) if (len(internal_blocks) and internal_blocks[-1].array_storage != 'streamed'): buff = io.BytesIO() ff.blocks.write_block_index(buff, ff) block_index = buff.getvalue() literal = nodes.literal_block(block_index, block_index) literal['language'] = 'yaml' set_source_info(self, literal) parts.append(literal) finally: os.chdir(cwd) result = nodes.admonition() textnodes, messages = self.state.inline_text(filename, self.lineno) title = nodes.title(filename, '', *textnodes) result += title result += parts return [result]
def _generate_nodes(self, name, command, parent, nested, commands=None, semantic_group=False): """Generate the relevant Sphinx nodes. Format a `click.Group` or `click.Command`. :param name: Name of command, as used on the command line :param command: Instance of `click.Group` or `click.Command` :param parent: Instance of `click.Context`, or None :param nested: The granularity of subcommand details. :param commands: Display only listed commands or skip the section if empty :param semantic_group: Display command as title and description for CommandCollection. :returns: A list of nested docutil nodes """ ctx = click.Context(command, info_name=name, parent=parent) if CLICK_VERSION >= (7, 0) and command.hidden: return [] # Title section = nodes.section( '', nodes.title(text=name), ids=[nodes.make_id(ctx.command_path)], names=[nodes.fully_normalize_name(ctx.command_path)], ) # Summary source_name = ctx.command_path result = statemachine.ViewList() if semantic_group: lines = _format_description(ctx) else: lines = _format_command(ctx, nested, commands) for line in lines: LOG.debug(line) result.append(line, source_name) sphinx_nodes.nested_parse_with_titles(self.state, result, section) # Subcommands if nested == NESTED_FULL: if isinstance(command, click.CommandCollection): for source in command.sources: section.extend( self._generate_nodes(source.name, source, ctx, nested, semantic_group=True)) else: commands = _filter_commands(ctx, commands) for command in commands: parent = ctx if not semantic_group else ctx.parent section.extend( self._generate_nodes(command.name, command, parent, nested)) return [section]
def run(self): secid = [self.arguments[0].lower().replace(' ', '-')] section = nodes.section(ids=secid) section.document = self.state.document section += nodes.title(text=self.arguments[0]) # parse the 'text' option into the section, as a paragraph. self.state.nested_parse(StringList([self.options['text']], parent=self), 0, section) node = self.create_progtable() section.children[-1] += node head = node.children[0].children[-2].children[0] body = node.children[0].children[-1] comps = collections.OrderedDict() cur = "" for line in self.content: # new list nl = re.match(r'^:(?P<component>.+):$', line) if nl is not None: if cur != "": # finish up shrow self.add_progbar(shrow, len([c for c in comps[cur] if c is True]), len(comps[cur])) cur = nl.groupdict()['component'] if cur not in comps: comps[cur] = [] # shrow is the section header row shrow = self.create_headrow(cur, classes=['field-name']) body += shrow continue nl = re.match(r'^\s+- (?P<item>[^,]+),\s+(?P<value>(True|False))(, (?P<description>.+)$)?', line) if nl is not None: nl = nl.groupdict() comps[cur].append(True if nl['value'] == "True" else False) tr = nodes.row() tr += nodes.description('', nodes.inline(text="\u2713" if comps[cur][-1] else " "), classes=['field-name', 'progress-checkbox']) tr += nodes.description('', nodes.strong(text='{:s} '.format(nl['item'])), nodes.inline(text='{:s}'.format(nl['description'] if nl['description'] is not None else ' ')), classes=['field-value']) body += tr if self.content: # finish up the final hrow self.add_progbar(shrow, len([c for c in comps[cur] if c == True]), len(comps[cur])) # and fill in the end of mrow self.add_progbar(head, len([c for r in comps.values() for c in r if c == True]), len([c for r in comps.values() for c in r])) return [section]
def _construct_manpage_specific_structure(self, parser_info): """ Construct a typical man page consisting of the following elements: NAME (automatically generated, out of our control) SYNOPSIS DESCRIPTION OPTIONS FILES SEE ALSO BUGS """ # SYNOPSIS section synopsis_section = nodes.section( '', nodes.title(text='Synopsis'), nodes.literal_block(text=parser_info["bare_usage"]), ids=['synopsis-section']) # DESCRIPTION section description_section = nodes.section( '', nodes.title(text='Description'), nodes.paragraph(text=parser_info.get( 'description', parser_info.get('help', "undocumented").capitalize())), ids=['description-section']) nested_parse_with_titles(self.state, self.content, description_section) if parser_info.get('epilog'): # TODO: do whatever sphinx does to understand ReST inside # docstrings magically imported from other places. The nested # parse method invoked above seem to be able to do this but # I haven't found a way to do it for arbitrary text description_section += nodes.paragraph(text=parser_info['epilog']) # OPTIONS section options_section = nodes.section('', nodes.title(text='Options'), ids=['options-section']) if 'args' in parser_info: options_section += nodes.paragraph() options_section += nodes.subtitle(text='Positional arguments:') options_section += self._format_positional_arguments(parser_info) if 'options' in parser_info: options_section += nodes.paragraph() options_section += nodes.subtitle(text='Optional arguments:') options_section += self._format_optional_arguments(parser_info) items = [ # NOTE: we cannot generate NAME ourselves. It is generated by # docutils.writers.manpage synopsis_section, description_section, # TODO: files # TODO: see also # TODO: bugs ] if len(options_section.children) > 1: items.append(options_section) if 'nosubcommands' not in self.options: # SUBCOMMANDS section (non-standard) subcommands_section = nodes.section( '', nodes.title(text='Sub-Commands'), ids=['subcommands-section']) if 'children' in parser_info: subcommands_section += self._format_subcommands(parser_info) if len(subcommands_section) > 1: items.append(subcommands_section) if os.getenv("INCLUDE_DEBUG_SECTION"): import json # DEBUG section (non-standard) debug_section = nodes.section( '', nodes.title(text="Argparse + Sphinx Debugging"), nodes.literal_block(text=json.dumps(parser_info, indent=' ')), ids=['debug-section']) items.append(debug_section) return items
def create_title_node(self, traceable): title_content = self.create_title_content(traceable) title_node = nodes.title(traceable.tag, "", title_content) return [title_node]
def create_section(self, title): section = nodes.section(ids=[title]) section += nodes.title(title, title) return section
def _build_grade_table(self, matrix, content): summarytitle = nodes.title(text="Backends - Summary") summary = nodes.table() cols = len(list(six.iterkeys(matrix.backends))) cols += 2 summarygroup = nodes.tgroup(cols=cols) summarybody = nodes.tbody() summaryhead = nodes.thead() for i in range(cols): summarygroup.append(nodes.colspec(colwidth=1)) summarygroup.append(summaryhead) summarygroup.append(summarybody) summary.append(summarygroup) content.append(summarytitle) content.append(summary) header = nodes.row() blank = nodes.entry() blank.append(nodes.strong(text="Backend")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Status")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Type")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="In Tree")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Notes")) header.append(blank) summaryhead.append(header) grades = matrix.grades impls = list(six.iterkeys(matrix.backends)) impls.sort() for grade in grades: for backend in impls: if matrix.backends[backend].status == grade.key: item = nodes.row() namecol = nodes.entry() namecol.append( nodes.paragraph(text=matrix.backends[backend].title)) item.append(namecol) statuscol = nodes.entry() statuscol.append(nodes.paragraph(text=grade.title)) item.append(statuscol) typecol = nodes.entry() typecol.append( nodes.paragraph(text=matrix.backends[backend].type)) item.append(typecol) if bool(matrix.backends[backend].in_tree): status = u"\u2714" else: status = u"\u2716" intreecol = nodes.entry() intreecol.append(nodes.paragraph(text=status)) item.append(intreecol) notescol = nodes.entry() notescol.append( nodes.paragraph(text=matrix.backends[backend].notes)) item.append(notescol) summarybody.append(item) return content
def run(self): self.env = self.state.document.settings.env self.app = self.env.app # Make sure we have some content, which should be yaml that # defines some parameters. if not self.content: error = self.state_machine.reporter.error( 'No parameters defined', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] if not len(self.arguments) >= 2: error = self.state_machine.reporter.error( '%s' % self.arguments, nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] _, status_defs_file = self.env.relfn2path(self.arguments.pop()) status_type = self.arguments.pop() self.status_defs = self._load_status_file(status_defs_file) # self.app.info("%s" % str(self.status_defs)) if status_type not in self.status_types: error = self.state_machine.reporter.error( 'Type %s is not one of %s' % (status_type, self.status_types), nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [error] self.yaml = self._load_codes() self.max_cols = len(self.headers) # TODO(sdague): it would be good to dynamically set column # widths (or basically make the colwidth thing go away # entirely) self.options['widths'] = [30, 70] self.col_widths = self.get_column_widths(self.max_cols) if isinstance(self.col_widths, tuple): # In docutils 0.13.1, get_column_widths returns a (widths, # colwidths) tuple, where widths is a string (i.e. 'auto'). # See https://sourceforge.net/p/docutils/patches/120/. self.col_widths = self.col_widths[1] # Actually convert the yaml title, messages = self.make_title() # self.app.info("Title %s, messages %s" % (title, messages)) table_node = self.build_table() self.add_name(table_node) title_block = nodes.title( text=status_type.capitalize()) section = nodes.section(ids=title_block) section += title_block section += table_node return [section] + messages
class ResourceDirective(Directive): has_content = True required_arguments = 0 option_spec = { 'classname': directives.unchanged_required, 'is-list': directives.flag, 'hide-links': directives.flag, 'hide-examples': directives.flag, } item_http_methods = set(['GET', 'DELETE', 'PUT']) list_http_methods = set(['GET', 'POST']) FILTERED_MIMETYPES = [ 'application/json', 'application/xml', ] def run(self): try: resource_class = self.get_resource_class(self.options['classname']) except ResourceNotFound, e: return e.error_node # Add the class's file and this extension to the dependencies. env = self.state.document.settings.env env.note_dependency(__file__) env.note_dependency(sys.modules[resource_class.__module__].__file__) resource = get_resource_from_class(resource_class) is_list = 'is-list' in self.options docname = 'webapi2.0-%s-resource' % \ get_resource_docname(env.app, resource, is_list) resource_title = get_resource_title(resource, is_list) targetnode = nodes.target('', '', ids=[docname], names=[docname]) self.state.document.note_explicit_target(targetnode) main_section = nodes.section(ids=[docname]) # Main section main_section += nodes.title(text=resource_title) for attr_name, text_fmt in (('added_in', 'Added in %s'), ('deprecated_in', 'Deprecated in %s'), ('removed_in', 'Removed in %s')): version = getattr(resource, attr_name, None) if not version: if is_list: prefix = 'list_resource' else: prefix = 'item_resource' version = getattr(resource, '%s_%s' % (prefix, attr_name), None) if version: paragraph = nodes.paragraph() paragraph += nodes.emphasis(text=text_fmt % version, classes=['resource-versioning']) main_section += paragraph main_section += parse_text( self, inspect.getdoc(resource), where='%s class docstring' % self.options['classname']) if getattr(resource, 'required_features', False): required_features = nodes.important() required_features += nodes.inline( text='Using this resource requires extra features to be ' 'enabled on the server. See "Required Features" below.') main_section += required_features # Details section details_section = nodes.section(ids=['details']) main_section += details_section details_section += nodes.title(text='Details') details_section += self.build_details_table(resource) # Fields section if (resource.fields and (not is_list or resource.singleton)): fields_section = nodes.section(ids=['fields']) main_section += fields_section fields_section += nodes.title(text='Fields') fields_section += self.build_fields_table(resource.fields) # Links section if 'hide-links' not in self.options: fields_section = nodes.section(ids=['links']) main_section += fields_section fields_section += nodes.title(text='Links') fields_section += self.build_links_table(resource) # HTTP method descriptions for http_method in self.get_http_methods(resource, is_list): method_section = nodes.section(ids=[http_method]) main_section += method_section method_section += nodes.title(text='HTTP %s' % http_method) method_section += self.build_http_method_section(resource, http_method) if 'hide-examples' not in self.options: examples_section = nodes.section(ids=['examples']) examples_section += nodes.title(text='Examples') has_examples = False if is_list: mimetype_key = 'list' else: mimetype_key = 'item' for mimetype in resource.allowed_mimetypes: try: mimetype = mimetype[mimetype_key] except KeyError: continue if mimetype in self.FILTERED_MIMETYPES: # Resources have more specific mimetypes. We want to # filter out the general ones (like application/json) # so we don't show redundant examples. continue if mimetype.endswith('xml'): # JSON is preferred. While we support XML, let's not # continue to advertise it. continue url, headers, data = \ self.fetch_resource_data(resource, mimetype) example_node = build_example(headers, data, mimetype) if example_node: example_section = \ nodes.section(ids=['example_' + mimetype], classes=['examples', 'requests-example']) examples_section += example_section example_section += nodes.title(text=mimetype) accept_mimetype = mimetype if (mimetype.startswith('application/') and mimetype.endswith('+json')): # Instead of telling the user to ask for a specific # mimetype on the request, show them that asking for # application/json works fine. accept_mimetype = 'application/json' curl_text = ( '$ curl http://reviews.example.com%s -H "Accept: %s"' % (url, accept_mimetype) ) example_section += nodes.literal_block( curl_text, curl_text, classes=['cmdline']) example_section += nodes.literal_block( headers, headers, classes=['http-headers']) example_section += example_node has_examples = True if has_examples: main_section += examples_section return [targetnode, main_section]
settings = frontend.OptionParser().get_default_values() settings.xml_declaration = False settings.embed_stylesheet = False settings.stylesheet_path = False settings.stylesheet = None settings.initial_header_level = "1" reporter = Reporter(source, settings.report_level, settings.halt_level, stream=settings.warning_stream, debug=settings.debug, encoding=settings.error_encoding, error_handler=settings.error_encoding_error_handler) document = nodes.document(settings, reporter) title = nodes.title(text="This is the title") subtitle = nodes.subtitle(text=".. with a subtitle") introduction = nodes.section() start = nodes.paragraph(text="The introduction starts with this.") introduction += start background = nodes.section() background += nodes.paragraph( text="This paragraph starts the second section, background.") document += [title, subtitle, introduction, background] #print str(document) out = docutils.io.FileOutput()