def run_directive(self, name, arguments=[], options={}, content=[]): """Generate directive node given arguments. Parameters ---------- name : str name of directive. arguments : list list of positional arguments. options : dict key value arguments. content : content content of the directive Returns ------- node : docutil Node Node generated by the arguments. """ direc, msg = directive(name, self.language, self.document) direc = direc(name=name, arguments=arguments, options=options, content=content, lineno=self.node.line, content_offset=0, block_text='Dummy BlockText', state=self.state, state_machine=self) return direc.run()
def test_directives(self): try: module = docutils.parsers.rst.languages.get_language( self.language) if not module: raise ImportError except ImportError: self.fail('No docutils.parsers.rst.languages.%s module.' % self.language) failures = [] for d in list(module.directives.keys()): try: func, msg = directives.directive(d, module, None) if not func: failures.append('"%s": unknown directive' % d) except Exception as error: failures.append('"%s": %s' % (d, error)) inverted = self._invert(module.directives) canonical = list(directives._directive_registry.keys()) canonical.sort() canonical.remove('restructuredtext-test-directive') for name in canonical: if name not in inverted: failures.append('"%s": translation missing' % name) if failures: text = ('Module docutils.parsers.rst.languages.%s:\n %s' % (self.language, '\n '.join(failures))) if type(text) is str: text = text.encode('raw_unicode_escape') self.fail(text)
def test_directives(self): try: module = docutils.parsers.rst.languages.get_language(self.language) if not module: raise ImportError except ImportError: self.fail('No docutils.parsers.rst.languages.%s module.' % self.language) failures = [] for d in module.directives.keys(): try: func, msg = directives.directive(d, module, None) if not func: failures.append('"%s": unknown directive' % d) except Exception as error: failures.append('"%s": %s' % (d, error)) inverted = self._invert(module.directives) canonical = sorted(directives._directive_registry.keys()) canonical.remove('restructuredtext-test-directive') for name in canonical: if name not in inverted: failures.append('"%s": translation missing' % name) if failures: text = ('Module docutils.parsers.rst.languages.%s:\n %s' % (self.language, '\n '.join(failures))) if isinstance(text, unicode): text = text.encode('raw_unicode_escape') self.fail(text)
def get_directive(name): from docutils.parsers.rst import directives try: return directives.directive(name, None, None)[0] except AttributeError: pass try: # docutils 0.4 return directives._directives[name] except (AttributeError, KeyError): raise RuntimeError("No directive named '%s' found" % name)
def catchall_directive(self, match, **option_presets): """Directive dispatch method. Replacement for Body.directive(): if a directive is not known, build one on the fly instead of reporting an error. """ type_name = match.group(1) directive_class, messages = directives.directive( type_name, self.memo.language, self.document) # in case it's missing, register a generic directive if not directive_class: directives.register_directive(type_name, AnyDirective) directive_class, messages = directives.directive( type_name, self.memo.language, self.document) assert directive_class, "can't find just defined directive" self.parent += messages return self.run_directive( directive_class, match, type_name, option_presets)
def catchall_directive(self, match, **option_presets): """Directive dispatch method. Replacement for Body.directive(): if a directive is not known, build one on the fly instead of reporting an error. """ type_name = match.group(1) directive_class, messages = directives.directive(type_name, self.memo.language, self.document) # in case it's missing, register a generic directive if not directive_class: directives.register_directive(type_name, AnyDirective) directive_class, messages = directives.directive( type_name, self.memo.language, self.document) assert directive_class, "can't find just defined directive" self.parent += messages return self.run_directive(directive_class, match, type_name, option_presets)
def run_directive(parent_directive, name, content='', options={}): """Run and render a directive. Args: parent_directive (docutils.parsers.rst.Directive): The directive running another directive. name (unicode): The name of the directive to run. content (unicode, optional): The content to pass to the directive. options (dict, optional): The options to pass to the directive. Returns: list of docutils.nodes.Node: The resulting list of nodes from the directive. """ state = parent_directive.state directive_class, messages = directives.directive(name, state.memo.language, state.document) state.parent += messages if not directive_class: return state.unknown_directive(name) state_machine = state.state_machine lineno = state_machine.abs_line_number() directive = directive_class( name=name, arguments=[], options=options, content=content, lineno=lineno, content_offset=0, block_text='', state=parent_directive.state, state_machine=state_machine) try: return directive.run() except DirectiveError as e: return [ parent_directive.reporter.system_message(e.level, e.msg, line=lineno), ]
def test_directives(self): try: module = docutils.parsers.rst.languages.get_language(self.language) if not module: raise ImportError except ImportError: self.fail('No docutils.parsers.rst.languages.%s module.' % self.language) failures = [] for d in module.directives.keys(): try: func, msg = directives.directive(d, module, None) if not func: failures.append('"%s": unknown directive' % d) except Exception, error: failures.append('"%s": %s' % (d, error))
def test_directives(self): try: module = docutils.parsers.rst.languages.get_language( self.language) if not module: raise ImportError except ImportError: self.fail('No docutils.parsers.rst.languages.%s module.' % self.language) failures = [] for d in module.directives.keys(): try: func, msg = directives.directive(d, module, None) if not func: failures.append('"%s": unknown directive' % d) except Exception, error: failures.append('"%s": %s' % (d, error))
def run_directive(self, lineno, state, state_machine): """Execute the directive generate a list of nodes.""" name = self["{antidox}name"] directive_class, messages = directives.directive( name, state.memo.language, state.document) raw_options = self.attlist() options = { k: directive_class.option_spec[k](v) for k, v in raw_options if not k.startswith("{antidox}") } arguments = [ n.astext() for n in self.children if n.tagname == "antidox_directive-argument" ] content = [ n.astext() for n in self.children if n.tagname == "antidox_directive-content" ] # what about this? # content_offset = 0 # block_text = '' directive_instance = directive_class(name, arguments, options, content, lineno, 0, "", state, state_machine) try: result = directive_instance.run() result += messages except DirectiveError as error: msg_node = state.reporter.system_message(error.level, error.msg, line=lineno) result = [msg_node] return result
def run_directive(self, name, arguments=None, options=None, content=None): """Generate directive node given arguments. Parameters ---------- name : str name of directive. arguments : list list of positional arguments. options : dict key value arguments. content : content content of the directive Returns ------- node : docutil Node Node generated by the arguments. """ if options is None: options = {} if content is None: content = [] if arguments is None: arguments = [] direc, msg = directive(name, self.language, self.document) direc = direc(name=name, arguments=arguments, options=options, content=content, lineno=self.node.line, content_offset=0, block_text='Dummy BlockText', state=self.state, state_machine=self) return direc.run()
def run(self): """Run the directive.""" name = self.arguments[0] # load the directive class klass, _ = directives.directive(name, self.state.memo.language, self.state.document) if klass is None: logger.warning(f"Directive {name} not found.", line=self.lineno) return [] content = " ".join(self.content) text = f"""\ :Name: `{name}` :Description: {content} :Arguments: {klass.required_arguments} required, {klass.optional_arguments} optional :Content: {'yes' if klass.has_content else 'no'} :Options: """ if klass.option_spec: text += " name | type\n -----|------\n" for key, func in klass.option_spec.items(): text += f" {key} | {convert_opt(name, func)}\n" node = nodes.Element() self.state.nested_parse(text.splitlines(), 0, node) return node.children
def run(self): language = self.state_machine.language document = self.state.document directive, messages = directives.directive("plot", language, document) self.state.parent += messages # Temporarily override template # * Add target to figure # * Add classes for Bootstrap target = ":target: " + self.options.pop("target", "") title = self.options["alt"] classes = " ".join(document.settings.env.config.gallery_plot_classes + ["thumbnail"]) template = ( """ {{ only_html }} {% for img in images %} .. figure:: {{ build_dir }}/{{ img.basename }}.png """ + target + """ :figclass: """ + classes + """ {% for option in options -%} {{ option }} {% endfor %} {% endfor %} {{ only_latex }} {% for img in images %} {% if 'pdf' in img.formats -%} .. image:: {{ build_dir }}/{{ img.basename }}.pdf """ + target + """ {% endif -%} {% endfor %} {{ only_texinfo }} {% for img in images %} .. image:: {{ build_dir }}/{{ img.basename }}.png """ + target + """ {% for option in options -%} {{ option }} {% endfor %} {% endfor %} """ ) plot_template_orig = document.settings.env.config.plot_template document.settings.env.config.plot_template = template # Don't bother with the high resolution version plot_formats_orig = document.settings.env.config.plot_formats plot_formats = [] for f in plot_formats_orig: if isinstance(f, str) and "hires" in f: continue elif isinstance(f, tuple) and "hires" in f[0]: continue plot_formats.append(f) document.settings.env.config.plot_formats = plot_formats options = {"alt": title} directive_instance = directive( "plot", self.arguments, options, self.content, self.lineno, self.content_offset, self.block_text, self.state, self.state_machine, ) try: result = directive_instance.run() except DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=self.lineno) msg_node += nodes.literal_block(self.block_text, self.block_text) result = [msg_node] # Restore original settings document.settings.env.config.plot_template = plot_template_orig document.settings.env.config.plot_formats = plot_formats_orig return result
def render_directive(self, token: Token): """Render special fenced code blocks as directives.""" first_line = token.info.split(maxsplit=1) name = first_line[0][1:-1] arguments = "" if len(first_line) == 1 else first_line[1] # TODO directive name white/black lists content = token.content position = token.map[0] self.document.current_line = position # get directive class directive_class, messages = directives.directive( name, self.language_module, self.document) # type: (Directive, list) if not directive_class: error = self.reporter.error( 'Unknown directive type "{}".\n'.format(name), # nodes.literal_block(content, content), line=position, ) self.current_node += [error] + messages return try: arguments, options, body_lines = parse_directive_text( directive_class, arguments, content) except DirectiveParsingError as error: error = self.reporter.error( "Directive '{}': {}".format(name, error), nodes.literal_block(content, content), line=position, ) self.current_node += [error] return # initialise directive if issubclass(directive_class, Include): directive_instance = MockIncludeDirective( self, name=name, klass=directive_class, arguments=arguments, options=options, body=body_lines, token=token, ) else: state_machine = MockStateMachine(self, position) state = MockState(self, state_machine, position) directive_instance = directive_class( name=name, # the list of positional arguments arguments=arguments, # a dictionary mapping option names to values options=options, # the directive content line by line content=StringList(body_lines, self.document["source"]), # the absolute line number of the first line of the directive lineno=position, # the line offset of the first line of the content content_offset= 0, # TODO get content offset from `parse_directive_text` # a string containing the entire directive block_text="\n".join(body_lines), state=state, state_machine=state_machine, ) # run directive try: result = directive_instance.run() except DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=position) msg_node += nodes.literal_block(content, content) result = [msg_node] except MockingError as exc: error = self.reporter.error( "Directive '{}' cannot be mocked: {}: {}".format( name, exc.__class__.__name__, exc), nodes.literal_block(content, content), line=position, ) self.current_node += [error] return assert isinstance( result, list), 'Directive "{}" must return a list of nodes.'.format(name) for i in range(len(result)): assert isinstance( result[i], nodes.Node ), 'Directive "{}" returned non-Node object (index {}): {}'.format( name, i, result[i]) self.current_node += result
def run(self): language = self.state_machine.language document = self.state.document directive,messages = directives.directive('plot', language, document) self.state.parent += messages # Temporarily override template # * Add target to figure # * Add classes for Bootstrap target = ':target: ' + self.options.pop('target', '') title = self.options['alt'] classes = ' '.join(document.settings.env.config.gallery_plot_classes + ['thumbnail']) template = ''' {{ only_html }} {% for img in images %} .. figure:: {{ build_dir }}/{{ img.basename }}.png ''' + target + ''' :figclass: ''' + classes + ''' {% for option in options -%} {{ option }} {% endfor %} {% endfor %} {{ only_latex }} {% for img in images %} .. image:: {{ build_dir }}/{{ img.basename }}.pdf ''' + target + ''' {% endfor %} {{ only_texinfo }} {% for img in images %} .. image:: {{ build_dir }}/{{ img.basename }}.png ''' + target + ''' {% for option in options -%} {{ option }} {% endfor %} {% endfor %} ''' plot_template_orig = document.settings.env.config.plot_template document.settings.env.config.plot_template = template # Don't bother with the high resolution version plot_formats_orig = document.settings.env.config.plot_formats plot_formats = [] for f in plot_formats_orig: if isinstance(f, str) and 'hires' in f: continue elif isinstance(f, tuple) and 'hires' in f[0]: continue plot_formats.append(f) document.settings.env.config.plot_formats = plot_formats options = { 'alt': title, } directive_instance = directive('plot', self.arguments, options, self.content, self.lineno, self.content_offset, self.block_text, self.state, self.state_machine) try: result = directive_instance.run() except DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=lineno) msg_node += nodes.literal_block(block_text, block_text) result = [msg_node] # Restore original settings document.settings.env.config.plot_template = plot_template_orig document.settings.env.config.plot_formats = plot_formats_orig return result
def run_fence_as_directive(self, match, **option_presets): # NOTE(josh): copied from directive() type_name = "code" directive_class, messages = directives.directive(type_name, self.memo.language, self.document) self.parent += messages if not directive_class: return self.unknown_directive(type_name) # NOTE(josh): copied from run_directive(): lineno = self.state_machine.abs_line_number() initial_line_offset = self.state_machine.line_offset # NOTE(josh): changed this from get_first_known_indented to # get_first_known_indented_until, which I wrote (well, sorta... I mean # I mostly copied the original function). indented, indent, line_offset, blank_finish \ = self.state_machine.get_first_known_indented_until( match.start(), match.group(0)) padded = StringList() # padded += indented[0:1] # First line contains any optional arguments (in this case, language) padded += StringList([indented[0][3:]]) # TODO(josh): check to see if there are any options specified, such # as :number-lines:, :class:, :name:. # Second line must be blank padded += StringList([""]) padded += indented[1:-1] padded += StringList([""]) # padded += indented[-1:] blank_finish = True # NOTE(josh): +1 to start, -1 to stop index, as compared to the usual # directive parsing. Also added a newline to the start block_text = '\n'.join( self.state_machine.input_lines[initial_line_offset + 1:self.state_machine.line_offset]) try: arguments, options, content, content_offset = ( self.parse_directive_block(padded, line_offset, directive_class, option_presets)) except MarkupError as detail: error = self.reporter.error('Error in "%s" directive:\n%s.' % (type_name, ' '.join(detail.args)), nodes.literal_block( block_text, block_text), line=lineno) return [error], blank_finish directive_instance = directive_class(type_name, arguments, options, content, lineno, content_offset, block_text, self, self.state_machine) try: result = directive_instance.run() except docutils.parsers.rst.DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=lineno) msg_node += nodes.literal_block(block_text, block_text) result = [msg_node] assert isinstance(result, list), \ 'Directive "%s" must return a list of nodes.' % type_name for i in range(len(result)): assert isinstance(result[i], nodes.Node), \ ('Directive "%s" returned non-Node object (index %s): %r' % (type_name, i, result[i])) return (result, blank_finish or self.state_machine.is_next_line_blank())
def run(self): language = self.state_machine.language document = self.state.document directive, messages = directives.directive('plot', language, document) self.state.parent += messages # Temporarily override template # * Add target to figure # * Add classes for Bootstrap target = ':target: ' + self.options.pop('target', '') title = self.options['alt'] classes = ' '.join(document.settings.env.config.gallery_plot_classes + ['thumbnail']) template = ''' {{ only_html }} {% for img in images %} .. figure:: {{ build_dir }}/{{ img.basename }}.png ''' + target + ''' :figclass: ''' + classes + ''' {% for option in options -%} {{ option }} {% endfor %} {% endfor %} {{ only_latex }} {% for img in images %} {% if 'pdf' in img.formats -%} .. image:: {{ build_dir }}/{{ img.basename }}.pdf ''' + target + ''' {% endif -%} {% endfor %} {{ only_texinfo }} {% for img in images %} .. image:: {{ build_dir }}/{{ img.basename }}.png ''' + target + ''' {% for option in options -%} {{ option }} {% endfor %} {% endfor %} ''' plot_template_orig = document.settings.env.config.plot_template document.settings.env.config.plot_template = template # Don't bother with the high resolution version plot_formats_orig = document.settings.env.config.plot_formats plot_formats = [] for f in plot_formats_orig: if isinstance(f, str) and 'hires' in f: continue elif isinstance(f, tuple) and 'hires' in f[0]: continue plot_formats.append(f) document.settings.env.config.plot_formats = plot_formats options = { 'alt': title, } directive_instance = directive('plot', self.arguments, options, self.content, self.lineno, self.content_offset, self.block_text, self.state, self.state_machine) try: result = directive_instance.run() except DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=self.lineno) msg_node += nodes.literal_block(self.block_text, self.block_text) result = [msg_node] # Restore original settings document.settings.env.config.plot_template = plot_template_orig document.settings.env.config.plot_formats = plot_formats_orig return result
def run_directive(self, name: str, first_line: str, content: str, position: int) -> List[nodes.Element]: """Run a directive and return the generated nodes. :param name: the name of the directive :param first_line: The text on the same line as the directive name. May be an argument or body text, dependent on the directive :param content: All text after the first line. Can include options. :param position: The line number of the first line """ # TODO directive name white/black lists self.document.current_line = position # get directive class directive_class, messages = directives.directive( name, self.language_module_rst, self.document) # type: (Directive, list) if not directive_class: error = self.reporter.error( 'Unknown directive type "{}".\n'.format(name), # nodes.literal_block(content, content), line=position, ) return [error] + messages if issubclass(directive_class, Include): # this is a Markdown only option, # to allow for altering relative image reference links directive_class.option_spec["relative-images"] = directives.flag directive_class.option_spec["relative-docs"] = directives.path try: arguments, options, body_lines = parse_directive_text( directive_class, first_line, content) except DirectiveParsingError as error: error = self.reporter.error( "Directive '{}': {}".format(name, error), nodes.literal_block(content, content), line=position, ) return [error] # initialise directive if issubclass(directive_class, Include): directive_instance = MockIncludeDirective( self, name=name, klass=directive_class, arguments=arguments, options=options, body=body_lines, lineno=position, ) else: state_machine = MockStateMachine(self, position) state = MockState(self, state_machine, position) directive_instance = directive_class( name=name, # the list of positional arguments arguments=arguments, # a dictionary mapping option names to values options=options, # the directive content line by line content=StringList(body_lines, self.document["source"]), # the absolute line number of the first line of the directive lineno=position, # the line offset of the first line of the content content_offset= 0, # TODO get content offset from `parse_directive_text` # a string containing the entire directive block_text="\n".join(body_lines), state=state, state_machine=state_machine, ) # run directive try: result = directive_instance.run() except DirectiveError as error: msg_node = self.reporter.system_message(error.level, error.msg, line=position) msg_node += nodes.literal_block(content, content) result = [msg_node] except MockingError as exc: error_msg = self.reporter.error( "Directive '{}' cannot be mocked: {}: {}".format( name, exc.__class__.__name__, exc), nodes.literal_block(content, content), line=position, ) return [error_msg] assert isinstance( result, list), 'Directive "{}" must return a list of nodes.'.format(name) for i in range(len(result)): assert isinstance( result[i], nodes.Node ), 'Directive "{}" returned non-Node object (index {}): {}'.format( name, i, result[i]) return result