Commits

Georg Brandl committed 61e9e70

Convert directives in builtin extensions to class API.

Comments (0)

Files changed (4)

sphinx/ext/doctest.py

 from docutils.parsers.rst import directives
 
 from sphinx.builders import Builder
+from sphinx.util.compat import Directive
 from sphinx.util.console import bold
 
 blankline_re = re.compile(r'^\s*<BLANKLINE>', re.MULTILINE)
 
 # set up the necessary directives
 
-def test_directive(name, arguments, options, content, lineno,
-                   content_offset, block_text, state, state_machine):
-    # use ordinary docutils nodes for test code: they get special attributes
-    # so that our builder recognizes them, and the other builders are happy.
-    code = '\n'.join(content)
-    test = None
-    if name == 'doctest':
-        if '<BLANKLINE>' in code:
-            # convert <BLANKLINE>s to ordinary blank lines for presentation
-            test = code
-            code = blankline_re.sub('', code)
-        if doctestopt_re.search(code):
-            if not test:
+class TestDirective(Directive):
+    """
+    Base class for doctest-related directives.
+    """
+
+    has_content = True
+    required_arguments = 0
+    optional_arguments = 1
+    final_argument_whitespace = True
+
+    def run(self):
+        # use ordinary docutils nodes for test code: they get special attributes
+        # so that our builder recognizes them, and the other builders are happy.
+        code = '\n'.join(self.content)
+        test = None
+        if self.name == 'doctest':
+            if '<BLANKLINE>' in code:
+                # convert <BLANKLINE>s to ordinary blank lines for presentation
                 test = code
-            code = doctestopt_re.sub('', code)
-    nodetype = nodes.literal_block
-    if name == 'testsetup' or 'hide' in options:
-        nodetype = nodes.comment
-    if arguments:
-        groups = [x.strip() for x in arguments[0].split(',')]
-    else:
-        groups = ['default']
-    node = nodetype(code, code, testnodetype=name, groups=groups)
-    node.line = lineno
-    if test is not None:
-        # only save if it differs from code
-        node['test'] = test
-    if name == 'testoutput':
-        # don't try to highlight output
-        node['language'] = 'none'
-    node['options'] = {}
-    if name in ('doctest', 'testoutput') and 'options' in options:
-        # parse doctest-like output comparison flags
-        option_strings = options['options'].replace(',', ' ').split()
-        for option in option_strings:
-            if (option[0] not in '+-' or option[1:] not in
-                doctest.OPTIONFLAGS_BY_NAME):
-                # XXX warn?
-                continue
-            flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]]
-            node['options'][flag] = (option[0] == '+')
-    return [node]
+                code = blankline_re.sub('', code)
+            if doctestopt_re.search(code):
+                if not test:
+                    test = code
+                code = doctestopt_re.sub('', code)
+        nodetype = nodes.literal_block
+        if self.name == 'testsetup' or 'hide' in self.options:
+            nodetype = nodes.comment
+        if self.arguments:
+            groups = [x.strip() for x in self.arguments[0].split(',')]
+        else:
+            groups = ['default']
+        node = nodetype(code, code, testnodetype=self.name, groups=groups)
+        node.line = self.lineno
+        if test is not None:
+            # only save if it differs from code
+            node['test'] = test
+        if self.name == 'testoutput':
+            # don't try to highlight output
+            node['language'] = 'none'
+        node['options'] = {}
+        if self.name in ('doctest', 'testoutput') and 'options' in self.options:
+            # parse doctest-like output comparison flags
+            option_strings = self.options['options'].replace(',', ' ').split()
+            for option in option_strings:
+                if (option[0] not in '+-' or option[1:] not in
+                    doctest.OPTIONFLAGS_BY_NAME):
+                    # XXX warn?
+                    continue
+                flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]]
+                node['options'][flag] = (option[0] == '+')
+        return [node]
 
-# need to have individual functions for each directive due to different
-# options they accept
+class TestsetupDirective(TestDirective):
+    option_spec = {}
 
-def testsetup_directive(*args):
-    return test_directive(*args)
+class DoctestDirective(TestDirective):
+    option_spec = {
+        'hide': directives.flag,
+        'options': directives.unchanged,
+    }
 
-def doctest_directive(*args):
-    return test_directive(*args)
+class TestcodeDirective(TestDirective):
+    option_spec = {
+        'hide': directives.flag,
+    }
 
-def testcode_directive(*args):
-    return test_directive(*args)
-
-def testoutput_directive(*args):
-    return test_directive(*args)
+class TestoutputDirective(TestDirective):
+    option_spec = {
+        'hide': directives.flag,
+        'options': directives.unchanged,
+    }
 
 
 parser = doctest.DocTestParser()
 
 
 def setup(app):
-    app.add_directive('testsetup', testsetup_directive, 1, (0, 1, 1))
-    app.add_directive('doctest', doctest_directive, 1, (0, 1, 1),
-                      hide=directives.flag, options=directives.unchanged)
-    app.add_directive('testcode', testcode_directive, 1, (0, 1, 1),
-                      hide=directives.flag)
-    app.add_directive('testoutput', testoutput_directive, 1, (0, 1, 1),
-                      hide=directives.flag, options=directives.unchanged)
+    app.add_directive('testsetup', TestsetupDirective)
+    app.add_directive('doctest', DoctestDirective)
+    app.add_directive('testcode', TestcodeDirective)
+    app.add_directive('testoutput', TestoutputDirective)
     app.add_builder(DocTestBuilder)
     # this config value adds to sys.path
     app.add_config_value('doctest_path', [], False)

sphinx/ext/ifconfig.py

 
 from docutils import nodes
 
+from sphinx.util.compat import Directive
+
 
 class ifconfig(nodes.Element): pass
 
 
-def ifconfig_directive(name, arguments, options, content, lineno,
-                       content_offset, block_text, state, state_machine):
-    node = ifconfig()
-    node.line = lineno
-    node['expr'] = arguments[0]
-    state.nested_parse(content, content_offset, node)
-    return [node]
+class IfConfig(Directive):
+
+    has_content = True
+    required_arguments = 1
+    optional_arguments = 0
+    final_argument_whitespace = True
+    option_spec = {}
+
+    def run(self):
+        node = ifconfig()
+        node.document = self.state.document
+        node.line = self.lineno
+        node['expr'] = self.arguments[0]
+        self.state.nested_parse(self.content, self.content_offset, node)
+        return [node]
 
 
 def process_ifconfig_nodes(app, doctree, docname):
 
 def setup(app):
     app.add_node(ifconfig)
-    app.add_directive('ifconfig', ifconfig_directive, 1, (1, 0, 1))
+    app.add_directive('ifconfig', IfConfig)
     app.connect('doctree-resolved', process_ifconfig_nodes)

sphinx/ext/mathbase.py

 from docutils import nodes, utils
 from docutils.parsers.rst import directives
 
+from sphinx.util.compat import Directive
+
 
 class math(nodes.Inline, nodes.TextElement):
     pass
     node['docname'] = inliner.document.settings.env.docname
     return [node], []
 
-def math_directive(name, arguments, options, content, lineno,
-                   content_offset, block_text, state, state_machine):
-    latex = '\n'.join(content)
-    if arguments and arguments[0]:
-        latex = arguments[0] + '\n\n' + latex
-    node = displaymath()
-    node['latex'] = latex
-    node['label'] = options.get('label', None)
-    node['nowrap'] = 'nowrap' in options
-    node['docname'] = state.document.settings.env.docname
-    ret = [node]
-    if node['label']:
-        tnode = nodes.target('', '', ids=['equation-' + node['label']])
-        state.document.note_explicit_target(tnode)
-        ret.insert(0, tnode)
-    return ret
+
+class MathDirective(Directive):
+
+    has_content = True
+    required_arguments = 0
+    optional_arguments = 1
+    final_argument_whitespace = True
+    option_spec = {
+        'label': directives.unchanged,
+        'nowrap': directives.flag,
+    }
+
+    def run(self):
+        latex = '\n'.join(self.content)
+        if self.arguments and self.arguments[0]:
+            latex = self.arguments[0] + '\n\n' + latex
+        node = displaymath()
+        node['latex'] = latex
+        node['label'] = self.options.get('label', None)
+        node['nowrap'] = 'nowrap' in self.options
+        node['docname'] = self.state.document.settings.env.docname
+        ret = [node]
+        if node['label']:
+            tnode = nodes.target('', '', ids=['equation-' + node['label']])
+            self.state.document.note_explicit_target(tnode)
+            ret.insert(0, tnode)
+        return ret
 
 
 def latex_visit_math(self, node):
                  html=(html_visit_eqref, html_depart_eqref))
     app.add_role('math', math_role)
     app.add_role('eq', eq_role)
-    app.add_directive('math', math_directive, 1, (0, 1, 1),
-                      label=directives.unchanged, nowrap=directives.flag)
+    app.add_directive('math', MathDirective)
     app.connect('doctree-resolved', number_equations)

sphinx/ext/todo.py

 
 from docutils import nodes
 
-from sphinx.util.compat import make_admonition
+from sphinx.util.compat import Directive, make_admonition
 
 class todo_node(nodes.Admonition, nodes.Element): pass
 class todolist(nodes.General, nodes.Element): pass
 
 
-def todo_directive(name, arguments, options, content, lineno,
-                   content_offset, block_text, state, state_machine):
-    env = state.document.settings.env
+class Todo(Directive):
+    """
+    A todo entry, displayed (if configured) in the form of an admonition.
+    """
 
-    targetid = "todo-%s" % env.index_num
-    env.index_num += 1
-    targetnode = nodes.target('', '', ids=[targetid])
+    has_content = True
+    required_arguments = 0
+    optional_arguments = 0
+    final_argument_whitespace = False
+    option_spec = {}
 
-    ad = make_admonition(todo_node, name, [_('Todo')], options, content, lineno,
-                         content_offset, block_text, state, state_machine)
+    def run(self):
+        env = self.state.document.settings.env
 
-    # Attach a list of all todos to the environment,
-    # the todolist works with the collected todo nodes
-    if not hasattr(env, 'todo_all_todos'):
-        env.todo_all_todos = []
-    env.todo_all_todos.append({
-        'docname': env.docname,
-        'lineno': lineno,
-        'todo': ad[0].deepcopy(),
-        'target': targetnode,
-    })
+        targetid = "todo-%s" % env.index_num
+        env.index_num += 1
+        targetnode = nodes.target('', '', ids=[targetid])
 
-    return [targetnode] + ad
+        ad = make_admonition(todo_node, self.name, [_('Todo')], self.options,
+                             self.content, self.lineno, self.content_offset,
+                             self.block_text, self.state, self.state_machine)
 
+        # Attach a list of all todos to the environment,
+        # the todolist works with the collected todo nodes
+        if not hasattr(env, 'todo_all_todos'):
+            env.todo_all_todos = []
+        env.todo_all_todos.append({
+            'docname': env.docname,
+            'lineno': self.lineno,
+            'todo': ad[0].deepcopy(),
+            'target': targetnode,
+        })
 
-def todolist_directive(name, arguments, options, content, lineno,
-                       content_offset, block_text, state, state_machine):
-    # Simply insert an empty todolist node which will be replaced later
-    # when process_todo_nodes is called
-    return [todolist('')]
+        return [targetnode] + ad
+
+
+class TodoList(Directive):
+    """
+    A list of all todo entries.
+    """
+
+    has_content = False
+    required_arguments = 0
+    optional_arguments = 0
+    final_argument_whitespace = False
+    option_spec = {}
+
+    def run(self):
+        # Simply insert an empty todolist node which will be replaced later
+        # when process_todo_nodes is called
+        return [todolist('')]
 
 
 def process_todo_nodes(app, doctree, fromdocname):
                  latex=(visit_todo_node, depart_todo_node),
                  text=(visit_todo_node, depart_todo_node))
 
-    app.add_directive('todo', todo_directive, 1, (0, 0, 1))
-    app.add_directive('todolist', todolist_directive, 0, (0, 0, 0))
+    app.add_directive('todo', Todo)
+    app.add_directive('todolist', TodoList)
     app.connect('doctree-resolved', process_todo_nodes)
     app.connect('env-purge-doc', purge_todos)