I'm the maintainer of sphinx-needs, which allows the definition of requirements, bugs, ...
These objects get stored inside the related directive run function and I finally get a list of all objects inside my sphinx documentation.
The objects can be linked to each other and I want to create a diagram of these links (using plantuml and related sphinx-plantuml extension).
The problem is, that I don't know how to let sphinx add and rerender a dynamically created plantuml diagram specification.
Inside a directive, I could use the state_machine to get this done:
diagram = generate_plantuml_spec(objects)
self.state_machine.insert_input(
diagram.split('\n'),
self.state_machine.document.attributes['source'])
But that's the wrong place, as my extension has not collected all objects yet.
So the right place should be inside a function, which gets executed when the event "doctree-resolved" is fired by sphinx.
Inside this function I'm able to add any kind of docutils nodes. My idea is to create a node.Text() with the generated diagram spec
def process_needfilters(app, doctree, fromdocname):
diagram_data = """"
.. plantuml::
@startuml
node Test
@enduml
"""
for node in doctree.traverse(needs_diagram):
content = []
diagram = nodes.Text(diagram_data, diagram_data)
content.append(diagram)
node.replace_self(content)
However this will not force sphinx to render the content.
I also found a sphinx function called nested_parse_with_titles(), but this needs a 'state' object, which is only available inside a directive and not inside an event handler.
So, any idea how I can render rst content inside sphinx event handlers?
Solution is to use directly the plantuml node from the plantuml-extension:
Simplified code snippet from sphinx-needs:
from sphinxcontrib.plantuml import plantuml
for node in doctree.traverse(MyDirective):
plantuml_block_text = ".. plantuml::\n" \
"\n" \
" @startuml" \
" @enduml"
puml_node = plantuml(plantuml_block_text, **dict())
node.replace_self(puml_node)