py2exe のハマりどころメモ

py2exe を使用すると、 setup.py にちょっと追記するだけで Python スクリプトを単体で配布可能な実行形式に変換できる。

結構便利ではあるのだが、これがけっこうハマる。
ということでそこら辺メモ。

基本

基本的に以下のようなスクリプトを記述し、 python setup.py py2exe で変換する。

# -*- coding:utf-8 -*-

import sys
import setuptools
import py2exe


setuptools.setup(
    console=["entrypoint.py"],
    name="py2exename",
    version=u"0.1.0",
    description=u"説明",
    options=dict(
        py2exe=dict(
            # 含まれる依存関係
            includes=['pyramid', 'zope.pagetemplate'],
            )
        )         
  

動的 import

py2exe で作成した実行バイナリは、 console に指定したエントリポイントとなるファイルを読み込んで実行が始まる。

生成されるバイナリに含まれるライブラリは、エントリポイントから import を辿って import されたモジュールが全て入っているのだが、それに含まれない動的に読み込むような(__import__ とか imp とかで読み込んでいる)モジュールの場合は、 options で指定してあげる必要がある。

egg の落とし穴

Python のライブラリをインストールするとき、以下のように setup.py や easy_install, pip などを使用してインストールする。
とても楽ではあるのだが、ここで py2exe の落とし穴があったりする。

$ python setup.py install
$ easy_install modulename
zip 形式 egg

上記方法でモジュールをインストールすると、 Python の lib/site-packages に egg が追加され、モジュールがインストールされる。
ただし、 egg が zip で圧縮された形式で保存された場合は、 py2exe での依存関係解決において見つけられず、対象モジュールがない状態で実行ファイルが生成されてしまうようで、とても困る。
includes オプションを指定しても読んでくれない。

そういう場合は egg を展開し、対象モジュールを setup.py と同じディレクトリにコピーすることで回避しているが、何かいい手はないものだろうか…。

EGG-INFO

まれにではあるが *.egg/EGG-INFO にあるパッケージのメタ情報に依存していることがある。 (例: blockdiag)
そもそも py2exe で固めた場合はパッケージのソースのみ抽出され、メタ情報である EGG-INFO などは残らない。
この場合は割とどうしようもないので、ソースを読んでハックするしかない。

その他

他にもなにかあったような気がするけども思い出せないので思い出したら書く。