排序sys.path:首先是virtualenv,然后是/usr [英] Sorting sys.path: first virtualenv, then /usr

查看:65
本文介绍了排序sys.path:首先是virtualenv,然后是/usr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么sys.path在我的virtualenv目录中之前包含/usr/...?

我用--system-site-packages

创建virtualenv

此时sys.path看起来像这样:

/home/my-virtualenv/src/foo
/usr/lib/python2.7/site-packages        <--- /usr paths should be below 
/usr/lib64/python2.7/site-packages
/home/my-virtualenv/lib/python27.zip
/home/my-virtualenv/lib64/python2.7
/home/my-virtualenv/lib64/python2.7/plat-linux2
/home/my-virtualenv/lib64/python2.7/lib-tk
/home/my-virtualenv/lib64/python2.7/lib-old
/home/my-virtualenv/lib64/python2.7/lib-dynload
/usr/lib64/python2.7
/usr/lib/python2.7
/usr/lib64/python2.7/lib-tk
/home/my-virtualenv/lib/python2.7/site-packages

我希望virtualenv(/usr...)以外的所有路径都在virtualenv的路径下方.

否则会发生疯狂的事情:我用pip安装了一个软件包. Pip告诉我已安装了新版本(pip freeze | grep -i ...),但导入确实使用了/usr/lib/python2.7/site-packages

中的版本

我不能在上下文中使用--no-site-packages.

是否可以对sys.path进行排序?

我为什么使用系统站点软件包

似乎没有直接的方法来使virtualenv中的全局站点程序包中的单个库可用.看到这个问题: 在virtualenv中使全局站点包中的某些模块可用

有些软件包如python-gtk很难安装在virtualenv中.

解决方案

讨论后进行

我希望我的virtualenv(/usr ...)之外的所有路径都位于 virtualenv的路径. [...]它需要排序."

然后,只需在第一次导入之前对sys.path进行排序.给定与您的virtalenv位置相对应的特定路径prefix,此方法可能就足够了:

sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)

sorted()的排序行为是稳定的:保留具有相同排序键的项目的原始顺序.在这里,仅使用两个排序键:TrueFalse.您需要想出一种可靠的方法来设置prefix(您可能想对其进行硬编码,或者根据当前的工作目录来确定它,我相信您会找到一种方法).

原始答案(通常仍然有效):

您不想过多地阐述您的需求和应用场景,因此我提供了一个更笼统的答案:您可能需要考虑一下方法,也许不希望virtualenv能够完全解决您的问题. >

在某些情况下,virtualenv并不是完美的解决方案. 是一种妥协,本文对这一妥协的一面进行了详尽描述:sys.path.insert(1, foo)实际上由许多软件包和测试环境使用.一点也不罕见.仅需一分钟的工作时间,此方法即可为您提供可行的解决方案.试试看!

  • 如果您认为您的情况下virtualenv的行为不如所记载的或明显显示了错误的行为,请向项目报告您的发现.他们一定会感谢您的简要反馈.
  • 如果您认为virtualenv不能提供应用程序案例中所需的隔离或控制级别,则可能需要查看其他选项,例如Docker或Vagrant,或功能齐全的虚拟机.
  • Why does sys.path contain /usr/... before directories from my virtualenv?

    I create the virtualenv with --system-site-packages

    The sys.path looks like this at the moment:

    /home/my-virtualenv/src/foo
    /usr/lib/python2.7/site-packages        <--- /usr paths should be below 
    /usr/lib64/python2.7/site-packages
    /home/my-virtualenv/lib/python27.zip
    /home/my-virtualenv/lib64/python2.7
    /home/my-virtualenv/lib64/python2.7/plat-linux2
    /home/my-virtualenv/lib64/python2.7/lib-tk
    /home/my-virtualenv/lib64/python2.7/lib-old
    /home/my-virtualenv/lib64/python2.7/lib-dynload
    /usr/lib64/python2.7
    /usr/lib/python2.7
    /usr/lib64/python2.7/lib-tk
    /home/my-virtualenv/lib/python2.7/site-packages
    

    I want all paths outside my virtualenv (/usr...) to be below the paths of the virtualenv.

    Otherwise crazy things happen: I install a package with pip. Pip tells me that the new version is installed (pip freeze | grep -i ...) but the import does use the one from /usr/lib/python2.7/site-packages

    I can't use --no-site-packages in my context.

    Is there a way to sort sys.path?

    Why I use system-site-packages

    There seems to be no straight forward way to make single libraries from the global site-packages available in the virtualenv. See this question: make some modules from global site-packages available in virtualenv

    There are packages like python-gtk which are very hard to install in a virtualenv.

    解决方案

    Edit, after discussion:

    "I want all paths outside my virtualenv (/usr...) to be below the paths of the virtualenv. [...] It needs to be sorted."

    Then, just sort your sys.path before the first import happens. Given a certain path prefix corresponding to the location of your virtalenv, this approach likely is sufficient:

    sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)
    

    sorted()'s sorting behavior is stable: the original order is preserved for items with same sort key. Here, only two sort keys are used: True and False. You need to come up with a reliable way to set your prefix (You might want to hard-code it, or determine it based on the current working directory, I am sure you find a way).

    Original answer (still valid, in general):

    You did not want to elaborate on your requirements and application scenario too much, so I provide a more general answer: you may need to overthink your approach, and maybe not expect virtualenv to entirely solve your problem.

    In certain situations, virtualenv is just not the perfect solution. It is a compromise, and one side of this compromise is exhaustively described in this article: https://pythonrants.wordpress.com/2013/12/06/why-i-hate-virtualenv-and-pip/

    In many scenarios virtualenv serves a splendid purpose and does its job very fine! It helped me a lot, for sure, especially for development purposes. In other scenarios, it is either not a complete solution or even a bad solution.

    So, there are a few different options now that I see:

    1. Use virtualenv, but take control over those things that you need to have changed. For instance, modify sys.path from within your package before doing a certain import. While some might consider this "not clean", it for sure is a very quick way to efficiently and reliably control directory search order. sys.path.insert(1, foo) is actually used by many packages and test environments. It not uncommon at all. This approach may provide you with a working solution after just one minute of work. Give it a try!
    2. If you think that virtualenv in your case does not behave as documented or clearly shows buggy behavior, then please report you findings to the project. They will surely appreciate your concise feedback.
    3. If you think that virtualenv does not provide the level of isolation or control that you need in your application case, you might want to look at other options, such as Docker or Vagrant, or fully-features virtual machines.

    这篇关于排序sys.path:首先是virtualenv,然后是/usr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆