之前项目文档是用 reStructuredText 格式写的,但是这个语法比较复杂,还是更喜欢用 Markdown 写。 这几天把文档从 Sphinx 迁移到 MKDocs ,还是托管在 ReadTheDocs 上面,遇到几个坑。
-
MKDocs 没有 autodoc 插件,而且还没有插件 API Issue。 其实是有一个 autodoc 插件的,但是 MKDocs 没有插件 API ,那个插件作者只好把 MKDocs 代码给改了, 到现在已经大半年了插件 API 还没搞定。。。这样也就没法在 ReadTheDocs 上使用。
-
托管到 ReadTheDocs 上只能用 ReadTheDocs 的主题,Issue。
At present the theme is hard-coded: https://github.com/rtfd/readthedocs.org/blob/master/readthedocs/doc_builder/backends/mkdocs.py#L147
研究了两天源码,最后用 Hack 手段搞定,核心代码:
@patch(build.build)
def patched_build(f, config, *args, **kwargs):
print("HACK".center(60, "-"))
real_config = load_config(config_file=None)
for k in ["theme", "theme_dir"]:
config[k] = real_config[k]
return f(config, *args, **kwargs)
运行时修改 build 函数
PATCHED = {}
def patch(f_be_patched):
def decorater(f):
key = str(uuid.uuid4())
PATCHED[key] = functools.partial(f, copy_func(f_be_patched))
code = """
def wrapper(*args, **kwargs):
return __import__("magicpatch").PATCHED["{}"](*args, **kwargs)
""".format(key)
context = {}
exec(code, context)
f_be_patched.__code__ = context["wrapper"].__code__
return f
return decorater
这句f_be_patched.__code__ = context["wrapper"].__code__比较魔性,直接修改函数定义,
但是有限制, locals,globals,closure 这些必须一致(无法修改),也就是只能使用原有的函数能用的变量。
完整代码在这: https://github.com/restaction/mkdocs-autodoc
Demo: http://restaction.readthedocs.io/zh_CN/latest/api/