pip 非対応のモジュールを virtualenv で使うには(OS X 編)

Windows 編POSIX 編の続き。というかこれが本題。

これまで説明してきた方法でシステムにインストールしたパッケージやライブラリを virtualenv 環境にリダイレクトできるのだけど、このやりかたを使って OS X で wxPython を使おうとすると、以下のような奇妙なメッセージが出てうまくいかない。

This program needs access to the screen.
Please run with a Framework build of python, and only when you are
logged in on the main display of your Mac.

どうも OS X の Python は特定の場所にインストールされているバイナリでないと GUI のフレームワークなどを使うことができないらしい(適当な推測)。virtualenv は作業ディレクトリにインタプリタをコピーするのでそれではじかれるようだ。

これは困った。コピーしたインタプリタが使えないんじゃ virtualenv できないじゃないか。で、あれこれ考えたのだけど、環境変数 PYTHONHOME を設定してもとの python を実行すれば別の環境でインタプリタを起動できることに気づいた。virtualenv 環境が /path/to/venv ディレクトリにあるなら、PYTHONHOME を /path/to/venv にして /usr/bin/python を実行すれば、virtualenv と同等のカプセル化の恩恵が得られる。

そこで、activate.csh に(tcsh なんすよ……)、PYTHONHOME を設定するような記述(と、deactivate したときにそれを戻す記述)を追加してみた。それから、virtualenv が作った作業ディレクトリの python コマンドの代わりに、システムの python へのシンボリックリンクを置く。

ln -s /usr/bin/python /path/to/venv/bin/

改造した activate.csh は Gist に置きました。bash 用のスクリプトをだれか作ってあげてください。

それはさておき、こうするとそれまでの virtualenv と同様の使い勝手で開発を続けることができる。めでたい。

めでたいのだけど、virtualenv 環境を作るごとにこの作業をするのは面倒くさい。なんとか virtualenv のほうで対応してくれないものかなあ……。僕の力量ではどうしていいのかわからん。

pip 非対応のモジュールを virtualenv で使うには(POSIX 編)

Windows 編の続き。

Windows ではハードリンクとジャンクションで行ったが、Linux や OS X など、POSIX の環境であればハードリンクとシンボリックリンクで同様に対策できる。じつは Windows 編で紹介したスクリプト(redirect-package.py)は、すでに POSIX 環境ではそう処理するようになっている。

Linux ではこれで問題ない。

ところが、OS X ではこれで wxPython を使えるようにしようとすると virtualenv 環境では wx モジュールをインポートできない。次回にはこれについて書きます。

pip 非対応のモジュールを virtualenv で使うには(Windows 編)

プロジェクトごとに独立した Python インストール環境を作れる virtualenv は便利なのだけど、pip でのインストールに対応していないモジュールを使いたいとなるととたんに難しいことになる。Windows では標準で拡張モジュールをビルドできないこともあってインストーラーの配布形式(bdist_wininst)が長い間使われてきたので、古いパッケージだと pip でインストールできる wheel 形式での配布がなされていないものが多い。wxPython とか py2exe とかである。

しかし、一旦インストーラーでシステムの Python にインストールしたうえで、それらを virtualenv 環境のライブラリのディレクトリにリダイレクトしてやれば、virtualenv 環境からでもインポートできるようになる。リダイレクトといっても、ようは site-packages にハードリンクやジャンクションを張るだけだけど。

たとえば wxPython の場合、通常どおりインストーラーで導入してシステムの Python から使ってみると、

C:\Users\mshibata>python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>> wx.__file__
'C:\\Python27\\lib\\site-packages\\wx-3.0-msw\\wx\\__init__.pyc'
>>>

パッケージが C:\Python27\lib\site-packages\wx-3.0-msw\wx にあるということがわかる。そこで、virtualenv 環境があるディレクトリで、

C:\Users\mshibata\work>virtualenv venv
New python executable in venv\Scripts\python.exe
Installing setuptools, pip...done.
C:\Users\mshibata\work>mklink /j venv\Lib\site-packages\wx C:\Python27\lib\site-packages\wx-3.0-msw\wx
venv\Lib\site-packages\wx <<===>> C:\Python27\lib\site-packages\wx-3.0-msw\wx のジャンクションが作成されました

とすれば、

C:\Users\mshibata\work>venv\Scripts\activate.bat
(venv) C:\Users\mshibata\work>python
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32
Type "help", "copyright", "credits" or "license" for more information.
>>> import wx
>>>

とこのようにインポートできる。パッケージではなく単体のモジュールの場合は、ジャンクションではなくモジュールの .py ファイルへのハードリンクを張ればよい(けど、そういうのはふつうに virtualenv 環境にインストールできるか)。

py2exe もこの方法で virtualenv 環境で使えるようにすることができる。しかしこれだと py2exe がさらに読みこんでいる別のモジュールまではリダイレクトされていないので、ImportError が発生することがある。その場合は適宜足りてないモジュールへのリンクを張ればよい(いいかげんだ)。

最初だけなので手作業でやってもいいのだけれど、いちいちインポートされてるモジュールのパスを調べてコピペするのは面倒なので、上記の作業をやってくれるスクリプトを作ってみた。

C:\Users\mshibata\work>redirect-package.py venv wx py2exe
venv\Lib\site-packages\wx <<===>> C:\Python27\lib\site-packages\wx-3.0-msw\wx のジャンクションが作成されました
venv\Lib\site-packages\py2exe <<===>> C:\Python27\lib\site-packages\py2exe のジャンクションが作成されました

と、こんなふうに使う。

tcsh で virtualenv を有効化する

さいきん清水川さんの新しい本のレビューをさせていただいていて、pip とか virtualenv とか wheel とかの知識をフライングゲットしてにわかに盛り上がっています。

virtualenv で環境作って有効化するとき、シェルが bash なら venv/bin/activate コマンドで有効化するのだけど、自分はシェルが tcsh なので source venv/bin/activate.csh としなければならない。

これは面倒なので、.cshrc にエイリアスを定義してみた。

alias activate source "\!*/bin/activate.csh"

これで tcsh でも activate venv と打つだけで有効化できる。引数間違えたりとかするとおかしなことになるけど、まあそれは気が向いたら改善しよう。