将Python virtualenv包与发行包混用?

时间:2015-05-07 07:33:46

标签: python ubuntu pip virtualenv

使用Python virtualenv 处理这种情况的好方法是什么,但是您想要通过发行版的软件包管理器安装一些软件包?

我们假设您需要 lxml ,但因为您无法让pip install lxml在Ubuntu上工作。而且你真的不想浪费时间在这上面,所以你只需要apt-get install python-lxml

现在,您可以使用--system-site-packages创建virtaulenv,并且现在可以访问系统范围内安装的预编译 lxml 。但是,您也会拖入您不需要的所有其他系统级软件包!是的,将会有很多软件包安装在virtualenv之外,通过sudo pip ...sudo apt-get python-...,所以没有"只需保持系统清洁并安装所有内容可以在virtualenvs中,以便--system-site-packages不会用它拖动太多的包#34; 不是我在这里的解决方案。

那么,有没有办法安装某些特定的系统网站包?

1 个答案:

答案 0 :(得分:1)

我总是使用pip install --user packagename - 它不需要sudo。

如果您还没有pip,或者操作系统的pip或操作系统的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选项。

按照您描述的方式进行

例如,我想导入操作系统中存在的模块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的评论,所以这就是为什么我写了一个完整的答案。 :)

  

但是你也会拖入你不需要的所有其他系统范围的包!

不,你不会。只有在执行import时才将模块加载到内存中。如果你的意思是包装将出现在virtualenv中 - 再一次,它不会。如果您查看了myvenv/lib/python3.4/site-packages/内部,您会看到内部只有两个包 - pipsetuptools(后者分为几个目录)。 virtualenv中的Python解释器只是像普通的解释器一样加载系统范围的模块。

P.S。上面的代码也适用于Python 2.7。只需将pip3替换为pip2python3替换为python23.4替换为2.7等。

P.P.S。您可以将带有依赖项的模块复制到virtualenv到相应的目录,而不是符号链接。使用--always-copy时这是有道理的,这样你的virtualenv就变得可移植了。

P.P.P.S。如果您决定将virtualenv与--system-site-packagespip一起使用,并且,比方说,您希望requests包比/usr/lib中已安装的包更新,请使用{{ 1}},如here所述。