sphinx拡張開発メモ ( #sphinxjp アドベントカレンダー 13.1日目)


前回の記事では私が作成した sphinx 拡張、sphinxcontrib-recentpages の紹介をしました。

この記事では sphinx 拡張の開発をしたときに気づいたことなどのメモを紹介します。

私は sphinx 拡張の開発は初心者ですので、間違いがあるかもしれません。間違いを発見した場合はご連絡いただけると助かります。

チュートリアル


まずはチュートリアルをやること。
http://sphinx-users.jp/doc11/ext/tutorial.html

基本

まず def setup(app): という関数を作る。

ノード

  • app.add_node(<ノード名>) で登録。
  • このノードは新しいクラスとして、docutils.nodes.<ノード> クラスを必要なだけ継承する。
class recentpages(nodes.General, nodes.Element):
    pass
  • add_nodes() に追加で引数を渡すことができる。
    • html = () と指定すると、html のビルド時にそのノードを訪れる(あるいは立ち去る)際の挙動を決めることができる。

ディレクティブ

  • app.add_directive(<ディレクティブ名>, <対応クラス>) でディレクティブを登録。
  • ディレクティブクラスは sphinx.util.compat.Directive を継承する必要がある。
class RecentpagesDirective(Directive):
  • ディレクティブ作成には run(self) というメソッドを作る必要がある。
    • この関数はディレクトリが見つかるたびに呼ばれる。
    • 返り値はノードのリストになる。
  • ディレクティブに引数を持たせたい場合は以下のように設定する。
    has_content = True
    option_spec = {
        'num': int
    }

  • こうしておけば、ユーザは以下のような形でオプション引数を渡せる。

.. recentpages::
:num: 3

  • run() メソッド内で以下のようにして取得できる。
    • 以下の例ではデフォルトを -1 にしている。
        num = self.options.get('num', -1)
  • ノードは dict 形式なので、情報を渡したい場合は dict に値を追加するのと同じ感覚で大丈夫。
        res = recentpages('')
        res['num'] = num
Directive の中身
  • directive.state
    • ディレクティブについての状態を扱うオブジェクト。
  • directive.state_machine
    • ディレクティブについての状態を扱うオブジェクト。
  • directive.state.document
    • そのディレクティブが属するドキュメントについてのオブジェクト。
  • directive.state.document.current_source
    • ドキュメントへのフルパス。
  • directive.state.document.settings.env
    • Sphinx の環境オブジェクトはここからアクセス可能。
  • directive.state.document.settings.env.srcdir
    • ドキュメントのルートディレクトリ。


例えば、そのノードが属するページの pagename は以下のように生成可能。

pagename = current_source.replace(srcdir, '').lstrip('/').rpartition('.')[0]

環境情報

  • 現在の環境情報は directive.state.document.settings.env あるいは application.builder.env に入っている。
  • env() の使い方は sphinx.environment のソースコードを参照のこと。

ビジター関数

  • def <メソッド名>(self, node): で定義する。
  • node は現在のノード。ここで node['num'] とすれば、先ほどディレクティブクラス内で投入したデータを取り出せる。
  • env は self.builder.env で取り出せる。

conf.py

  • conf.py の設定は app.builder.config.<コンフィグ名> で取り出すことができる。
  • 例えば以下の例では、 recentpages_sidebar という設定の値を取り出すことが可能。
app.builder.config.recentpages_sidebar

tips

  • あるディレクティブが存在するページを常にビルドしたい場合は run() 内で self.state.document.settings.env.note_reread() を呼ぶことで可能。
  • Sphinx プロジェクトのルートパスは env.srcdir で取得可能。
  • builder は app.builder で取り出せる。
  • env は app.builder.env で取り出せる。
  • Sphinx プロジェクト内で発見された全てのソースファイルの一覧は env.found_docs で取得可能。
  • builder.get_relative_uri(pagename, docname) で、あるページから別のページへの相対 URI を生成できる。
  • あるドキュメントへのフルパスは env.doc2path(docname) で取り出せる。
  • ビルド時の warning は builder.warn(<メッセージ>) で出力可能。
  • あるドキュメント名の表示時のタイトルは env.titles[docname] で取得可能。