Sphinxのドキュメントビルド時に、特定の拡張をスキップしたかった


前提

自分は自作のsphinx-revealjsをもとに、SphinxでReveal.jsのスライドを書いている人です。

Sphinxで拡張を使うまで

Sphinx + Revealjsの組み合わせでスライドのソースを書いてると、こういうシーンがあります。

presentation.rst
Ansibleの動き(中身)
-------------------

.. 60sec

.. todo:: 上記デモのPlaybook

インベントリファイル

* 処理実行先のサーバー一覧や簡単な情報を定義

ここで使われるtodoディレクティブは、Sphinx内でtodoをとして表示できるようにするもので、
「この後書くこと」や「書いておきたかったこと」などをメモるするのに便利です。

で、ビルトインの拡張でないため、sphinxでのビルド時に用いるconf.pyには拡張として指定してあげる必要があるのですが、、、

conf.py
extensions = [
    'sphinx.ext.todo',
    'sphinx_revealjs',
]

カスタムのビルダーでビルドすると、失敗してしまう

実行すると、このようなエラーが出てビルドに失敗してしまいます。

$ pipenv run make revealjs
例外が発生しました
  File "/home/attakei/.local/share/virtualenvs/slides-P9x2JL-m/lib/python3.7/site-packages/sphinx/writers/html5.py", line 885, in unknown_visit
    raise NotImplementedError('Unknown node: ' + node.__class__.__name__)
NotImplementedError: Unknown node: todo_node

はて、きちんとSphinx拡張が登録されているはずなのにこんなエラーが出てしまう。
ビルダーをhtmlに設定したみると正常にビルドが完了するらしい。ということは、自作の方のrevealjsビルダーに原因がありそう

エラーを追跡...はまた今度

※そのうち、自分のライブラリを直します

conf.pyの側から拡張の呼出を分割する

ライブラリ修正は色々大変な匂いがするので、ひとまずconf.pyを弄って

「ビルダーにrevealjsを指定した場合は、sphinx.ext.todoを拡張に登録しない」

をゴールにします。

conf.py
extensions = [
    'sphinx_revealjs',
]

if is_not_builder_revealjs:
    extensions += [
       'sphinx.ext.todo',
    ]

こんな感じ

conf.pyの時点でビルダーを雑に確定する(限定条件下

Sphinxはmakeベースでのビルドを推奨しているのですが、

%: Makefile
    @$(SPHINXBUILD) -b $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

こんなふうに、sphinx-buildコマンドを通すようになっています。
そして、ありがたいことにコマンドのもとであるsphinx.cmd.buildモジュールは、引数パーサーを関数で別途生成した上でコマンドライン上で使うようです。

ざっくり見る感じ、そのまま活かせそうなので、conf.pyに突っ込んでみます。

conf.py
import sys
from sphinx.cmd.build import get_parser


sphinx_args = get_parser().parse_args(sys.argv[1:])

extensions = [
    'sphinx_revealjs',
]

if sphinx_args.builder != 'revealjs':
    extensions += [
        'sphinx.ext.todo',
    ]

こうなりました。ビルドすると、、、

$ pipenv run make revealjs



静的ファイルをコピー中... ... 完了
copying extra files... 完了
dumping search index in Japanese (code: ja)... 完了
dumping object inventory... 完了
build 成功, 3 warnings.

無事成功しました