Reputation: 43091
I am using Sphinx to generate the documentation for a project of mine.
In this project, I describe a list of available commands in a yaml file which, once loaded, results in a dictionary in the form {command-name : command-description}
for example:
commands = {"copy" : "Copy the highlighted text in the clipboard",
"paste" : "Paste the clipboard text to cursor location",
...}
What I would like to know, is if there is a method in sphinx to load the yaml file during the make html
cycle, translate the python dictionary in some reStructuredText format (e.g. a definition list) and include in my html output.
I would expect my .rst
file to look like:
Available commands
==================
The commands available in bla-bla-bla...
.. magic-directive-that-execute-python-code::
:maybe python code or name of python file here:
and to be converted internally to:
Available commands
==================
The commands available in bla-bla-bla...
copy
Copy the highlighted text in the clipboard
paste
Paste the clipboard text to cursor location
before being translated to HTML.
Upvotes: 30
Views: 16552
Reputation: 5222
Not quite the answer you're after, but perhaps a close approximation: yaml2rst. It's a converter from YAML to RST. Doesn't do anything explicitly fancy with the YAML itself, but looks for comment lines (starts with #
) and pulls them out into RST chunks (with the YAML going into code-block
s). Allows for a sort-of literate YAML.
Also, the syntax-highlighted YAML is quite readable (heck, it's YAML, not JSON!).
Upvotes: 0
Reputation: 1435
An improvement based on Michael's code and the built-in include directive:
import sys
from os.path import basename
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
from docutils.parsers.rst import Directive
from docutils import nodes, statemachine
class ExecDirective(Directive):
"""Execute the specified python code and insert the output into the document"""
has_content = True
def run(self):
oldStdout, sys.stdout = sys.stdout, StringIO()
tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
source = self.state_machine.input_lines.source(self.lineno - self.state_machine.input_offset - 1)
try:
exec('\n'.join(self.content))
text = sys.stdout.getvalue()
lines = statemachine.string2lines(text, tab_width, convert_whitespace=True)
self.state_machine.insert_input(lines, source)
return []
except Exception:
return [nodes.error(None, nodes.paragraph(text = "Unable to execute python code at %s:%d:" % (basename(source), self.lineno)), nodes.paragraph(text = str(sys.exc_info()[1])))]
finally:
sys.stdout = oldStdout
def setup(app):
app.add_directive('exec', ExecDirective)
This one imports the output earlier so that it goes straight through the parser. It also works in Python 3.
Upvotes: 18
Reputation: 81
I know this question is old, but maybe someone else will find it useful as well.
It sounds like you don't actually need to execute any python code, but you just need to reformat the contents of your file. In that case you might want to look at sphinx-jinja (https://pypi.python.org/pypi/sphinx-jinja).
You can load your YAML file in the conf.py
:
jinja_contexts = yaml.load(yourFileHere)
Then you can use jinja templating to write out the contents and have them treated as reST input.
Upvotes: 3
Reputation: 175745
I needed the same thing, so I threw together a new directive that seems to work (I know nothing about custom Sphinx directives, but it's worked so far):
import sys
from os.path import basename
from StringIO import StringIO
from sphinx.util.compat import Directive
from docutils import nodes
class ExecDirective(Directive):
"""Execute the specified python code and insert the output into the document"""
has_content = True
def run(self):
oldStdout, sys.stdout = sys.stdout, StringIO()
try:
exec '\n'.join(self.content)
return [nodes.paragraph(text = sys.stdout.getvalue())]
except Exception, e:
return [nodes.error(None, nodes.paragraph(text = "Unable to execute python code at %s:%d:" % (basename(self.src), self.srcline)), nodes.paragraph(text = str(e)))]
finally:
sys.stdout = oldStdout
def setup(app):
app.add_directive('exec', ExecDirective)
It's used as follows:
.. exec::
print "Python code!"
print "This text will show up in the document"
Upvotes: 9
Reputation: 9303
Sphinx does support custom extensions that would probably be the best way to do this http://sphinx.pocoo.org/ext/tutorial.html.
Upvotes: 1
Reputation: 43091
At the end I find a way to achieve what I wanted. Here's the how-to:
generate-includes.py
) that will generate the reStructuredText and save it in the myrst.inc
file. (In my example, this would be the script loading and parsing the YAML, but this is irrelevant). Make sure this file is executable!!!Use the include
directive in your main .rst document of your documentation, in the point where you want your dynamically-generated documentation to be inserted:
.. include:: myrst.inc
Modify the sphinx Makefile in order to generate the required .inc files at build time:
myrst.inc:
./generate-includes.py
html: myrst.inc
...(other stuff here)
Build your documentation normally with make html
.
Upvotes: 27
Reputation: 3405
Sphinx doesn't have anything built-in to do what you like. You can either create a custom directive to process your files or generate the reStructuredText in a separate step and include the resulting reStructuredText file using the include directive.
Upvotes: 4