前フリ

Pythonにはpydocというモジュールがあって、これを使うと同じようにAPIリストが出力できると思っていた。今までDjangoのコードを書いてみて、いわゆるヘッダーコメントとかドキュメンテーションコメントと言われているものをなんとなくjavadocライクに書いていたが、pydocだとあんまり期待した通りのHTMLを出力してくれないことが分かった。

自分が期待していたのは、

  • @タグでクラス、関数属性に関する情報を出力
  • phpDocumentorのように、テンプレートを変更可能

というものだったが、あんまりよろしくなかった。調べてみると、epydocというツールで実現できそうだったが、テンプレートはないらしい。もうちょっと調べてみると、Sphinxというドキュメンテーションツールがあるそうだ。すでに、以前のエントリーでちょっとした使い方について書いたが、インストール方法とかを書いてなかったので、ここにまとめておく。何かを作り始める時には、

  • テスト
  • ロギング
  • ドキュメンテーション
  • 国際化・地域化

をどうするか、最初に考えておくのはすごく大事だと思った。

Sphinxについて

すでにかなり有名なツールだそうなので、渋日記 Sphinxのドキュメントの日本語訳しましたにまとまってます。ブログでsphinxを検索すると、sphinx関連のエントリーがずらっと並びます。すげぇっす。特徴的なのは、reST(reStructeredText)形式でxxx.rstファイルを構築していくという点。pythonでドキュメンテーションコメントを書く場合は、docstringに書くことになっていると思うが、Sphinxではautodocという機能拡張を使って、半自動的にdocstringを取得して、rstファイルを生成してくれる。「半自動的」と書いたのは、どのモジュールのdocstringを出力するかを設定しなければ出力されないから。docstringを書いたからといって、それがそのまま出力されるわけではないので、この点は注意が必要。

使い方

以下、Windows 7での作業方法。きっとLinuxでもあまり変わらないはず。

easy_installでインストール

SphinxはPyPIで公開されているので、easy_installでインストール可能。

easy_install Sphinx

WindowsだとPYTHON_ROOT/Scriptsに必要なコマンドがインストールされるので、ここにパスが通ってなかったら適宜設定する。

初期設定

ドキュメントを出力する前にsphinx-quickstartというコマンドで初期設定する必要がある。Djangoではプロジェクトルートのディレクトリで、実行する。

sphinx-quickstart

このコマンドを実行すると、いくつか質問されるので、これに答えていく。

Welcome to the Sphinx 1.0.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 [.]:
ドキュメントのルートパスを指定。Djangoの場合はプロジェクトルートと同じにしたいので、"."のまま。
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]:
sourceディレクトリとbuildディレクトリを分けるかどうか。なんとなくnにした。
Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.
> Name prefix for templates and static dir [_]:
テンプレートディレクトリとstaticファイルディレクトリのprefix。デフォルトのまま"_"にした。
The project name will occur in several places in the built documentation.
* Please enter some text.
> Project name: test
> Author name(s):
自分の名前とかメンバーの名前。
Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1. If you don't need this dual structure,
just set both to the same value.
> Project version: 1.0
プロジェクトのバージョン。
> Project release [1.0]: 1.0
リリースバージョン。
バージョン変更は、このコマンドが終了したときに作成されるconf.pyに設定されている値を変更すればいいはず。
The file name suffix for source files. Commonly, this is either ".txt"
or ".rst". Only files with this suffix are considered documents.
> Source file suffix [.rst]:
reSTファイルのsuffix。デフォルトのまま.rstにした。
One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.
> Name of your master document (without suffix) [index]:
ドキュメントのルートツリーとなるマスターファイルのファイル名。デフォルトのままindex(index.rst)にした。
Sphinx can also add configuration for epub output:
> Do you want to use the epub builder (y/N) [n]:
epubビルダーを使うかどうか。使わないので、デフォルトのままnにした。
Please indicate if you want to use one of the following Sphinx extensions:
> autodoc: automatically insert docstrings from modules (y/N) [n]:
autodocを使用して、docstringからドキュメントを出力するかどうか。これがやりたいので、Yにした。
> doctest: automatically test code snippets in doctest blocks (y/N) [n]:
doctestを使用するかもしれないので、Yにした。
> intersphinx: link between Sphinx documentation of different projects (y/N) [n]:
別プロジェクトに対し、Sphinxドキュメント間でリンクを張るかどうか。使うかもしれないので、Yにした。
> todo: write "todo" entries that can be shown or hidden on build (y/N) [n]:
//TODO: みたいにtodoをドキュメントに出力するかどうか。とりあえずYで。
> coverage: checks for documentation coverage (y/N) [n]:
ドキュメントのカバレッジをチェックするかどうか。とりあえずYで。
> pngmath: include math, rendered as PNG images (y/N) [n]:
> jsmath: include math, rendered in the browser by JSMath (y/N) [n]:
mathモジュールを読み込んで、出力するかどうか。使わないと思うので、nで、
> ifconfig: conditional inclusion of content based on config values (y/N) [n]:
ドキュメント出力制御のために条件文(ifconfig)を使うかどうか。nにした気がする。
> viewcode: include links to the source code of documented Python objects (y/N)[n]:
ソースコードへのリンクを出力するかどうか。便利そうなので、Yで。
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]:
Makefileとバッチファイルを作成するかどうか。どちらもYで。
Finished: An initial directory structure has been created.
You should now populate your master file .\index.rst and create other documentation
source files. Use the Makefile to build the docs, like so:
make builder
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.

これが終わると、いくつかのファイルとディレクトリが作成される。

conf.py : Sphinx用の設定ファイル。
index.rst : マスターファイル。
make.bat : make用バッチファイル。
Makefile : make。
_build : ビルドディレクトリ。
_static : staticリソース用ディレクトリ。
_templates : templateファイル用ディレクトリ。

ビルド方法

sphinx-buildというコマンドを実行すると、htmlファイルが作成される。

sphinx-build -a -b html . .\doc

aオプションを付けると、生成済みかどうかに関わらず、強制的にドキュメントを生成することができる。bオプションは出力方法を指定するためのオプション。ビルダーの指定、なのでbオプション。他にもpdfとかlatexなんかがあった気がするが、とりあえず使わないので、htmlで。第一引数はドキュメント化の対象となるディレクトリを指定する。第二引数は作成したドキュメントの出力先ディレクトリを指定する。このコマンドを実行すると、

.doctree
doc

というディレクトリが作成され、docディレクトリの中に作成されたドキュメントが出力されている。

autodoc

ドキュメントを作成していくには、rstファイルに出力するドキュメントを書いていくことになるが、Django、というかpythonの場合はdocstringにドキュメントを書いていくので、autodocという拡張機能を使って、出力することになる。

rstファイルの中に、automoduleというディレクティブを書くと、指定したモジュールのdocstringを読み込むようになる。

.. automodule:: module_name

config.pyに設定すること

automoduleで指定する際には、いくつかのロールを設定しておく必要がある。基本的には必要なものはデフォルトで設定しておいて、設定されたくないロールがあるモジュールがある場合には、そのロールを外す、という方針とすると、rstファイルに書く内容が減る。

config.py
# -- General configuration -----------------------------------------------------
keep_warnings = True
autodoc_default_flags = ['members', 'undoc-members', 'show-inheritance']

keep_warningsは、Sphinxの警告をドキュメントに出力するかどうか。メンテナンスの観点から、Trueにしておいた方がいいと思う。

autodocdefaultflagsに指定しているのは次の通り。

  • members : 自動的にメンバーの関数やプロパティのドキュメントも取り込む
  • undoc-members : docstringの付いていないメンバーも取り込む
  • show-inheritance : クラスのシグニチャの直前に、継承しているベースクラスのリストを表示

phpDocumentorみたいに継承しているクラス・メソッドの一覧をまとめて出力してくれると便利なんだけど、これはどうするんだろう。

todolist

ソース中に書いてあるtodoを一か所に出力するtodolistというディレクティブもある。これを使うと、todoの内容と、どこに書いてあるtodoか、という情報が出力されるようになる。

.. todolist::

ドキュメンテーションコメントの書き方

docstringの書き方はjavadocだと@タグを使って書いていくが、Sphinxでは:field:というフィールドを使って書いていくことになる。pythonで使用できるフィールドは詳細情報フィールドのリストに載っている。

例えば、functionやmethodの場合、

def hello(msg):
"""
こんにちわ。
:param string msg: 出力するメッセージ
"""
print msg
def add(a, b):
"""
足し算ぐらいできます。
:param int a: 足される値。
:param int b: 足す値。
:rtype: int
:return: 足し算した数値。
:todo: sample.py/def add - 例外出たときどうするんだろ。誰か直しといて。
"""
return a + b

というように書く。

自動化

sphinx-buildでドキュメント生成できるなら、バッチファイルなり、シェルスクリプトに書いておいて、ApacheのDocumentRootに出力できると便利。gitにコミットした時点で自動的に実行するなら、hook?フォルダに入れておけばいいのかな。この辺は要調査。

出力対象が増えた時点で、rstファイルのメンテナンスが発生するので、そこはめんどくささとのトレードオフだと思うが、これだけいいものが使えるなら、それは許容すべきだと思う。こういった便利ツールがあるのとないのだと、継続的な開発はきびしいのかも。というより、2人以上が関わるようなシステムであれば、ドキュメントは作られるべき。

設計ツールとしてのSphinx:シーケンス図も書けます

疑似コードからシーケンス図を出力する拡張機能もあるみたいだし、こりゃぁ便利。ドキュメントも日本語化されてます。ありがたや。

ちょっとしたバグ

ブラウザによっては、クイック検索用のテキストボックスの長さがうまく設定されない。具体的にはinputタグのsize属性がうまく解釈されないらしい。cssにもwidthが設定されていないので、input textがはみ出す。cssを直せば済む話なので、気になる人は設定しておくといいかもしれない。

参考資料