Edited at

PySide(Qt4)とPyQt(Qt5)に必要な環境変数をセットする

More than 3 years have passed since last update.

Qt4/Qt5およびPySide(Qt4対応,Qt5に対応していないようなので)/PyQt(Qt5対応)を両立する際、環境変数まわりで少し工夫が必要だった。


前提環境


  • OS X(10.9.5)

  • virtualenvwrapper

  • Homebrew


Qt4/Qt5のインストール

Homebrew経由でインストールする。


Qt4/Qt5のインストール(Homebrew)

$ brew install qt

$ brew install qt5


PySideのインストール

PySideはpip経由でインストール可能だったため、virtualenv下にインストールする。


PySideのインストール(pip)

$ mkvirtualenv -p python3 pyside

(pyside)$ mkvirtualenv
(pyside)$ pip install PySide


PyQtのインストール

PyQtも同様にpip経由でインストールを試みたところ、既に削除されたのかインストールできなかった。


PyQtのインストール(pipで失敗)

$ mkvirtualenv -p python3 pyqt

(pyqt)$ pip install PyQt5
Downloading/unpacking PyQt5
Could not find any downloads that satisfy the requirement PyQt5
Cleaning up...
No distributions at all found for PyQt5
Storing debug log for failure in /Users/FGtatsuro/.pip/pip.log

そのため、PyQtはHomebrew経由でインストールすることとした。インストール時のトラブルはこちら。なおPyQt自体はHomebrew経由でインストールしたが、関連するライブラリをインストールすることを考えて、PySideと同様にvirtualenv環境は作っておく。


PyQtのインストール(Homebrew)

(pyqt)$ brew install pyqt5



PySideの実行

ここにあるPySideのサンプルを動かそうとしたが、動的ライブラリの読み込みに失敗し実行できない。


PySideの実行(失敗)

(pyside)$ python pyside_test.py

Traceback (most recent call last):
File "pyside_test.py", line 6, in <module>
from PySide.QtCore import *
ImportError: dlopen(/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/QtCore.so, 2): Library not loaded: libpyside.cpython-34m.1.2.dylib
Referenced from: /Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/QtCore.so
Reason: image not found

読み込もうとしている動的ライブラリはvirtualenvのsite-package下にある。そのパスを環境変数DYLD_LIBRARY_PATHに追加することで実行できる。


PySideの実行(成功)

(pyside)$ ls /Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/libpyside.cpython-34m.1.2.dylib

/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/libpyside.cpython-34m.1.2.dylib
(pyside)$ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide
(pyside)$ python pyside_test.py


PyQtの実行

ここにあるPyQtのサンプルを動かそうとしたが、こちらはPyQtのモジュールの読み込みに失敗する。


PyQtの実行(失敗)

(pyqt)$ python pyqt_test.py

Traceback (most recent call last):
File "pyqt_test.py", line 4, in <module>
from PyQt5.QtCore import *
ImportError: No module named 'PyQt5'

Homebrew経由でインストールしたPyQt(+PyQtが依存しているsip)のsite-packageが、virtualenv環境から見えていないのが原因。そのパスを環境変数PYTHONPATHに追加することで実行できる。


PyQtの実行(成功)

(pyqt)$ export PYTHONPATH=$PYTHONPATH:/usr/local/opt/pyqt5/lib/python3.4/site-packages:/usr/local/opt/sip/lib/python3.4/site-packages

(pyqt)$ python pyqt_test.py


環境変数の切り替え

ここまででPySide/PyQtの実行はできたが、これらを共存するとなるとまだ問題がある。PySideに必要なDYLD_LIBRARY_PATHとPyQtの実行に必要なPYTHONPATHが両方存在した場合、PyQtの実行に失敗する。(ライブラリの読み込みトラブル?)


環境変数によるPyQt実行の失敗

(pyqt)$ env | egrep 'DYLD_LIBRARY_PATH|PYTHONPATH'

DYLD_LIBRARY_PATH=/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide
PYTHONPATH=/usr/local/opt/pyqt5/lib/python3.4/site-packages:/usr/local/opt/sip/lib/python3.4/site-packages

(pyqt)$ python pyqt_test.py
Traceback (most recent call last):
File "pyqt_test.py", line 5, in <module>
from PyQt5.QtWidgets import *
RuntimeError: the PyQt5.QtCore module failed to register with the sip module


DYLD_LIBRARY_PATHをunsetすれば実行可能になるが、virtualenv環境を切りかえるたびにこの変数を意識しなくてはならないのは非常に面倒に感じる。

そこでPySide/PyQtのvirtualenv環境をactivate/deactivateした際に必要な環境変数をexport/unsetするようにvirtualenvwrapperの設定ファイルを変更した。.virtualenvs/postactivateはactivate「後」に実行され、.virtualenvs/predeactivteはdeactive「前」に実行される。PySide環境の判定が「virtualenv環境下の」pipに依存しており、判定のタイミングはvirtualenv環境に入った「後」とvirtualenv環境から出る「前」でなくてはならない。

判定の条件は次の通り。


  • PySide: pipでPySideがインストールされている。

  • PyQt: virtualenv環境名に文字列pyqtを含む。


.virtualenvs/postactivate

#!/bin/bash

# This hook is run after every virtualenv is activated.

# PySideがpipでインストールされていれば、DYLD_LIBRARY_PATHに必要なパスを追加する。
if [ `pip freeze | grep PySide` ]; then
# Now, I can use PySide on only 3.4.x environment
VENV_PYSIDE_PATH=$VIRTUAL_ENV/lib/python3.4/site-packages/PySide
if [ $DYLD_LIBRARY_PATH ]; then
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$VENV_PYSIDE_PATH
else
export DYLD_LIBRARY_PATH=$VENV_PYSIDE_PATH
fi
fi

# virtualenv環境名が"pyqt"を含んでいれば、PYTHONPATHに必要なパスを追加する。
if [ `basename $VIRTUAL_ENV | grep pyqt` ]; then
# Now, I can use PyQt on only 3.4.x environment
BREW_PYQT_PATH=`brew --prefix pyqt5`/lib/python3.4/site-packages:`brew --prefix sip`/lib/python3.4/site-packages
if [ $PYTHONPATH ]; then
export PYTHONPATH=$PYTHONPATH:$BREW_PYQT_PATH
else
export PYTHONPATH=$BREW_PYQT_PATH
fi
fi



.virtualenvs/predeactivate

#!/bin/bash

# This hook is run before every virtualenv is deactivated.

# PySideがpipでインストールされていれば、DYLD_LIBRARY_PATHから関連するパスを除く。
if [ `pip freeze | grep PySide` ]; then
# Now, I can use PySide on only 3.4.x environment
VENV_PYSIDE_PATH=$VIRTUAL_ENV/lib/python3.4/site-packages/PySide
export DYLD_LIBRARY_PATH=`echo $DYLD_LIBRARY_PATH | sed -e "s|:*$VENV_PYSIDE_PATH||g"`
if [ -z $DYLD_LIBRARY_PATH ]; then
unset DYLD_LIBRARY_PATH
fi
fi

# virtualenv環境名が"pyqt"を含んでいれば、PYTHONPATHから関連するパスを除く。
if [ `basename $VIRTUAL_ENV | grep pyqt` ]; then
# Now, I can use PyQt on only 3.4.x environment
BREW_PYQT_PATH=`brew --prefix pyqt5`/lib/python3.4/site-packages:`brew --prefix sip`/lib/python3.4/site-packages
export PYTHONPATH=`echo $PYTHONPATH | sed -e "s|:*$BREW_PYQT_PATH||g"`
if [ -z $PYTHONPATH ];then
unset PYTHONPATH
fi
fi


PyQtをpip経由でインストールすることができなかったため、判定の条件をvirtualenv環境の命名規則に頼らざるを得なかった。その点が少し残念なので、いいアイデアがないか考える。