使用本地目录覆盖 virtualenv 中的模块

Posted

技术标签:

【中文标题】使用本地目录覆盖 virtualenv 中的模块【英文标题】:Override module in virtualenv with local directory 【发布时间】:2015-07-03 15:14:19 【问题描述】:

我对 python 比较陌生,遇到了一个我无法解决的问题。我有一个依赖于模块 B 的模块 A。通常,A 下载 B 并将其与其余的鸡蛋一起存储在我的 virtualenv 站点包中。现在,我想使用 B 的本地版本而不是下载的 B 版本,但无论我做什么,A 仍然在其站点包中使用 B,而不是我在 PYTHONPATH 中指定的那个。

我知道我的本地 B 设置正确,因为如果我将它添加到我的 PYTHONPATH 并且我没有使用 virtualenv,我可以很好地使用它。

如果我打开 ipython 并将本地 B 附加到 PYTHONPATH,我会看到我的 sys.path 首先列出了站点包版本,然后是我的 PYTHONPATH 中的目录。如果我做了一些 hacky,比如颠倒 sys.path 的顺序并尝试加载 B,它仍然使用站点包中的 B。我发现解决这个问题的唯一方法是创建一个从我的站点包中的 B 到我的本地 B 的符号链接,并删除我本地 B 中的所有 *.pyc 文件。必须有一个更好的方法要做到这一点......任何帮助都会很棒。谢谢!

我不确定这是否重要,但作为参考,我正在使用以下版本的东西:

virtualenv 12.1.1 python 2.7 模块 A 和 B 是我公司的内部库 Ubuntu 12.04.5 LTS

【问题讨论】:

你可以卸载远程版本和pip install -e本地吗? 你需要卸载包 B(从你的站点包中),然后确保你的 B 的本地副本可以在你的 PYTHONPATH 中的某个地方访问(可导入)。 @tzaman 实际上效果很好。当我对本地版本进行更改时,我什至不必重做 pip 安装。我仍然希望找到为什么 PYTHONPATH 不起作用的答案,但这是我手头任务的可行解决方案。谢谢! @LizBennett 太棒了!我已将其发布为更详细的答案。 【参考方案1】:

Python 将始终在您的安装目录(站点包)中查找软件包,然后再查找您的当前目录。如果/当它在安装目录中找到一个包时,它会停止查找。

如果您想这样做,您可以明确引用您的本地副本。

from . import ModuleB
from .. import ModuleB
#etc

【讨论】:

感谢您的回答。我很惊讶没有办法覆盖这种行为。似乎加载我的本地版本(不使用您建议的语法)的唯一方法是实际删除站点包中的内容。作为来自 java 领域的人,从完全控制加载库的顺序到没有真正控制是很奇怪的。【参考方案2】:

如果您正在处理一对相互依赖的相关项目,您可以卸载“远程”版本并使用pip install -e 从您的本地副本editable mode 安装它。

这会让你的依赖项目看到它,并自动看到上游项目的变化,而不需要任何额外的工作。

【讨论】:

我遇到的唯一问题是模块 A 依赖包 C 版本 1.3.6,而模块 B 也依赖包 C,但版本 1.3.3。当我在 virtualenv 中处理模块 A 并且我执行 pip install -e /path/to/B 时,它会尝试使用错误版本的 C 构建模块 B,即当 B 需要 1.3.3 时使用 1.3.6。为此,只需升级 B 的依赖项就可以了,但这可能并不总是一种选择。

以上是关于使用本地目录覆盖 virtualenv 中的模块的主要内容,如果未能解决你的问题,请参考以下文章

Pythonpip模块部署——组件virtualenv和pipreqs

虚拟环境virtualenv

用Pipenv 管理你的本地环境,别直接用virtualenv

python的Virtualenv

使用virtualenv管理多个Python版本

使用pyenv和virtualenv在apache后面部署flask应用程序时找不到numpy,pandas模块