[英]Force Sphinx to interpret Markdown in Python docstrings instead of reStructuredText
I'm using Sphinx to document a python project.我正在使用 Sphinx 来记录一个 python 项目。 I would like to use Markdown in my docstrings to format them.
我想在我的文档字符串中使用 Markdown 来格式化它们。 Even if I use the
recommonmark
extension, it only covers the .md
files written manually, not the docstrings.即使我使用
recommonmark
扩展名,它也只涵盖手动编写的.md
文件,而不是文档字符串。
I use autodoc
, napoleon
and recommonmark
in my extensions.我在我的扩展中使用
autodoc
、 napoleon
和recommonmark
。
How can I make sphinx parse markdown in my docstrings?如何在我的文档字符串中进行 sphinx 解析降价?
Sphinx's autodoc
extension emits an event named autodoc-process-docstring
every time it processes a doc-string. 每次处理文档字符串时,Sphinx的
autodoc
扩展都会发出一个名为autodoc-process-docstring
的事件。 You can hook into that mechanism to convert the syntax from Markdown to reStructuredText. 您可以挂钩该机制将语法从Markdown转换为reStructuredText。
I do not know why recommonmark
does not offer that functionality out of the box. 我不知道为什么
recommonmark
不能提供开箱即用的功能。 It should be an easy feature to add. 这应该是一个简单的功能添加。 Personally, I use
m2r
for the conversion in my projects. 就个人而言,我在我的项目中使用
m2r
进行转换。 Because it's fast — much faster than pandoc
, for example. 因为它很快 -
pandoc
如pandoc
快得多。 Speed is important as the conversion happens on the fly and handles each doc-string individually. 速度很重要,因为转换会动态发生并单独处理每个文档字符串。 Other than that, any Markdown-to-reST converter would do.
除此之外,任何Markdown-to-reST转换器都可以。
Install m2r
and add the following to Sphinx's configuration file conf.py
: 安装
m2r
并将以下内容添加到Sphinx的配置文件conf.py
:
import m2r
def docstring(app, what, name, obj, options, lines):
md = '\n'.join(lines)
rst = m2r.convert(md)
lines.clear()
for line in rst.splitlines():
lines.append(line)
def setup(app):
app.connect('autodoc-process-docstring', docstring)
[ Edited to add… ] [已编辑添加... ]
Just like above, but with commonmark
: 就像上面一样,但有
commonmark
:
import commonmark
def docstring(app, what, name, obj, options, lines):
md = '\n'.join(lines)
ast = commonmark.Parser().parse(md)
rst = commonmark.ReStructuredTextRenderer().render(ast)
lines.clear()
for line in rst.splitlines():
lines.append(line)
def setup(app):
app.connect('autodoc-process-docstring', docstring)
This uses the same Markdown parser as the Sphinx extension recommonmark
and is as fast as m2r
, which means next to no effect on build time compared to the native reStructuredText. 这使用与Sphinx扩展
recommonmark
相同的Markdown解析器,并且与m2r
一样快,这意味着与本机reStructuredText相比,接下来对构建时间没有影响。
Building on @john-hennig answer, the following will keep the restructured text fields like: :py:attr:
, :py:class:
etc. .基于@john-hennig 的回答,以下内容将保留重组后的文本字段,例如:
:py:attr:
、 :py:class:
等。 This allows you to reference other classes, etc.这允许您引用其他类等。
import re
import commonmark
py_attr_re = re.compile(r"\:py\:\w+\:(``[^:`]+``)")
def docstring(app, what, name, obj, options, lines):
md = '\n'.join(lines)
ast = commonmark.Parser().parse(md)
rst = commonmark.ReStructuredTextRenderer().render(ast)
lines.clear()
lines += rst.splitlines()
for i, line in enumerate(lines):
while True:
match = py_attr_re.search(line)
if match is None:
break
start, end = match.span(1)
line_start = line[:start]
line_end = line[end:]
line_modify = line[start:end]
line = line_start + line_modify[1:-1] + line_end
lines[i] = line
def setup(app):
app.connect('autodoc-process-docstring', docstring)
I had to extend the accepted answer by john-hen to allow multi-line descriptions of Args:
entries to be considered a single parameter:我不得不扩展 john-hen 接受的答案,以允许
Args:
条目的多行描述被视为单个参数:
def docstring(app, what, name, obj, options, lines):
wrapped = []
literal = False
for line in lines:
if line.strip().startswith(r'```'):
literal = not literal
if not literal:
line = ' '.join(x.rstrip() for x in line.split('\n'))
indent = len(line) - len(line.lstrip())
if indent and not literal:
wrapped.append(' ' + line.lstrip())
else:
wrapped.append('\n' + line.strip())
ast = commonmark.Parser().parse(''.join(wrapped))
rst = commonmark.ReStructuredTextRenderer().render(ast)
lines.clear()
lines += rst.splitlines()
def setup(app):
app.connect('autodoc-process-docstring', docstring)
The current @john-hennig is great, but seems to be failing for multi-line Args:
in python style.当前的@john-hennig 很棒,但似乎在多行
Args:
失败了Args:
python 风格。 Here was my fix:这是我的修复:
def docstring(app, what, name, obj, options, lines):
md = "\n".join(lines)
ast = commonmark.Parser().parse(md)
rst = commonmark.ReStructuredTextRenderer().render(ast)
lines.clear()
lines += _normalize_docstring_lines(rst.splitlines())
def _normalize_docstring_lines(lines: list[str]) -> list[str]:
"""Fix an issue with multi-line args which are incorrectly parsed.
```
Args:
x: My multi-line description which fit on multiple lines
and continue in this line.
```
Is parsed as (missing indentation):
```
:param x: My multi-line description which fit on multiple lines
and continue in this line.
```
Instead of:
```
:param x: My multi-line description which fit on multiple lines
and continue in this line.
```
"""
is_param_field = False
new_lines = []
for l in lines:
if l.lstrip().startswith(":param"):
is_param_field = True
elif is_param_field:
if not l.strip(): # Blank line reset param
is_param_field = False
else: # Restore indentation
l = " " + l.lstrip()
new_lines.append(l)
return new_lines
def setup(app):
app.connect("autodoc-process-docstring", docstring)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.