开发一个 “Hello world” 插件

本教程的目的是创建一个非常基本的扩展,增加一个新的指令。这条指令将输出一个包含 “hello world” 的段落。

本教程中只提供了基本信息。更多信息,请参考 其他教程,其中有更多细节。

警告

对于这个插件,你需要对 docutils 和 Python 有一些基本了解。

概述

我们希望这个插件能给 Sphinx 增加以下内容:

  • 一个 helloworld 指令,它将简单地输出文字 “hello world”。

前提条件

我们不会通过 PyPI 来发布这个插件,而是将其作为现有项目的一部分。这意味着你需要使用一个现有的项目或使用 sphinx-quickstart 创建一个新的项目。

我们假设你在使用独立的源文件(source)和构建文件(build)文件夹。你的插件文件可以在你项目的任何文件夹中。在我们的例子中,让我们做以下事情:

  1. source 中创建一个 _ext 文件夹

  2. _ext 文件夹下创建一个新的 Python 文件,名为 helloworld.py

下面是一个你可能获得的文件夹结构的例子:

└── source
    ├── _ext
    │   └── helloworld.py
    ├── _static
    ├── conf.py
    ├── somefolder
    ├── index.rst
    ├── somefile.rst
    └── someotherfile.rst

编写插件

打开 helloworld.py 并在其中粘贴以下代码:

 1from docutils import nodes
 2from docutils.parsers.rst import Directive
 3
 4
 5class HelloWorld(Directive):
 6
 7    def run(self):
 8        paragraph_node = nodes.paragraph(text='Hello World!')
 9        return [paragraph_node]
10
11
12def setup(app):
13    app.add_directive("helloworld", HelloWorld)
14
15    return {
16        'version': '0.1',
17        'parallel_read_safe': True,
18        'parallel_write_safe': True,
19    }

在这个例子中发生了一些基本的事情,对于所有的指令,你都会看到它们。

指令类

我们的新指令是在 HelloWorld 类中声明的。

1class HelloWorld(Directive):
2
3    def run(self):
4        paragraph_node = nodes.paragraph(text='Hello World!')
5        return [paragraph_node]

该类扩展了 docutils Directive 类。所有创建指令的插件都应该扩展这个类。

该类包含一个 run 方法。这个方法是一个需求,它是每个指令的一部分。它包含指令的主要逻辑,并返回一个由 Sphinx 处理的 docutils 节点的列表。这些节点是 docutils 表示文档内容的方式。有许多类型的节点可用:text、paragraph、reference、table 等。

nodes.paragraph 类创建一个新的段落节点。一个段落节点通常包含一些文本,我们可以在实例化过程中使用 text 参数来设置。

setup 函数

这个函数是一个需求。我们用它来把我们的新指令插入 Sphinx。

1def setup(app):
2    app.add_directive("helloworld", HelloWorld)
3
4    return {
5        'version': '0.1',
6        'parallel_read_safe': True,
7        'parallel_write_safe': True,
8    }

你能做的最简单的事情就是调用 add_directive() 方法,这就是我们在这里做的。对于这个特殊的调用,第一个参数是 reST 文件中使用的指令本身的名字。在这种情况下,我们会使用 helloworld。比如说:

Some intro text here...

.. helloworld::

Some more text here...

我们还返回 插件元数据,表明我们的插件版本,以及使用插件进行并行读写都是安全的。

使用插件

扩展名必须在你的 conf.py 文件中声明,以使 Sphinx 知道它。这里有两个必要的步骤:

  1. 使用 sys.path.append_ext 目录添加到 Python 路径。这应该放在文件的顶部。

  2. 更新或创建 extensions 列表,并将插件添加到该列表中

例如:

import os
import sys

sys.path.append(os.path.abspath("./_ext"))

extensions = ['helloworld']

小技巧

我们没有把这个插件作为 Python 包 发布,我们需要修改 Python 路径,以便 Sphinx 能找到我们的插件。这就是为什么我们需要调用 sys.path.append

现在你可以在文件中使用插件。比如说:

Some intro text here...

.. helloworld::

Some more text here...

上面的例子会输出:

Some intro text here...

Hello World!

Some more text here...

深入阅读

这是创造一个新指令的插件的非常基本的原则。

关于更高级的例子,请参考 开发 “TODO” 插件