Sphinxメンテナ日記: 2to3やめてsixに切り換えました¶
前置き: このエントリを読むと、既存のPython2実装の何かをPython3に移行する時の参考になるかもしれません。前置きおわり。
Sphinx-1.2のPython3対応¶
Sphinxはバージョン1.1からPython3対応していました。しかしSphinx-1.1と1.2はPython2で書かれていて、インストール時に 2to3 - Python 2 から 3 への自動コード変換 でコードを変換してPython3で動作させています。 しかし、2to3を使ったためにSphinxの機能以外のところでいくつかの問題が起きていました。
インストールに時間がかかる
インストール時に2to3が実行されますが、多くの変換を行うため、対象ソースのコード行数に比例して時間がかかります。 Sphinx-1.2.2をローカルのソースからインストールした場合:
Python2.7: 7 秒
Python3.3: 41 秒
Python3のテスト実行に時間がかかる
Sphinxはtoxでテストを行っていますが、テスト対象パッケージはテスト毎にvirtualenv環境に再インストールされるため、前述のインストール時間がテスト毎に2回(py32,py33)かかります。
Python3でのデバッグに手間がかかる
Python3でのみ発生するバグの修正やPython3の新しいバージョンで動作しない場合、2to3変換後のコードに対して修正を行い、そのように変換されるように2to3変換前のリポジトリのコードを修正する必要があります。 うまく書けたか確認するために2to3を何度も実行するため、前述の変換コストがかかります。
もちろん、2to3自体はPython2が主流だったこれまでは、Python3にも楽に対応したい場合の道具としてとても役立つ物でしたが、Python3.4もリリースされ Python3が一般的になってきた 現状では、開発やインストールに時間がかかる2to3は良い選択とは言えなくなりました。
Sphinx-1.3のPython3対応¶
Sphinx-1.3は現在開発中ですが、既に2to3を使わない実装に切り替えがほぼ終了しており、Sphinx-1.3からは2to3による変換なしでPython3で動作します。
Sphinxはどのようにして2to3から脱却したか¶
チケット #1350 でいくつかの方法を検討しました。
six を使う
python-future を使う
ピュアPythonコードで書く
これらのうち、Georgのコメントから、python-futureよりもsixを使う、出来ればsixも無しで実装する、という方針になり、最終的にはsixを使った実装を採用しました。 また、#1350のやりとりを通して、 Pygments もシングルソースでの実装に移行し、その結果、Pygments-2.0はPython-2.6, 2.7, Python-3.3+ で動作することになったようです (PygmentsのCHANGESより)。
ちなみに、python-futureは Comparing future.moves and six.moves の中で「six.movesの実装のためにDjangoのオートリロードや、py2exeやcx_freezeなどのツールで問題がある」という事を指摘しています。Sphinxもsixを採用したことにより、こういった問題に遭遇する可能性はあります。
Sphinxのシングルソース移行¶
移行は以下の3つのPull Requestで行われました(3つめは現在レビュー中です)。
Pull Request #208 python-futureの
futurize --stage1
によるexcept文やprint文の変換Pull Request #238 sixパッケージを採用し、Py2/3で移動したパッケージに対応、bytes/str/unicodeの調整、iterの調整
Pull Request #243 next()の調整、mapの調整、
ur""
リテラルの調整、2to3の削除
3つめの Pull Request #243 では、部分的に from __future__ import unicode_literals
を使っていますが、全体的には u""
リテラルを残してあります。
Sphinxで多く利用されている u""
リテラルを unicode_literals
で書き換えるのは多くの手間と気を遣う作業のため、やりませんでした。
しかし、 u""
リテラルが復活したPython-3.3以降でも ur""
リテラルは使用できないため、その部分についてだけunicode_literalsで対処してあります。
ところで、Python3.2では u""
リテラルが使用できません。このため、Sphinx-1.3もPython-3.2では動作しなくなる予定です。
なお、Sphinx-1.2が依存している Pygments (Georg作)と snowballstemmer (shibu作)もPython-3.2では動作しません。今後はPython-3.2対応はどんどん厳しくなっていきそうですね。
インストール時間の改善¶
Sphinx-1.3のソースからのインストール時間を計ってみました:
Python2.7: 6 秒
Python3.3: 6 秒
ところで最近のSphinxはwheelパッケージもリリースしているので、pip-1.5以降を使っていればwheelパッケージでインストールされるので、インストール時間はもっと短かったりします。 wheelがどのくらい速いかについては@aodagによる pipとwheelでテスト環境構築をスピードアップ が詳しいです。 Sphinxのテストにwheelを活用したらめちゃ速くなりました( https://drone.io/bitbucket.org/shimizukawa/sphinx-py3-native/18 )。@aodag、良い記事をありがとうー。
まとめ¶
そろそろ 2to3 やめよう
python-future のfuturizeは便利
six と python-future どちらが良いか誰か調査して
u""
リテラルめんどくさいPython-3.2 はDropしよう
wheel速いよ、開発に活用すると良いよ