混合 Python virtualenv 包和发行包?
Mix Python virtualenv packages with distro packages?
当您使用 Python virtualenv 但您希望通过发行版的包管理器安装一些包时,有什么好的处理方法?
假设您需要 lxml,但因为您无法获得 pip install lxml
来处理 Ubuntu。你真的不想在这上面浪费时间,所以你只需要 apt-get install python-lxml
.
现在,您可以使用 --system-site-packages
创建一个 virtaulenv,并且现在可以访问系统范围内安装的预编译 lxml。但是您还将拖入不需要的所有其他系统范围的包!是的,将有相当多的软件包将通过 sudo pip ...
或 sudo apt-get python-...
安装在 virtualenv 之外,因此没有 "just keep the system clean and install everything you can in virtualenvs, so that --system-site-packages
won't drag too many packages with it"不是我这里的解决方案。
那么,有没有办法只安装一些特定的系统站点包?
我总是使用 pip install --user packagename
– 它不需要 sudo。
如果您还没有 pip
,或者 OS 的 pip
或 OS 的 easy_install
无法正常工作,首先在用户的主目录中安装setuptools
,然后将其easy_install
用于pip
。
$ wget https://bootstrap.pypa.io/ez_setup.py -O - | python3 - --user
$ easy_install-3.4 --user pip
另一方面,如果您决定在 virtualenv 中使用 pip
,请不要使用 --user
选项,原因很明显。
按照您描述的方式进行操作
例如,我想导入 OS 中的模块 curl
。
$ pip3 install --user virtualenv
$ python3 -m virtualenv myvenv
$ cd myvenv
$ source bin/activate
(myvenv)$ python3
>>> import curl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named curl
virtualenv 中没有这样的模块。只是为了确保我查看了 sys.path
.
中的内容
>>> import sys
>>> sys.path
['',
'/home/username/myvenv/lib/python27.zip',
'/home/username/myvenv/lib/python2.7',
'/home/username/myvenv/lib/python2.7/lib-dynload',
'/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2',
'/home/username/myvenv/lib/python2.7/site-packages']
请注意,没有 /usr/lib/python3.4/site-packages
,如您所愿,但存在 /usr/lib/python3.4
。如果这对您来说不合适,请在创建 virtualenv 时使用 --always-copy
选项。
在接下来的步骤中,我创建了指向 curl
模块及其依赖项的符号链接。
>>> ^D # Press Control-D
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/curl lib/python3.4/site-packages/
注意第二个参数(符号链接指向的文件或目录)中没有尾部斜杠,但第三个参数(应该创建符号链接的地方)有一个斜杠。那是因为我在目录 lib/python3.4/site-packages
的 中创建了一个符号链接 。如果没有尾部斜杠,它将尝试替换目录。
让我们检查一下是否有效。
(myvenv)$ python3
>>> import curl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/username/myvenv/lib/python3.4/site-packages/curl/__init__.py", line 9, in <module>
import sys, pycurl
ImportError: No module named 'pycurl'
没有。 curl
取决于 pycurl
。我们需要更深入。
>>> ^D
(myvenv)$ ls -1 /usr/lib/python3.4/site-packages/pycurl*
/usr/lib/python3.4/site-packages/pycurl-7.19.3.1-py3.4.egg-info
/usr/lib/python3.4/site-packages/pycurl.cpython-34m.so
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/pycurl-7.19.3.1-py3.4.egg-info lib/python3.4/site-packages/
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/pycurl.cpython-34m.so lib/python3.4/site-packages/
(myvenv)$ python3
>>> import curl
>>> curl
<module 'curl' from '/home/username/myvenv/lib/python3.4/site-packages/curl/__init__.py'>
终于。
这是你需要的吗?
就个人而言,我强烈建议您不要这样做,因为首先,这是一种变态。
此外,我怀疑这种方法是否适用于所有情况。依赖的深度可能很可怕。
其次,我认为没有理由避免 --system-site-packages
它在我所承认的所有情况下都非常有效。
由 pip
安装在用户主目录中的包比系统范围的包具有更高的优先级,因此,在执行 import
时它们首先被采用。
在 virtualenv 中,只有在使用 --system-site-packages
选项创建 virtualenv 时才会导入它们。
pip
在 virtualenv 中安装的包具有更高的优先级。
老实说,我写这个答案只是想问,为什么 你想要搞砸所有这些而不是让 pip
工作。我还不能写关于 SO 的评论,所以这就是为什么我写了一个完整的答案。 :)
But you'll also drag in all the other system wide packages that you don't need!
不,你不会。只有在执行 import
时才将模块加载到内存中。如果你的意思是这个包将出现在 virtualenv 中——再一次,它不会。如果你看过 myvenv/lib/python3.4/site-packages/
的内部,你会发现里面只有两个包 - pip
和 setuptools
(尽管后者被分成几个目录)。 virtualenv 中的 Python 解释器就像普通解释器一样简单地加载系统范围的模块。
P.S。上面的代码也适用于Python 2.7。只需将 pip3
替换为 pip2
,将 python3
替换为 python2
,将 3.4
替换为 2.7
,等等
P.P.S。您可以将模块及其依赖项复制到 virtualenv 到相应的目录,而不是符号链接。这在使用 --always-copy
时很有意义,因此您的 virtualenv 变得可移植。
P.P.P.S。如果您决定将 virtualenv 与 --system-site-packages
和 pip
一起使用,并且假设您希望 requests
软件包比 /usr/lib
中已安装的软件包更新,请使用 pip install -I
,如所述 here。
当您使用 Python virtualenv 但您希望通过发行版的包管理器安装一些包时,有什么好的处理方法?
假设您需要 lxml,但因为您无法获得 pip install lxml
来处理 Ubuntu。你真的不想在这上面浪费时间,所以你只需要 apt-get install python-lxml
.
现在,您可以使用 --system-site-packages
创建一个 virtaulenv,并且现在可以访问系统范围内安装的预编译 lxml。但是您还将拖入不需要的所有其他系统范围的包!是的,将有相当多的软件包将通过 sudo pip ...
或 sudo apt-get python-...
安装在 virtualenv 之外,因此没有 "just keep the system clean and install everything you can in virtualenvs, so that --system-site-packages
won't drag too many packages with it"不是我这里的解决方案。
那么,有没有办法只安装一些特定的系统站点包?
我总是使用 pip install --user packagename
– 它不需要 sudo。
如果您还没有 pip
,或者 OS 的 pip
或 OS 的 easy_install
无法正常工作,首先在用户的主目录中安装setuptools
,然后将其easy_install
用于pip
。
$ wget https://bootstrap.pypa.io/ez_setup.py -O - | python3 - --user
$ easy_install-3.4 --user pip
另一方面,如果您决定在 virtualenv 中使用 pip
,请不要使用 --user
选项,原因很明显。
按照您描述的方式进行操作
例如,我想导入 OS 中的模块 curl
。
$ pip3 install --user virtualenv
$ python3 -m virtualenv myvenv
$ cd myvenv
$ source bin/activate
(myvenv)$ python3
>>> import curl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named curl
virtualenv 中没有这样的模块。只是为了确保我查看了 sys.path
.
>>> import sys
>>> sys.path
['',
'/home/username/myvenv/lib/python27.zip',
'/home/username/myvenv/lib/python2.7',
'/home/username/myvenv/lib/python2.7/lib-dynload',
'/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2',
'/home/username/myvenv/lib/python2.7/site-packages']
请注意,没有 /usr/lib/python3.4/site-packages
,如您所愿,但存在 /usr/lib/python3.4
。如果这对您来说不合适,请在创建 virtualenv 时使用 --always-copy
选项。
在接下来的步骤中,我创建了指向 curl
模块及其依赖项的符号链接。
>>> ^D # Press Control-D
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/curl lib/python3.4/site-packages/
注意第二个参数(符号链接指向的文件或目录)中没有尾部斜杠,但第三个参数(应该创建符号链接的地方)有一个斜杠。那是因为我在目录 lib/python3.4/site-packages
的 中创建了一个符号链接 。如果没有尾部斜杠,它将尝试替换目录。
让我们检查一下是否有效。
(myvenv)$ python3
>>> import curl
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/username/myvenv/lib/python3.4/site-packages/curl/__init__.py", line 9, in <module>
import sys, pycurl
ImportError: No module named 'pycurl'
没有。 curl
取决于 pycurl
。我们需要更深入。
>>> ^D
(myvenv)$ ls -1 /usr/lib/python3.4/site-packages/pycurl*
/usr/lib/python3.4/site-packages/pycurl-7.19.3.1-py3.4.egg-info
/usr/lib/python3.4/site-packages/pycurl.cpython-34m.so
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/pycurl-7.19.3.1-py3.4.egg-info lib/python3.4/site-packages/
(myvenv)$ ln -s /usr/lib/python3.4/site-packages/pycurl.cpython-34m.so lib/python3.4/site-packages/
(myvenv)$ python3
>>> import curl
>>> curl
<module 'curl' from '/home/username/myvenv/lib/python3.4/site-packages/curl/__init__.py'>
终于。
这是你需要的吗?
就个人而言,我强烈建议您不要这样做,因为首先,这是一种变态。
此外,我怀疑这种方法是否适用于所有情况。依赖的深度可能很可怕。
其次,我认为没有理由避免 --system-site-packages
它在我所承认的所有情况下都非常有效。
由 pip
安装在用户主目录中的包比系统范围的包具有更高的优先级,因此,在执行 import
时它们首先被采用。
在 virtualenv 中,只有在使用 --system-site-packages
选项创建 virtualenv 时才会导入它们。
pip
在 virtualenv 中安装的包具有更高的优先级。
老实说,我写这个答案只是想问,为什么 你想要搞砸所有这些而不是让 pip
工作。我还不能写关于 SO 的评论,所以这就是为什么我写了一个完整的答案。 :)
But you'll also drag in all the other system wide packages that you don't need!
不,你不会。只有在执行 import
时才将模块加载到内存中。如果你的意思是这个包将出现在 virtualenv 中——再一次,它不会。如果你看过 myvenv/lib/python3.4/site-packages/
的内部,你会发现里面只有两个包 - pip
和 setuptools
(尽管后者被分成几个目录)。 virtualenv 中的 Python 解释器就像普通解释器一样简单地加载系统范围的模块。
P.S。上面的代码也适用于Python 2.7。只需将 pip3
替换为 pip2
,将 python3
替换为 python2
,将 3.4
替换为 2.7
,等等
P.P.S。您可以将模块及其依赖项复制到 virtualenv 到相应的目录,而不是符号链接。这在使用 --always-copy
时很有意义,因此您的 virtualenv 变得可移植。
P.P.P.S。如果您决定将 virtualenv 与 --system-site-packages
和 pip
一起使用,并且假设您希望 requests
软件包比 /usr/lib
中已安装的软件包更新,请使用 pip install -I
,如所述 here。