简体   繁体   English

Python动态导入在Virtualenv中找不到包

[英]Python Dynamic Import Can't Find Packages in Virtualenv

So, I have a directory structure: 所以,我有一个目录结构:

main.py
\_ modules/
   \_ a.py
   \_ b.py

In main.py, modules are dynamically loaded at runtime, depending on which modules are specified. 在main.py中,模块会在运行时动态加载,具体取决于指定的模块。 (This allows for a hypothetical c.py to be added, main.py to be rerun, and the program to detect the addition of c.py and run it.) (这允许添加假设的c.py ,重新运行main.py ,以及用于检测c.py并运行它的程序。)

The problem is that b.py imports a module installed via pip (in a virtualenv). 问题是b.py导入了通过pip安装的模块(在virtualenv中)。 (I'm going to refer to it as a library to help avoid confusion.) When b.py is run directly ( python b.py ) the library imports just fine. (我要提到它作为一个库,以避免混淆。)当b.py被直接运行( python b.py )库进口就好了。 When the shell is opened and the library is imported by hand, it works. 打开外壳并手动导入库后,它就可以工作了。

But, when main.py is run and b.py is dynamically imported (using pkgutil.iter_modules to detect the modules and then importlib.import_module to import the required ones), the library that b.py imports isn't found - an ImportError: No module is thrown. 但是,当main.py运行和b.py动态导入(使用pkgutil.iter_modules检测模块,然后importlib.import_module导入需要的),该库b.py进口未发现-一个ImportError: No module未引发ImportError: No module

To recap: a module imports an installed library, and this works when the module is run directly or when the library in question is imported manually in the python interpreter, but when the module is dynamically imported, the library isn't found. 回顾一下:一个模块会导入一个已安装的库,当直接运行该模块或在python解释器中手动导入有问题的库时,此方法有效,但是当动态导入模块时,找不到该库。 What gives? 是什么赋予了?

A third, unrelated detail was the problem: pyenv. 第三个不相关的细节是问题:pyenv。

There's a bug report here , but long story short is that pyenv uses shims to intercept package imports and route them correctly. 有一个bug报告在这里 ,但长话短说是pyenv使用垫片来正确地拦截包装的产品进口,并将它们路由。

This means that pyenv has to muddle with the path. 这意味着pyenv必须混淆路径。 When I run python directly, the shims are apparent in the python path: 当我直接运行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']
>>> 

However, in the dynamically imported package, the same code results in an output of: 但是,在动态导入的程序包中,相同的代码将导致以下输出:

['/usr/lib64/python2.7/site-packages', '/usr/lib/python2.7/site-packages', '/usr/lib/site-python']
['/usr', '/usr']

So, the issue appears to be that pyenv isn't doing its shim magic during dynamic imports. 因此,问题似乎在于pyenv在动态导入期间没有发挥其匀称魔术的作用。

To solve the problem, I used pip install --user to force pip to install to the place where the dynamic import is looking, rather than where pyenv wants the install to go. 为了解决该问题,我使用pip install --user强制将pip安装到动态导入所在的位置,而不是pyenv希望安装的位置。 (also add a -I if you've previously installed the package to force a reinstall) (如果您之前已经安装了该软件包以强制重新安装,则还要添加-I

It can also be solved by appending the install location (in my case, /usr/lib/python2.7/site-packages ) to the python path using sys.path.append , but that smells awful and could cause problems down the line for other people. 也可以通过使用sys.path.append将安装位置(在我的情况下为/usr/lib/python2.7/site-packages )附加到python路径中来解决,但这闻起来很糟,可能会导致问题对于其他人。

Virtualenvs are notorious. 虚拟环境是臭名昭著的。 They tinker around with paths lots of times and mess up quite a lot of things. 他们无数次地在小路旁乱转,弄乱了很多东西。

You need to check the PATH variable inside b.py in both scenarios. 在两种情况下,您都需要检查b.py中的PATH变量。 This will most probably not be the same. 这很可能会不一样。

You'd need to set the path to include your c.py 's directory. 您需要设置路径以包含c.py的目录。 You can check the PATH in main.py and if it is correct there, it would mean that one of your other imports is changing your sys.path ina way to remove that. 您可以在main.py检查PATH,如果那里是正确的,则意味着其他导入之一正在更改sys.path从而将其删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM