使用 Sphinx 为 Python 生成文档的正确姿势
使用一个有文档的程序 (库) 是一件幸福的事,但维护一套文档是一件痛苦的事。
为了将广大程序员从写文档的地狱中解救出来,程序员们发明了 (目前为止) 写文档的最佳实践 —— 文档代码化 —— 也就是将文档和代码写在一起,一般是通过注释的方式。文档代码化的好处这里就不再赘述了。
幸运的是 Python 是支持文档代码化的,通过 """
注释。但作为 Python 文档之光的 Sphinx 做文档代码化的体验并不好。这也不能怪 Sphinx,毕竟 Sphinx 出生时,文档代码化的概念还没有被人们所熟知。
如果你在网上搜索“使用 Sphinx 为 Python 生成文档”,搜索到的方法多半是:
- 新建文件夹
doc(s)
- 在
docs
中使用sphinx-quickstart
新建一个 Sphinx 工程 - 配置 Sphinx 工程
- 用
sphinx-apidoc
读取代码,生成rst
文件 - …
好的,现在你不仅要写代码,还要维护文档了,非常 old school!
我们可以看出,Sphinx 并没有逃出:写代码,写文档,写代码的地狱。正确的文档代码化实践应当是:
- 写代码,在注释中写文档
- 通过 CI 直接从代码中生成文档
好在最新版的 sphinx-apidoc
基本支持这一实践 (只是有点简陋)。
使用 sphinx-apidoc 自动生成文档🔗
阅读最新的 sphinx-apidoc 文档 我们可以发现, sphinx-apidoc
实际上是可以生成一个完整的 Sphinx 工程的:
所以,其实我们并不需要 sphinx-quickstart
,直接在 Python 工程中(使用 -f
强制生成):
sphinx-apidoc -f -F -o docs <code dir>
你还可以将它配置在 Makefile 中:
DOCS_CMD = sphinx-apidoc
PROJ_DIR = myq_spider
DOCS_DIR = docs
doc: $(DOCS_DIR)
$(DOCS_DIR): $(PROJ_NAME)
@$(DOCS_CMD) -f -F -o $@ $<
html: $(DOCS_DIR)
@$(MAKE) -C $< html
然后直接在 Python 工程中运行 make docs
和 make html
就可以生成、编译文档了。
然后配合 CI,就可以基本实现在不维护一套独立的 Sphinx 文档的前提下,自动生成 API 文档。
使用模板 (进阶)🔗
目前为止,基于 sphinx-apidoc
的文档代码化已经基本能用了,但并不好用。
原因在于配置文件 conf.py
会在每次运行 make docs
时刷新到初始状态。项目名称、作者姓名等信息尚且可以通过 [OPTIONS] 传入:
但主题怎么办?那个丑不拉几的默认主题?看多了也不怕性冷淡…
还有各种插件也没法配置,只能用默认的…
好在 >=2.2
的版本增加了模板的支持。
我们首先将生成的 docs/conf.py
复制一份到 docs/_templates/conf.py_t
。
然后根据实际需要在 docs/_templates/conf.py_t
中修改配置。
最后在 Makefile
中指定存放模板的文件夹:
DOCS_CMD = sphinx-apidoc
PROJ_DIR = myq_spider
DOCS_DIR = docs
doc: $(DOCS_DIR)
$(DOCS_DIR):
@$(DOCS_CMD) -f -F -t $@/_templates -o $@ $(PROJ_NAME)
html: $(DOCS_DIR)
@$(MAKE) -C $< html
生成文档时,sphinx-apidoc
会以 docs/_templates/conf.py_t
作为模板生成 docs/conf.py
,从而实现对 docs/conf.py
的配置。
当然你也可以复制并配置 Sphinx 安装目录中的 templates/quickstart/conf.py_t
,以获得更好的动态灵活性。
.gitignore🔗
既然选择了 CI 来自动生成 API 文档,那么 docs
文件夹中的 Sphinx 项目似乎就有点多余。
我们可以通过 .gitignore
来排除它们 (只包含模板和静态文件):
# Sphinx documentation
docs/*
!docs/_static
!docs/_templates
包含 README.rst🔗
有时候我们会希望 Python 项目的 API 文档的首页包含本项目的 README.rst。
同样的,直接修改 docs/index.rst
是没用的,我们需要使用模板。
但这次不能直接复制 docs/index.rst
了,我们需要一点动态能力,复制并配置 Sphinx 安装目录中的 templates/quickstart/root_doc.rst_t
至 docs/_templates/root_doc.rst_t
,然后修改 (找不到 Sphinx 安装目录的可以直接复制以下内容):
.. {{ project }} documentation master file, created by
sphinx-quickstart on {{ now }}.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to {{ project }}'s documentation!
==========={{ project_underline }}=================
.. toctree::
:maxdepth: {{ mastertocmaxdepth }}
:caption: Contents:
{{ mastertoctree }}
README.rst
==========
.. include:: ../README.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`