Python 动态导入无法在 Virtualenv 中找到包
Python Dynamic Import Can't Find Packages in Virtualenv
所以,我有一个目录结构:
main.py
\_ modules/
\_ a.py
\_ b.py
在 main.py 中,模块在 运行 时动态加载,具体取决于指定的模块。 (这允许添加一个假设的 c.py
,main.py
被重新 运行,并且程序检测添加 c.py
和 运行 它。 )
问题是 b.py
导入了一个通过 pip 安装的模块(在 virtualenv 中)。 (为了避免混淆,我将把它称为库。)当 b.py
直接为 运行 (python b.py
) 时,库导入就好了。当打开 shell 并手动导入库时,它可以工作。
但是,当 main.py
是 运行 并且 b.py
是动态导入的(使用 pkgutil.iter_modules
检测模块,然后 importlib.import_module
导入所需的ones),找不到 b.py
导入的库 - 抛出 ImportError: No module
。
回顾一下:模块导入已安装的库,这在模块直接 运行 或在 python 解释器中手动导入有问题的库时有效,但是当模块是动态导入的,找不到库。给出了什么?
虚拟环境臭名昭著。他们多次修改路径并弄乱了很多东西。
在这两种情况下,您都需要检查 b.py
中的 PATH
变量。
这很可能不一样。
您需要设置路径以包含您的 c.py
目录。
您可以检查 main.py
中的路径,如果它在那里是正确的,则意味着您的其他导入之一正在更改您的 sys.path
以删除它。
第三个不相关的细节是问题所在:pyenv。
有一个错误报告 here,但长话短说,pyenv 使用垫片拦截包导入并正确路由它们。
这意味着pyenv必须混淆路径。当我直接 运行 python 时,垫片在 python 路径中很明显:
[dnelson@blueharvest somedir]$ python
Python 2.7 (r27:82500, Jun 1 2015, 15:01:57)
[GCC 4.9.2 20150212 (Red Hat 4.9.2-6)] on linux3
Type "help", "copyright", "credits" or "license" for more information.
>>> import site
>>> site.getsitepackages()
['/home/dnelson/.pyenv/versions/2.7/lib/python2.7/site-packages', '/home/dnelson/.pyenv/versions/2.7/lib/site-python']
>>> site.PREFIXES
['/home/dnelson/.pyenv/versions/2.7', '/home/dnelson/.pyenv/versions/2.7']
>>>
然而,在动态导入的包中,相同的代码导致输出:
['/usr/lib64/python2.7/site-packages', '/usr/lib/python2.7/site-packages', '/usr/lib/site-python']
['/usr', '/usr']
所以,问题似乎是 pyenv 在动态导入期间没有发挥它的 shim 魔法。
为了解决这个问题,我使用pip install --user
强制pip安装到动态导入查找的地方,而不是pyenv希望安装到的地方。 (如果您之前安装过该软件包以强制重新安装,还要添加 -I
)
也可以通过使用 sys.path.append
将安装位置(在我的例子中是 /usr/lib/python2.7/site-packages
)附加到 python 路径来解决,但这闻起来很糟糕,可能会导致问题其他人的线路。
所以,我有一个目录结构:
main.py
\_ modules/
\_ a.py
\_ b.py
在 main.py 中,模块在 运行 时动态加载,具体取决于指定的模块。 (这允许添加一个假设的 c.py
,main.py
被重新 运行,并且程序检测添加 c.py
和 运行 它。 )
问题是 b.py
导入了一个通过 pip 安装的模块(在 virtualenv 中)。 (为了避免混淆,我将把它称为库。)当 b.py
直接为 运行 (python b.py
) 时,库导入就好了。当打开 shell 并手动导入库时,它可以工作。
但是,当 main.py
是 运行 并且 b.py
是动态导入的(使用 pkgutil.iter_modules
检测模块,然后 importlib.import_module
导入所需的ones),找不到 b.py
导入的库 - 抛出 ImportError: No module
。
回顾一下:模块导入已安装的库,这在模块直接 运行 或在 python 解释器中手动导入有问题的库时有效,但是当模块是动态导入的,找不到库。给出了什么?
虚拟环境臭名昭著。他们多次修改路径并弄乱了很多东西。
在这两种情况下,您都需要检查 b.py
中的 PATH
变量。
这很可能不一样。
您需要设置路径以包含您的 c.py
目录。
您可以检查 main.py
中的路径,如果它在那里是正确的,则意味着您的其他导入之一正在更改您的 sys.path
以删除它。
第三个不相关的细节是问题所在:pyenv。
有一个错误报告 here,但长话短说,pyenv 使用垫片拦截包导入并正确路由它们。
这意味着pyenv必须混淆路径。当我直接 运行 python 时,垫片在 python 路径中很明显:
[dnelson@blueharvest somedir]$ python
Python 2.7 (r27:82500, Jun 1 2015, 15:01:57)
[GCC 4.9.2 20150212 (Red Hat 4.9.2-6)] on linux3
Type "help", "copyright", "credits" or "license" for more information.
>>> import site
>>> site.getsitepackages()
['/home/dnelson/.pyenv/versions/2.7/lib/python2.7/site-packages', '/home/dnelson/.pyenv/versions/2.7/lib/site-python']
>>> site.PREFIXES
['/home/dnelson/.pyenv/versions/2.7', '/home/dnelson/.pyenv/versions/2.7']
>>>
然而,在动态导入的包中,相同的代码导致输出:
['/usr/lib64/python2.7/site-packages', '/usr/lib/python2.7/site-packages', '/usr/lib/site-python']
['/usr', '/usr']
所以,问题似乎是 pyenv 在动态导入期间没有发挥它的 shim 魔法。
为了解决这个问题,我使用pip install --user
强制pip安装到动态导入查找的地方,而不是pyenv希望安装到的地方。 (如果您之前安装过该软件包以强制重新安装,还要添加 -I
)
也可以通过使用 sys.path.append
将安装位置(在我的例子中是 /usr/lib/python2.7/site-packages
)附加到 python 路径来解决,但这闻起来很糟糕,可能会导致问题其他人的线路。