"Hello world" 拡張機能の開発

このチュートリアルの目的はとても基本的な拡張を作成することです。拡張では新たなディレクティブを追加し、そこで”hello world”を含んだパラグラフが出力されます。

基本的な情報だけを、このチュートリアルでは扱います。さらに情報が必要な場合は、 other tutorials を参照してください。こちらで細部が述べられています。

警告

この拡張については、docutils と Python の基礎知識が必要になります。

概要

以下のような拡張機能をSphinxに追加したいとします:

  • helloworld ディレクティブ, "hello world" というテキストを単に出力するもの.

前提条件

このプラグインを PyPI を通して配布せず、代わりに既存プロジェクトへ、その一部としてこのプラグインを加えることにしましょう。すなわち、みなさんは既存プロジェクトを使用するか、 sphinx-quickstart を利用して新しいものを作成する必要があります。

ソース (source) と ビルド (build) のフォルダーをみなさんが分けて使用していることを想定します。みなさんの拡張ファイルはプロジェクト内のどこかのフォルダに入っているかもしれません。ここでは、次のようにします:

  1. source 内に _ext フォルダーを作成します

  2. Create a new Python file in the _ext folder called helloworld.py

フォルダ構造として次のようなものが得られるでしょう:

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

拡張機能の書き方

Open helloworld.py and paste the following code in it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from docutils import nodes
from docutils.parsers.rst import Directive


class HelloWorld(Directive):

    def run(self):
        paragraph_node = nodes.paragraph(text='Hello World!')
        return [paragraph_node]


def setup(app):
    app.add_directive("helloworld", HelloWorld)

    return {
        'version': '0.1',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }

いくつかの本質的なことがこの例の中にはあり、すべてのディレクティブでそれらを確認することができます。

ディレクティブクラス

新しいディレクティブを`HelloWorld`` クラス内で宣言しています。

1
2
3
4
5
class HelloWorld(Directive):

    def run(self):
        paragraph_node = nodes.paragraph(text='Hello World!')
        return [paragraph_node]

このクラスは docutils' Directive クラスを拡張しています。ディレクティブを生成するすべての拡張機能は、このクラスを拡張すべきです。

このクラスには run メソッドが含まれています。このメソッドは必須であり、すべてのディレクティブに構成要素として存在します。メソッドには当該ディレクティブの主要ロジックが含まれていて、Sphinx によって処理された docutils ノードのリストを返します。 これらのノードはdocutils でのドキュメントコンテクストの表現法であらわされています。多くの利用可能ノードのタイプがあります。text、paragraph、 reference、 table などです。

The nodes.paragraph class creates a new paragraph node. A paragraph node typically contains some text that we can set during instantiation using the text parameter.

setup 関数

This function is a requirement. We use it to plug our new directive into Sphinx.

1
2
3
4
5
6
7
8
def setup(app):
    app.add_directive("helloworld", HelloWorld)

    return {
        'version': '0.1',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }

The simplest thing you can do it call the add_directive() method, which is what we've done here. For this particular call, the first argument is the name of the directive itself as used in a reST file. In this case, we would use helloworld. For example:

Some intro text here...

.. helloworld::

Some more text here...

We also return the extension metadata that indicates the version of our extension, along with the fact that it is safe to use the extension for both parallel reading and writing.

Using the extension

The extension has to be declared in your conf.py file to make Sphinx aware of it. There are two steps necessary here:

  1. Add the _ext directory to the Python path using sys.path.append. This should be placed at the top of the file.

  2. Update or create the extensions list and add the extension file name to the list

例:

import os
import sys

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

extensions = ['helloworld']

ちなみに

We're not distributing this extension as a Python package, we need to modify the Python path so Sphinx can find our extension. This is why we need the call to sys.path.append.

You can now use the extension in a file. For example:

Some intro text here...

.. helloworld::

Some more text here...

The sample above would generate:

Some intro text here...

Hello World!

Some more text here...

Further reading

This is the very basic principle of an extension that creates a new directive.

For a more advanced example, refer to "TODO" 拡張機能の開発.