如何使用Python程序生成Sphinx文档的一部分?
我正在使用Sphinx来为我的一个项目生成文档。
在这个项目中,我在一个yaml文件里列出了可用的命令,这个文件加载后会变成一个字典,格式是{命令名称 : 命令描述}
,比如:
commands = {"copy" : "Copy the highlighted text in the clipboard",
"paste" : "Paste the clipboard text to cursor location",
...}
我想知道的是,Sphinx有没有办法在执行make html
的时候加载这个yaml文件,把这个Python字典转换成某种reStructuredText格式(例如,一个定义列表),然后包含在我的HTML输出中。
我希望我的.rst
文件看起来像这样:
Available commands
==================
The commands available in bla-bla-bla...
.. magic-directive-that-execute-python-code::
:maybe python code or name of python file here:
然后在内部转换成:
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
最后再转换成HTML。
7 个回答
9
我也需要这个功能,所以我简单做了一个新的指令,似乎可以用(我对自定义 Sphinx 指令一无所知,但到目前为止它都能正常工作):
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)
用法如下:
.. exec::
print "Python code!"
print "This text will show up in the document"
18
这是对Michael的代码和内置的包含指令进行的一些改进:
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)
这个方法会提前导入输出,这样它就可以直接通过解析器处理了。而且它在Python 3中也能正常工作。
27
最后我找到了一种方法来实现我想要的效果。下面是具体步骤:
- 创建一个Python脚本(我们叫它
generate-includes.py
),这个脚本会生成 reStructuredText 格式的内容,并把它保存到myrst.inc
文件中。(在我的例子中,这个脚本会加载和解析YAML文件,但这并不重要)。确保这个文件是可以执行的!!! 在你的主 .rst 文档中使用
include
指令,在你希望插入动态生成文档的地方:.. include:: myrst.inc
修改 Sphinx 的 Makefile,以便在构建时生成所需的 .inc 文件:
myrst.inc: ./generate-includes.py html: myrst.inc ...(other stuff here)
正常构建你的文档,使用
make html
命令。