Extending documentation documentation Does Sphinx work differently for HTML and LaTeX output?

I have a simple Sphinx extension as follows:

from docutils import nodes from docutils.parsers.rst import directives from sphinx.util.compat import Directive class testnode(nodes.Element): def __init__(self, *args, **kwargs): super(testnode, self).__init__(*args, **kwargs) self['foo'] = '?' def visit_testnode_latex(self, node): self.body.append('Test: %s' % node['foo']) def depart_testnode_latex(self, node): pass def visit_testnode_html(self, node): self.body.append('<p>Test: %s</p>' % node['foo']) def depart_testnode_html(self, node): pass class TestDirective(Directive): has_content = False required_arguments = 0 optional_arguments = 0 final_argument_whitespace = False option_spec = { 'foo': directives.unchanged, } def run(self): node = testnode() node['foo'] = self.options.get('foo') return [node] def setup(app): app.add_directive("testdirective", TestDirective) app.add_node(testnode, html=(visit_testnode_html, depart_testnode_html), latex=(visit_testnode_latex, depart_testnode_latex)) 

Given a document containing

 .. testdirective:: :foo: bar 

HTML output contains "Test: bar" but LaTeX output contains "Test :?" (default value). I checked that node['foo'] has the correct value after assignment in TestDirective.run() , but it doesn’t seem like it will work until the LaTeX script is run.

What am I doing wrong?

+8
python python-sphinx
source share
1 answer

After navigating through LaTeX writer for Sphinx, I found the problem here. This is the way you set the default value for the 'foo' keyword in the testnode initializer.

The writer LaTeX makes sense that he makes a deep copy of the entire document tree to embed it in another tree. The deepcopy function on an Element node initializes a new node of the same class and passes all the attributes and contents of the source node through the constructor. Therefore, when your testnode copied, your constructor overrides the original attribute "foo", which is passed to the constructor. Instead, write this and it should work:

 class testnode(nodes.Element): def __init__(self, *args, **kwargs): super(testnode, self).__init__(*args, **kwargs) if 'foo' not in self: self['foo'] = '?' 

This will prevent overriding your default value for the explicit attribute value passed to the constructor. Other options are possible.

+3
source share

All Articles