简体   繁体   English

导入在解释器启动时不可用的Python模块

[英]Importing a Python module that was not available at interpreter startup

I have code which looks like this: 我有看起来像这样的代码:

import sys, importlib

try:
    import pip
except ImportError:
    raise ImportError("Please install pip")

reqs = ["sh", "vcstools"]
for req in reqs:
    sys.stdout.write("checking for %s..." % req)
    try:
        importlib.import_module(req)
        print("found")
    except ImportError:
        print("missing!")
        print("Installing %s..." % req)
        pip.main(['install', '--user', req])
        #importlib.invalidate_caches() python3 only
        # XXX fails
        importlib.import_module(req)
        new_mods = True

    locs = locals()
    locs[req] = sys.modules[req]

print(sh, vcstools)

This is designed to download (rough) dependencies at runtime and import them (yes, I know, it does not respect version numbers, and I could have used virtualenv, etc. These are separate issues). 这样做是为了在运行时下载(粗糙)依赖项并导入它们(是的,我知道,它不尊重版本号,我本可以使用virtualenv等,这些是单独的问题)。

If we run this (with nothing installed in ~/.local), we get the following: 如果运行此命令(〜/ .local中未安装任何内容),则会得到以下信息:

checking for sh...missing!
Installing sh...
Downloading/unpacking sh
....
Successfully installed sh
Cleaning up...
Traceback (most recent call last):
  File "test.py", line 20, in <module>
    importlib.import_module(req)
  File "/usr/local/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
ImportError: No module named sh

So we see that after installing the sh module, we cannot immediately import it. 因此,我们看到在安装sh模块之后,我们无法立即将其导入。 If we re-run the script, it will succeed, finding the sh installed in the previous run. 如果我们重新运行该脚本,它将成功,找到在上一次运行中安装的sh

What I find odd is that, we do not see the same behavior for vcstools ; 我发现奇怪的是,对于vcstools我们没有看到相同的行为; it installs and imports just fine in the same run. 它可以在同一运行中很好地安装和导入。 What gives? 是什么赋予了? Is there something special about sh ? sh有什么特别之处吗?

Here is the full output from the second run. 这是第二次运行的完整输出。 Notice that we pick up sh from the last run, we then install vcstools and import it without error: 请注意,我们从上一次运行中拾取了sh ,然后安装vcstools 并将其导入而没有错误:

checking for sh...found
checking for vcstools...missing!
Installing vcstools...
Downloading/unpacking vcstools
  Downloading vcstools-0.1.33.tar.gz
  Running setup.py egg_info for package vcstools

Downloading/unpacking pyyaml (from vcstools)
  Downloading PyYAML-3.11.tar.gz (248Kb): 248Kb downloaded
  Running setup.py egg_info for package pyyaml

    skipping 'ext/_yaml.c' Cython extension (up-to-date)
Requirement already satisfied (use --upgrade to upgrade): python-dateutil in /usr/local/lib/python2.7/site-packages (from vcstools)
Installing collected packages: vcstools, pyyaml
  Running setup.py install for vcstools

  Running setup.py install for pyyaml
    checking if libyaml is compilable
    cc -pthread -fno-strict-aliasing -O2 -pipe -DNDEBUG -O2 -pipe -fPIC -fPIC -I/usr/local/include/python2.7 -c build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c -o build/temp.openbsd-5.5-amd64-2.7/check_libyaml.o
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:2:18: error: yaml.h: No such file or directory
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c: In function 'main':
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:5: error: 'yaml_parser_t' undeclared (first use in this function)
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:5: error: (Each undeclared identifier is reported only once
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:5: error: for each function it appears in.)
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:5: error: expected ';' before 'parser'
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:6: error: 'yaml_emitter_t' undeclared (first use in this function)
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:6: error: expected ';' before 'emitter'
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:8: error: 'parser' undeclared (first use in this function)
    build/temp.openbsd-5.5-amd64-2.7/check_libyaml.c:11: error: 'emitter' undeclared (first use in this function)

    libyaml is not found or a compiler error: forcing --without-libyaml
    (if libyaml is installed correctly, you may need to
     specify the option --include-dirs or uncomment and
     modify the parameter include_dirs in setup.cfg)

    skipping 'ext/_yaml.c' Cython extension (up-to-date)
Successfully installed vcstools pyyaml
Cleaning up...
(<module 'sh' (built-in)>, <module 'vcstools' from '/home/edd/.local/lib/python2.7/site-packages/vcstools/__init__.pyc'>)

This is Python-2.7 on OpenBSD. 这是OpenBSD上的Python-2.7。

Cheers 干杯

EDIT: Just noticed the new_mods line is redundant. 编辑:只是注意到new_mods行是多余的。 I will leave it there so the line numbers in the output are not skewed. 我将其保留在那里,这样输出中的行号就不会倾斜。

This probably is the first package you try to install into ~/.local/... - that means that ~/.local/... is only created with pip.main(['install', '--user', req]) 这可能是您尝试安装到~/.local/...的第一个软件包-这意味着~/.local/...仅使用pip.main(['install', '--user', req])

If ~/.local does not exist upon python startup, it is not added to sys.path, and the module will not be found (not even with importlib.invalidate_caches() ). 如果python启动时〜/ .local不存在,则不会将其添加到sys.path中,也将找不到该模块(即使使用importlib.invalidate_caches()也不存在)。

So you have to add that path into sys.path, or reload sys.path as indicated in this answer , then it will work... 因此,您必须将该路径添加到sys.path中,或按照此答案所示重新加载sys.path,然后它将起作用...

My solution: 我的解决方案:

import pip
import importlib
import sys

def pip_import(module_name, pip_package=None):
    try:
        mod = importlib.import_module(module_name)
    except ImportError:
        pip.main(['install', '--user', pip_package if pip_package else module_name])

        # If the install path did not exist on start up it has 
        # to be added to sys.path
        if not pip.locations.user_site in sys.path:
            sys.path.append(pip.locations.user_site)

        mod = importlib.import_module(module_name)

    # Add the imported module to the global namespace so it
    # can be used just like `import module`
    globals()[module_name] = mod

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

相关问题 导入模块,但解释器无法识别该模块python中的功能 - Importing a module but the interpreter is not recognizing the function in that module python 导入Python模块只能在解释器中运行,而不能在脚本中运行 - Importing Python module works in interpreter but not script Pycharm 项目解释器中没有标准 Python 模块? - Standard Python module not available in Pycharm project interpreter? python中的导入模块在解释器和脚本文件中提供了两个不同的输出 - importing module in python giving two different output in interpreter and script file 解释器启动期间不会自动导入站点模块 - The site module is not automatically imported during interpreter startup 导入模块在 Jupyter 笔记本和解释器中的行为不同? - importing module behaves differently in Jupyter notebook and Interpreter? 如何在 Virtualenv 的解释器启动时执行 Python 代码? - How to execute Python Code on Interpreter Startup in Virtualenv? 导入模块时,如何指定解释器来编译模块? - When importing a module, how do I specify an interpreter to compile the module? 导入numpy使用解释器,但不完全使用python中的pyscripter - importing numpy works with interpreter but not fully with pyscripter in python OSX更改默认解释器Python(导入matplotlib) - OSX Change Default Interpreter Python (importing matplotlib)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM