ドキュメンテーション文字列　再考

この記事はMaya-Pythonアドベントカレンダー12月11日の記事です。

# はじめに

Pythonの機能の一つに[documentation strings](https://www.python.org/dev/peps/pep-0008/#documentation-strings)というものがあります。

モジュール・クラス・関数などに下記のように文字列を記述することでドキュメントとして解釈されます。

```py:
def sayhello():
    u"""こんにちわと元気に挨拶する。"""
    sys.stdout.write(u"こんにちわ！")
```

helpメソッドに渡すと整形して出力してくれるので、関数の使い方を調べるのに使用します。

```
>>> help(sayhello)
Help on function sayhello in module __main__:

sayhello()
    こんにちわと元気に挨拶する
```

標準モジュールも当然記述されています。

```
>>> import os
>>> help(os.path.abspath)
Help on function abspath in module ntpath:

abspath(path)
    Return the absolute version of a path.
```

# 検証環境

Windows10
Python 2.7.12
PyCharm 2016.3
Sphinx 1.5
Maya 2016 Extension2


# 弊社で抱えている問題

弊社では多数のモジュール・メソッド・クラスを共有ライブラリとして管理しています。現時点でも全てを記憶しておくことは不可能な数のファンクション数になっています。
このうちmayaパッケージはmaya組み込みPythonでしか動作しません。その他にも組み込みPython依存のパッケージもありますが、今回はmayaに限定して話を進めます。

```
stu/
  __init__.py
  maya/
    __init__.py
    skin.py
    他多数・・・
  path.py
  pyside.py
  他多数・・・
```

* 共有ライブラリの利用を促進する
* 車輪の再開発を避ける

上記2点の理由から、欲しい機能で簡単に検索出来て、メソッドの引数の仕様についても視認性の高いシステムが求められています。

テストコードも作成しているのでテストコードを見れば大体の使い方はわかるのですが、当然のことながらどのような経緯で現在の仕様になっているのかはわかりませんし、そもそもテストコードが不十分なことが多いです。

そこで「きちんとdocstringに注意書きとか残しておこうよ」という話になるのですが、私自身あまり積極的には書いていません。

人間が行動には動機が必要なのです。

ではどうやって動機付けしてやろうか。ということでdocstringを見つめ直してみたいと思います。


# メンテナンスしない問題

PEP8でも触れられているように、コードとコメントが一致しないのは最悪です。どちらが正しいのか分かりません。メンテナンスしないコメントなど書かないほうがマシでしょう。

などという言い訳ばかりして書かないのは何故か？単純に自分に対して恩恵が無いからではないでしょうか。

Pythonは日々進化しています。
Python3.5からはType Hints（[PEP484](https://www.python.org/dev/peps/pep-0484/)）という変数の型を定義する機能が追加されています。引数および返り値の型を定義しておくことが可能になり、エディタがサポートすれば返ってきた変数のメソッドを候補として表示することができます。
PyCharmでは[Type Hinting](https://www.jetbrains.com/help/pycharm/2016.3/type-hinting-in-pycharm.html)機能として、Python3.5のType Hintsと、docstringsに記述する方法をサポートしているようです。

これはdocstringをメンテナンスする動機になりそうです。

では、以下の検証を行い、docstringを便利に使いながらHTMLのドキュメントを手に入れたいと思います。

1. PyCharmのType Hinting
1. SphinxでドキュメントをHTML化して検索


# Type Hintingを検証

Type HintsはPython 3.5で導入されたそうなので、一部コメントでの表現方法はあるそうですが、Python2では使用できないので思い切って却下です。

まずは、いつものように、Project Interpreterがmayapyになっていることを確認。これを怠るとpymelの型などを定義しても機能しません。
![2016-12-10_20h47_50.png](https://qiita-image-store.s3.amazonaws.com/0/13183/f02f0934-e057-9cd7-4843-319d049ed9bb.png)



関数の返り値を定義してみます。```rtype```でSkinClusterを指定してみます。
で、試しに関数呼んで変数に格納します。

![2016-12-10_20h45_53.png](https://qiita-image-store.s3.amazonaws.com/0/13183/f2f28cd0-564c-9e0b-e6ae-ff86a91bd06b.png)

その変数からメソッドをタイプすると・・・SkinClusterオブジェクトのメソッドが候補に上がります。もちろん親クラスのメソッドも。素晴らしい・・・

![2016-12-10_20h45_24.png](https://qiita-image-store.s3.amazonaws.com/0/13183/ff9cb69f-5aaf-9028-7b91-9d9caee0109b.png)

これであっさりとrtypeを書かない理由がなくなりました。

# Sphinxを検証

PythonにはソースコードからHTMLドキュメントを自動生成する仕組みはいくつかありますが、最近はPython以外のプログラム言語のサポートにも力が入っている[Sphinx](http://www.sphinx-doc.org/en/1.5/)が最も一般的と言えるでしょう。Python自体の公式ドキュメントもSphinxです。というかそのために開発されたそうです。

Sphinxでドキュメントの自動生成して、docstringに書いた情報を検索できるようにします。

とりあえずpipでsphinxをインストール。

```
"C:\Program Files\Autodesk\Maya2016\bin\mayapy.exe" -m pip install sphinx --user
```

PyCharmでもSphinxが使えるようになっているので、ドキュメントディレクトリを指定します。今回はC:\sample\sphinxとします。

![2016-12-11_00h05_54.png](https://qiita-image-store.s3.amazonaws.com/0/13183/30d6080d-6b47-e6b0-faf4-98d65f094dc3.png)

Sphinx Quickstartを実行してインタラクティブに設定ファイルを作成します。基本的に言語をjaにしたくらいで後はデフォルトでOK。（説明が雑ですいません）

![2016-12-11_00h06_52.png](https://qiita-image-store.s3.amazonaws.com/0/13183/fd78d09d-67e9-e2b5-8bbf-81f7ed7707ea.png)

これだけだとdocstringsは無関係でreStructuredTextフォーマットのテキストファイル（.rst）からhtmlを作成するだけなので、[sphinx-apidoc](http://www.sphinx-doc.org/ja/stable/invocation.html#invocation-of-sphinx-apidoc)という機能を別途使ってソースコードからAPIドキュメントを生成する.rstファイルを生成します。
コマンドラインでの実行になります。

```
%USERPROFILE%\AppData\Roaming\Python\Scripts\sphinx-apidoc.exe ライブラリのパス -o C:\sample\sphinx
```

これで準備完了。続いてドキュメント生成の実行です。
PyCharmに戻って、Run/Debug Configurationsから新規Configを作ります。Python docs/Sphinx taskというのがちゃんと用意されてますね・・・inputとoutputを指定して完了です。Interpreterはmayapyになっていると思いますが、Sphinxはドキュメント化するモジュールをインポートしてdocstringsを取得するので、通常のPythonではインポートエラーが起こるためドキュメント化も失敗しますのでご注意ください。

![2016-12-11_00h06_15.png](https://qiita-image-store.s3.amazonaws.com/0/13183/4fb557f0-86d9-53f8-b677-f7a2a2df39ec.png)

で、いつものようにRun。C:\sample\sphinx\\_build\index.html（その他多数）が生成されるはずです。

![2016-12-11_00h41_30.png](https://qiita-image-store.s3.amazonaws.com/0/13183/1f41c456-8459-a6ec-dfdd-554a3a292514.png)


index.htmlを開きます。デフォルト状態だとそっけないhtmlが生成されますが、とりあえず検索してみましょう。

![2016-12-11_00h23_00.png](https://qiita-image-store.s3.amazonaws.com/0/13183/04ccd36e-a6c6-2447-3947-ca9f6cee5d9f.png)

お、結果出た。（１つはゴミです）

![2016-12-11_00h23_12.png](https://qiita-image-store.s3.amazonaws.com/0/13183/42441d57-03b3-f166-46c8-baed8a7b8b66.png)

おおお！きちんとdocstringに記述した返り値の型が記述されています。

![2016-12-11_00h23_31.png](https://qiita-image-store.s3.amazonaws.com/0/13183/e3037f27-5369-3ca5-73ca-dd99799a1afe.png)


# まとめ

docstringsは多くのノウハウがウェブから得られました。マークアップのフォーマットはいくつか候補があるようですが、とりあえずはPython標準マークアップであるreStructuredTextで書いておくことにします。
Qiitaで書いているこの文章もそうですが、世間的にはマークアップ言語はmarkdownが事実上の標準かな？・・・と思わなくもないので少し不安もありますが、そもそもそんなに複雑な構成のドキュメントが目的ではないので結論を急ぐ必要はありません。またの機会に考えてみることにします。

Sphinxはコマンドラインで実行するにはちょっと敷居が高いと感じますが、PyCharm上で実行することで面倒な部分はほとんど隠ぺいしてくれます。
実はものすごく試行錯誤を繰り返したので、結果PyCharmを使えばアッサリした手順になってしまうのが少し悔しい。

結局またもやPyCharm最高という結果になってしまった。


# 参考

[PyCharm での type hinting を使いこなす](http://qiita.com/methane/items/e95c578c3d8fc5f1f62e)
[PyCharm (IntelliJ) で Sphinx で楽にドキュメントを書く](http://qiita.com/kojionilk/items/1de43c49b8007e3780ce)