pythonpython-sphinxdocutils

How can I use an existing Directive within a custom python-sphinx Directive/extension?


I'd like to create a custom Directive that uses the an existing Directive (code-block in this example) in it's implementation.

The manual equivalent of this in reStructuredText would be:

.. mydirective:: py

   .. code-block: py
        
      print("Hello world")     

However, I would like the code-block to be created within my-directive's definition. I found an example that hard-codes the appropriate reStructuredText for the existing Directive (below), but this depends on the parser using rST.

class MyDirective(Directive):
    has_content = True

    def run(self):
        # Do custom stuff...

        # Use code-block Directive
        new_content = [
            '.. tab:: {}'.format(json.dumps(tab_args)),
            '   {}'.format(tab_name),
            '',
            '   .. code-block:: {}'.format(lang),
        ]

        if 'linenos' in self.options:
            new_content.append('      :linenos:')

        new_content.append('')

        for idx, line in enumerate(new_content):
            self.content.data.insert(idx, line)
            self.content.items.insert(idx, (None, idx))

        node = nodes.container()
        self.state.nested_parse(self.content, self.content_offset, node)
        return node.children

How could I implement this in a parser-independent fashion?


Solution

  • In the end, my solution was:

    from sphinx.directives.code import CodeBlock
    
    
    class CodeTabDirective(CodeBlock):
        """ Tab directive with a codeblock as its content"""
    
        def run(self):
            self.assert_has_content()
            
            code_block = super().run()[0]
    
            # Set anything required by OtherDirective
    
            node = OtherDirective.run(self)[0]  # Generates container
            node.append(code_block)  # Put code block inside container
    
            return [node]
    

    Where OtherDirective was another existing directive.

    I wasn't able to subclass both directives and use their functionality via super, as I needed to call a method named run from both.

    Update

    You can see the final solution in place in the CodeTabDirective of sphinx-tabs.