54
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Sphinxのドキュメント作成を便利にする「sphinx-quickstart-plus」を作りました

Last updated at Posted at 2017-02-19

前記事:Sphinxを便利にして、みんなに使ってもらいたい

Sphinxは非常に便利なのですが、ドキュメント作成の手順が非常に煩雑でした。
そこで、Sphinxを拡張するモジュール「sphinx-quickstart-plus」を作りました。

インストール方法

pipで簡単にインストールできます。
Sphinxモジュールに依存していますので、あらかじめSphinxをインストールしておいてください。

$ pip install sphinx-quickstart-plus

使い方

今まで、ドキュメント作成はsphinx-quickstartと打っていましたが、sphinx-quickstart-plusと打つだけです。

$ sphinx-quickstart-plus

すると、以下のようなメッセージが流れてきます。

出力
Welcome to the Sphinx 1.5.1 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Enter the root path for documentation.
> Root path for the documentation [.]: document_path

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: y

...

今までのsphinx-quickstartと全く同じ出力が出ます。
「何も変わってねーじゃん」と思われるかもしれませんが、もう少しお付き合いください。

出力
...
A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.
> Create Makefile? (y/n) [y]: 
> Create Windows command file? (y/n) [y]: 

> ext_commonmark:use CommonMark and AutoStructify (y/n) [n]: y
> ext_nbshpinx:provides a source parser for *.ipynb files (y/n) [n]: y
> ext_blockdiag:Sphinx extension for embedding blockdiag diagrams (y/n) [n]: y
> ext_fontawesome:use font awesome (y/n) [n]: y
> ext_rtd_theme:use Read the Doc theme (y/n) [n]: y
> ext_autobuild:autobuild: Watch a directory and rebuild the documentation (y/n) [n]: y

最後にsphinx-quickstartになかった設問が出てきます。
今現在の拡張と説明は以下のとおりです。

拡張名 説明
ext_commonmark .rstだけでなく.md(CommonMark)が使えるようになります
ext_nbshpinx Jupyter Notebookが取り込めるようになります
ext_blockdiag ブロック図が書けるようになります
ext_fontawesome Font AwesomeがreSTから使えるようになります
ext_rtd_theme Read the Docsのテーマを使えるようになります
ext_autobuild オートビルドが使えるようになります

これらのSphinx拡張がconf.pyを編集することなく使えるようになります。

それだけではありません、ふたたびsphinx-quickstart-plusを起動すると、冒頭の設問が変わります。

出力
> Use latest setting? (y/n) [y]: y

'y'とタイプすると、PathProject nameAuthorVersionReleaseの5項目を答えるだけで、前回のドキュメントと同じ設定のドキュメントが作成されます。
前回のsphinx-quickstart-plusで作成したドキュメント設定を記憶しています。

ちなみに'n'とタイプした場合は、通常のsphinx-quickstartの設問が流れますが、デフォルト設定が最後の設定になっていますので、変更箇所以外はEnterキーの連打でよいので楽ちんです。

$ sphinx-quickstart-plus

> Use latest setting? (y/n) [y]: n

...

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [y]: <-デフォルトが最後の入力になってる

各拡張選択時にconf.pyに追加されるコード

ext_commonmark

conf.py
# ----- CommonMark
source_suffix = [source_suffix, '.md']

from recommonmark.parser import CommonMarkParser
source_parsers = {
    '.md': CommonMarkParser,
}

from recommonmark.transform import AutoStructify

github_doc_root = 'https://github.com/rtfd/recommonmark/tree/master/doc/'
def setup(app):
    app.add_config_value('recommonmark_config', {
            'url_resolver': lambda url: github_doc_root + url,
            'auto_toc_tree_section': 'Contents',
            }, True)
    app.add_transform(AutoStructify)

ext_nbshpinx

conf.py
# ----- Jupyter Notebook nbsphinx
extensions.append('nbsphinx')
exclude_patterns.append('**.ipynb_checkpoints')

ext_blockdiag

conf.py
# ----- blockdiag settings
extensions.extend([
    'sphinxcontrib.blockdiag',
    'sphinxcontrib.seqdiag',
    'sphinxcontrib.actdiag',
    'sphinxcontrib.nwdiag',
    'sphinxcontrib.rackdiag',
    'sphinxcontrib.packetdiag',
])
blockdiag_html_image_format = 'SVG'
seqdiag_html_image_format = 'SVG'
actdiag_html_image_format = 'SVG'
nwdiag_html_image_format = 'SVG'
rackiag_html_image_format = 'SVG'
packetdiag_html_image_format = 'SVG'

ext_fontawesome

conf.py
# ----- sphinx-fontawesome
import sphinx_fontawesome
extensions.append('sphinx_fontawesome')

ext_rtd_theme

conf.py
# ----- Read the Docs Theme
html_theme = "sphinx_rtd_theme"

ext_autobuild

auto_buildはconf.pyを書き換えませんが、Makefileを書き換えます。

$ make livehtml

と打つと、オートビルドが始まります。
Windowsの人はauto_build.batが生成されるので、それを実行してください。

$ auto_build.bat

PyCharmなどの.mdを編集していると一時ファイルが作成されてしまい、それもビルドしてしまうので、いくつかの一時ファイルをビルド無視する設定も含まれています。

ライセンスについて

「sphinx-quickstart-plus」はライセンスフリーです、ご自由にお使いください。
なお、このモジュールを使っていかなる不利益が生じても責任は負いませんので、ご理解ください。

また、私の環境はUbuntuなのでWindowsとMacの環境ではテストできていません。
バグなどはあるかと思います。
問題がありましたら、GitHubのイシューかコメント欄におねがいします。

コード解説

このモジュール本体はコメントを合わせて400行もない小さなモジュールです、作成期間も6時間程度で殆どがデバッグ作業です。
ですが、sphinx-quickstartの豊富な引数や機能をフルサポートしています。

どうしてこんな事ができるかというと、モンキーパッチという技術を使っているからです。

モンキーパッチとは?

モンキーパッチとは既存のライブラリの動作を乗っ取って、動的に書き換えてしまうパッチです。
これは動的言語の特性を活かした離れ業であり、コンパイル言語では真似できない手法です。1

補足
モンキーパッチは既存のライブラリのファイルを書き換えるものではありません。
あくまで既存ライブラリのファイルを変更することなく、動的に動作を変える手法です。
sphinx-quickstart-plusをインストールしても、元となるSphinxライブラリの動作は一切変わりません。

参考

モンキーパッチ Wikipedia

sphinx-quickstartsphinx.quickstart.pyというモジュールに処理が書かれています。
ですので、普通にsphinx.quickstartをインポートしますが、ask_user関数はモンキーパッチで書き換えてしまいますので、オリジナル処理の関数ポインタを忘れないよう、別途にfrom .. import ask_userでインポートしています。

from sphinx import quickstart
from sphinx.quickstart import ask_user, generate, do_prompt, nonempty, boolean

quickstart.ask_user関数をmonkey_patch_ask_user関数で上書きして乗っ取ります。

    # monkey patch
    quickstart.ask_user = monkey_patch_ask_user

monkey_patch_ask_user関数で独自の処理を行った後、オリジナルのquickstart.ask_user関数を呼び出しています。

def monkey_patch_ask_user(d):
    ... 独自処理

    # オリジナルの ask_user呼び出し
    ask_user(d)

    ... 独自処理

他にも色んな関数をモンキーパッチで乗っ取っているのですが、基本的にやっている事は一緒です。

最後にquickstart.mainを呼びます。

    quickstart.main(argv)

sphinx-quickstart-plusを更に拡張する

Did you want to further expand ‘sphinx-quickstart-plus’? Editing ‘sphinx-quickstart-plus’ source code for extension is not cool.
('sphinx-quickstart-plus'を更に拡張したくなった?拡張のために'sphinx-quickstart-plus'のコードを編集するなんて無粋なことしないでくれよ)

Let’s monkey patch!
(モンキーパッチしようぜ!)

Below is an example of a simple extension.
(下のコードはシンプルな拡張の例)

from sphinx_qsp import quickstart_plus

# Setting your extension.
your_extension = quickstart_plus.Extension(
    "ext_your_ext", "your extensions description.",
    conf_py="""

# ----Your Extension
import your_extension_package
extension.append("your-extension_name")
)
""",
    package=["your_extension_packge"]
)

# Add your extension.
quickstart_plus.qsp_extensions.extend([
    your_extension
])

# Run sphinx-quickstart-plus.
quickstart_plus.main()

The base class of extension is the following code.
(拡張に使う基底クラスのコードは以下の通り)

class Extension(object):
    def __init__(self, key, description, conf_py=None, new_makefile=None,
                 makefile=None, package=None):
        self.key = key
        self.description = description
        self.conf_py = conf_py
        self.new_makefile = new_makefile
        self.makefile = makefile
        self.package = package or []

    # noinspection PyUnusedLocal
    def extend_conf_py(self, d):
        return self.conf_py

    def extend_makefile(self, d, make_mode):
        return self.new_makefile if make_mode else self.makefile

The extended class of ‘sphinx-autobuild’ is the following code.
(‘sphinx-autobuild’の拡張クラスは以下のようになる)

class AutoBuildExtension(Extension):
    def extend_makefile(self, d, make_mode):
        if d['batchfile']:
            batchfile_path = os.path.join(d['path'], 'auto_build.bat')
            source_dir = d['sep'] and 'source' or '.'
            build_dir = d['sep'] and 'build' or d['dot'] + 'build'

            open(batchfile_path, "w").write(
                AUTO_BUILD_BATCH.format(
                    build_dir=build_dir, source_dir=source_dir,
                    AUTOBUILD_IGNORE=" ".join(AUTOBUILD_IGNORE),
                )
            )

        makefile = self.new_makefile if make_mode else self.makefile
        return makefile.format(" ".join(AUTOBUILD_IGNORE))

あとがき

個人的にいくつかのドキュメントを作成しましたが、めっちゃ便利です。

  1. http://postd.cc/monkey-patching-in-go/ でコンパイル言語のモンキーパッチしてました、アセンブラを使うかなりな黒魔術ですね

54
49
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?