使用角色和指令扩展语法¶
概述¶
reStructuredtext和MyST的语法都可以通过创建新的 directives - 对于块级元素-和 roles - 对于内联元素。
在本教程中,我们将扩展Sphinx以添加:
A
hello
角色,这将简单地输出文本Hello {text}!
.A
hello
指令,这将简单地输出文本Hello {text}!
,作为一个段落。
对于这个扩展,您需要对Python有一些基本的了解,我们还将介绍 docutils API.
设置项目¶
您可以使用现有的Sphinx项目,也可以使用创建新项目 sphinx-quickstart .
通过此,我们将在 source
文件夹:
创建一个
_ext
文件夹source
在
_ext
文件夹被称为helloworld.py
以下是您可能获得的文件夹结构的示例:
└── source
├── _ext
│ └── helloworld.py
├── conf.py
├── index.rst
编写扩展¶
开放 helloworld.py
并将以下代码粘贴在其中:
1from __future__ import annotations
2
3from docutils import nodes
4
5from sphinx.application import Sphinx
6from sphinx.util.docutils import SphinxDirective, SphinxRole
7from sphinx.util.typing import ExtensionMetadata
8
9
10class HelloRole(SphinxRole):
11 """A role to say hello!"""
12
13 def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
14 node = nodes.inline(text=f'Hello {self.text}!')
15 return [node], []
16
17
18class HelloDirective(SphinxDirective):
19 """A directive to say hello!"""
20
21 required_arguments = 1
22
23 def run(self) -> list[nodes.Node]:
24 paragraph_node = nodes.paragraph(text=f'hello {self.arguments[0]}!')
25 return [paragraph_node]
26
27
28def setup(app: Sphinx) -> ExtensionMetadata:
29 app.add_role('hello', HelloRole())
30 app.add_directive('hello', HelloDirective)
31
32 return {
33 'version': '0.1',
34 'parallel_read_safe': True,
35 'parallel_write_safe': True,
36 }
这个例子中正在发生一些重要的事情:
角色类¶
我们的新角色在 HelloRole
课
1class HelloRole(SphinxRole):
2 """A role to say hello!"""
3
4 def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
5 node = nodes.inline(text=f'Hello {self.text}!')
6 return [node], []
这个类扩展了 SphinxRole
课该类包含 run
方法,这是每个角色的要求。它包含角色的主要逻辑,并返回一个包含以下内容的数组:
要由Sphinx处理的内联级文档节点列表。
系统消息节点的(可选)列表
指令类¶
我们的新指令在 HelloDirective
课
1class HelloDirective(SphinxDirective):
2 """A directive to say hello!"""
3
4 required_arguments = 1
5
6 def run(self) -> list[nodes.Node]:
7 paragraph_node = nodes.paragraph(text=f'hello {self.arguments[0]}!')
8 return [paragraph_node]
这个类扩展了 SphinxDirective
课该类包含 run
方法,这是每个指令的要求。它包含指令的主要逻辑,并返回要由Sphinx处理的块级docutils节点列表。它还包含一个 required_arguments
属性,它告诉Sphinx该指令需要多少个参数。
什么是docutils节点?¶
当Sphinx解析文档时,它会创建一个由节点组成的“抽象语法树”(AST),这些节点以结构化方式表示文档的内容,通常独立于任何一种输入(rST、MyST等)或输出(HTML、LaTeX等)格式。它是一棵树,因为每个节点都可以有子节点,等等:
<document>
<paragraph>
<text>
Hello world!
的 docutils 套件提供了许多 built-in nodes ,以表示不同类型的内容,例如文本、段落、参考文献、表格等。
每个节点类型通常只接受一组特定的直接子节点,例如 document
节点应仅包含“块级”节点,例如 paragraph
, section
, table
等,而 paragraph
节点应仅包含“内联级”节点,例如 text
, emphasis
, strong
等。
参见
docutils文档 creating directives ,而且 creating roles .
的 setup
功能¶
该功能是必需的。我们使用它将我们的新指令插入Sphinx。
def setup(app: Sphinx) -> ExtensionMetadata:
app.add_role('hello', HelloRole())
app.add_directive('hello', HelloDirective)
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
您能做的最简单的事情就是调用 Sphinx.add_role()
和 Sphinx.add_directive()
方法,这就是我们在这里所做的。对于这个特定的调用,第一个参数是reStructuredtext文件中使用的角色/指令本身的名称。在这种情况下,我们将使用 hello
.例如:
Some intro text here...
.. hello:: world
Some text with a :hello:`world` role.
我们还返回 extension metadata 这表明了我们扩展的版本,以及使用该扩展进行并行读写是安全的事实。
使用扩展¶
延期必须在您的 conf.py
文件以使Sphinx意识到它。这里需要两个步骤:
添加
_ext
目录到 Python path 使用sys.path.append
.这应该放在文件的顶部。更新或创建
extensions
列表并将扩展文件名添加到列表中
例如:
import sys
from pathlib import Path
sys.path.append(str(Path('_ext').resolve()))
extensions = ['helloworld']
小技巧
因为我们还没有将扩展安装为 Python package ,我们需要修改 Python path 这样Sphinx就可以找到我们的扩展。这就是为什么我们需要呼吁 sys.path.append
.
现在您可以在文件中使用扩展名。例如:
Some intro text here...
.. hello:: world
Some text with a :hello:`world` role.
上面的示例将生成:
Some intro text here...
Hello world!
Some text with a hello world! role.
进一步阅读¶
这是创建新角色和指令的扩展的基本原则。
有关更高级的示例,请参阅 扩展构建过程 .
如果您希望跨多个项目或与其他人共享您的扩展,请查看 第三方扩展 科.