排序 sys.path:首先是 virtualenv,然后是 /usr
Sorting sys.path: first virtualenv, then /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
?
为什么我使用 system-site-packages
似乎没有直接的方法可以从 virtualenv 中可用的全局站点包中创建单个库。看到这个问题:
make some modules from global site-packages available in virtualenv
像 python-gtk 这样的包很难安装在 virtualenv 中。
您可以在导入模块之前简单地添加所需的路径。有点老套,但应该可以解决您的问题
import sys
sys.path.insert(1, '/home/my-virtualenv/lib/python2.7/site-packages')
import lalala
下面的直接解决方案解决了您的问题:
1- 打开 my-virtualenv/lib/python2.7/site.py
文件进行编辑。
2- 在此文件末尾追加以下排序算法行(或解决您问题的任何代码)(无首行缩进):
prefix = __file__.rsplit(os.sep, 3)[0]
@Jan-Philip Gehrcke 建议的代码行下方:
sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)
3- 运行 您的节目并享受
此解决方案可帮助您对 sys.path
列表进行排序,而无需在程序主体中添加烦人的行。
注意:site模块在初始化时自动导入。可以使用解释器的 -S
选项来抑制自动导入。
如果您使用交互式 shell,您可以设置 PYTHONSTARTUP
,或者也可以设置一些 bash 别名,以您喜欢的方式修改您的 PYTHONPATH
.
你也可以在你的virtualenv
的bin
目录下修改激活文件activate.csh
、activate_this.py
;或 site.py
文件作为另一个提到的响应。
pip + virtualenv
是——正如有人指出的那样,这对于系统范围的包来说不是一个非常友好的组合,即没有默认标志说 使用系统 numpy或 package x,y 构建环境时。尽管正如评论中所建议的那样,我也建议使用 --no-site-packages
进行构建,然后从 /usr/lib
中专门导入您需要的内容
编辑,讨论后:
"I want all paths outside my virtualenv (/usr...) to be below the
paths of the virtualenv. [...] It needs to be sorted."
然后,只需在第一次导入之前对 sys.path
进行排序。给定一个特定的路径 prefix
对应于你的 virtalenv 的位置,这种方法可能就足够了:
sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)
sorted()
的排序行为是稳定的:具有相同排序键的项目保留原始顺序。这里只使用了两个排序键:True
和 False
。你需要想出一个可靠的方法来设置你的prefix
(你可能想硬编码它,或者根据当前工作目录确定它,我相信你找到了一种方法)。
原答案(仍然有效,一般来说):
你不想过多阐述你的需求和应用场景,所以我提供一个更笼统的答案:你可能需要考虑你的方法,并且可能不会期望 virtualenv
完全解决你的问题.
在某些情况下,virtualenv
并不是完美的解决方案。它 是 一种妥协,这种妥协的一方面在这篇文章中进行了详尽的描述:https://pythonrants.wordpress.com/2013/12/06/why-i-hate-virtualenv-and-pip/
在很多情况下 virtualenv
都有很好的用途,并且做得很好!当然,它对我帮助很大,尤其是在开发方面。在其他场景下,它不是一个完整的解决方案,甚至是一个糟糕的解决方案。
所以,现在我看到了几个不同的选项:
- 使用 virtualenv,但控制那些你需要改变的东西。例如,在 进行特定导入之前,从包 中修改
sys.path
。虽然有些人可能会考虑这个 "not clean",但它肯定是一种高效可靠地控制目录搜索顺序的非常快捷的方法。 sys.path.insert(1, foo)
实际上被 许多 包和测试环境使用。这一点也不罕见。这种方法可能会在一分钟的工作后为您提供一个可行的解决方案。试一试!
- 如果您认为您的情况下的 virtualenv 的行为与记录的不符或明显显示错误行为,请将您的发现报告给项目。他们一定会感谢您的简明反馈。
- 如果您认为 virtualenv 没有提供您的应用程序案例中所需的隔离或控制级别,您可能需要查看其他选项,例如 Docker 或 Vagrant,或全功能虚拟机。
我发现解决这个问题的一个简单方法就是将你的 virtualenv site-packages 文件夹添加到 $VIRTUAL_ENV/lib/python2.7/site-packages/_virtualenv_path_extensions.pth 文件或直接输入 shell 激活环境后:
$ add2virtualenv $VIRTUAL_ENV/lib/python2.7/site-packages
这将迫使该文件夹出现在您的系统文件夹之前,正如我注意到它对添加的其他路径所做的那样。
我相信这不是最干净的解决方案,但确实 virtualenv 对路径进行了奇怪的排序。
另一个观察结果是,当我开始 ipython 时,sys.path 以合理的顺序出现,但在 python 解释器内部时却没有,我不确定为什么。
为什么 sys.path
在我的 virtualenv 目录之前包含 /usr/...
?
我用 --system-site-packages
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
?
为什么我使用 system-site-packages
似乎没有直接的方法可以从 virtualenv 中可用的全局站点包中创建单个库。看到这个问题: make some modules from global site-packages available in virtualenv
像 python-gtk 这样的包很难安装在 virtualenv 中。
您可以在导入模块之前简单地添加所需的路径。有点老套,但应该可以解决您的问题
import sys
sys.path.insert(1, '/home/my-virtualenv/lib/python2.7/site-packages')
import lalala
下面的直接解决方案解决了您的问题:
1- 打开 my-virtualenv/lib/python2.7/site.py
文件进行编辑。
2- 在此文件末尾追加以下排序算法行(或解决您问题的任何代码)(无首行缩进):
prefix = __file__.rsplit(os.sep, 3)[0]
@Jan-Philip Gehrcke 建议的代码行下方:
sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)
3- 运行 您的节目并享受
此解决方案可帮助您对 sys.path
列表进行排序,而无需在程序主体中添加烦人的行。
注意:site模块在初始化时自动导入。可以使用解释器的 -S
选项来抑制自动导入。
如果您使用交互式 shell,您可以设置 PYTHONSTARTUP
,或者也可以设置一些 bash 别名,以您喜欢的方式修改您的 PYTHONPATH
.
你也可以在你的virtualenv
的bin
目录下修改激活文件activate.csh
、activate_this.py
;或 site.py
文件作为另一个提到的响应。
pip + virtualenv
是——正如有人指出的那样,这对于系统范围的包来说不是一个非常友好的组合,即没有默认标志说 使用系统 numpy或 package x,y 构建环境时。尽管正如评论中所建议的那样,我也建议使用 --no-site-packages
进行构建,然后从 /usr/lib
编辑,讨论后:
"I want all paths outside my virtualenv (/usr...) to be below the paths of the virtualenv. [...] It needs to be sorted."
然后,只需在第一次导入之前对 sys.path
进行排序。给定一个特定的路径 prefix
对应于你的 virtalenv 的位置,这种方法可能就足够了:
sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)
sorted()
的排序行为是稳定的:具有相同排序键的项目保留原始顺序。这里只使用了两个排序键:True
和 False
。你需要想出一个可靠的方法来设置你的prefix
(你可能想硬编码它,或者根据当前工作目录确定它,我相信你找到了一种方法)。
原答案(仍然有效,一般来说):
你不想过多阐述你的需求和应用场景,所以我提供一个更笼统的答案:你可能需要考虑你的方法,并且可能不会期望 virtualenv
完全解决你的问题.
在某些情况下,virtualenv
并不是完美的解决方案。它 是 一种妥协,这种妥协的一方面在这篇文章中进行了详尽的描述:https://pythonrants.wordpress.com/2013/12/06/why-i-hate-virtualenv-and-pip/
在很多情况下 virtualenv
都有很好的用途,并且做得很好!当然,它对我帮助很大,尤其是在开发方面。在其他场景下,它不是一个完整的解决方案,甚至是一个糟糕的解决方案。
所以,现在我看到了几个不同的选项:
- 使用 virtualenv,但控制那些你需要改变的东西。例如,在 进行特定导入之前,从包 中修改
sys.path
。虽然有些人可能会考虑这个 "not clean",但它肯定是一种高效可靠地控制目录搜索顺序的非常快捷的方法。sys.path.insert(1, foo)
实际上被 许多 包和测试环境使用。这一点也不罕见。这种方法可能会在一分钟的工作后为您提供一个可行的解决方案。试一试! - 如果您认为您的情况下的 virtualenv 的行为与记录的不符或明显显示错误行为,请将您的发现报告给项目。他们一定会感谢您的简明反馈。
- 如果您认为 virtualenv 没有提供您的应用程序案例中所需的隔离或控制级别,您可能需要查看其他选项,例如 Docker 或 Vagrant,或全功能虚拟机。
我发现解决这个问题的一个简单方法就是将你的 virtualenv site-packages 文件夹添加到 $VIRTUAL_ENV/lib/python2.7/site-packages/_virtualenv_path_extensions.pth 文件或直接输入 shell 激活环境后:
$ add2virtualenv $VIRTUAL_ENV/lib/python2.7/site-packages
这将迫使该文件夹出现在您的系统文件夹之前,正如我注意到它对添加的其他路径所做的那样。
我相信这不是最干净的解决方案,但确实 virtualenv 对路径进行了奇怪的排序。
另一个观察结果是,当我开始 ipython 时,sys.path 以合理的顺序出现,但在 python 解释器内部时却没有,我不确定为什么。