ubuntuでpyvenvしたときの落とし穴

dockerでアプリケーションテスト用の環境を作ろうとしたときにはまったので、誰得メモ。

python3.3のwebアプリケーションのテストをpostgresqlとかredisとかを簡単にリセットできる環境がほしいと思ったので、dockerで試していました。 で、なんかsaucyのイメージって公式っぽい base リポジトリにはなかったので、とりあえずppa:deadsnakesで各種バージョンのPythonが完備されているshimizukawa/python-allを使ってみました。

そして、dockerの中で環境作るためにpyvenvしてからのget-pip.pyをしたところ、pipが $VIRTUAL_ENV/bin じゃなくて、 $VIRTUAL_ENV/local/bin にインストールされてしまう問題に気づきました。 これだとPATHに含まれてないので、最初はpipのインストールに失敗したように見えます。 実際は違うところにインストールされていました。

で、なぜだろうと原因を探りつつ、発生する条件を特定してみると

  • activateした場合は発生しない。pyvenvしたpythonをパス指定で実行すると発生する。
  • ソースインストールしたPythonでは発生しない。
  • deadsnakesでなくともubuntuのパッケージで入れたPython3.3でも発生する。
  • pyvenvじゃなくて、virtualenvのときは発生しない。

まずactivateすると発生するってことで、その前後でsite-packagesを調べると、activateするとpyvenvした環境がsite.getsitepackages()の結果に含まれていることがわかりました。 pipは最終的に、 setup.py install を呼ぶようになってるので、このあたりの情報が狂ってしまうとどうしようもないのでしょう。 ソースインストールしたPythonではそういった動作はしてなかったので、パッケージの場合に当てられてるパッチかなと思い、パッケージソースを確認してみます。

なぜかdebianのほうのソースを確認していますが、多分ubuntuも同じでしょう。

http://bazaar.launchpad.net/~doko/python/pkg3.3-debian/view/head:/patches/site-locations.diff

ここで、dist-packagesとかなんかごちゃごちゃやってますが、 VIRTUAL_ENV環境変数が有効なときに、その環境のsite-packagesを追加するようになっています。 これで、activateすれば発生しない理由がわかりました。

しかし、ansibleとかそういうので環境作ろうとしたら、activateしないでそのままパス指定で実行することもあるので、別の方法はないのかと調べてみると、pipがやっていました。 pip はインストール先の環境を判定するのに sys.prefix, sys.base_prefix, sys.real_prefix をつかっています。 こちらの方法ならactivateに関係なく、パス指定の場合でも正確に判定できそうです。

ちなみに virtualenv の場合に発生しないのは、site.pyを仮想環境専用のsite.payを置いているのでパッチの影響を受けないのだろうと思われます。

とはいえ、この問題の発生条件は ubuntu(多分debianも)で、パッケージインストールされたPython3.3のpyvenvで作った環境以下のpythonをactivateせずにパス指定で実行するという以外に見つからなかったので、まあ virtualenv使うなり、VIRTUAL_ENV環境変数が使われるようにplaybookとかそういうのを書くってことで回避できるでしょう。 3.4だとensure-pipでpyvenv内に最初からpip入るようになるし....

多分まったく同じ問題ではまる人はあまりいないと思いますが、類似の問題のヒントにでもなればと思います。 役に立ったと思った人は、「午後の紅茶 おいしい無糖」でも送ってください。

Comments !

blogroll

social