如何自动安装缺少的 python 模块?

发布于 2024-11-09 17:32:30 字数 288 浏览 0 评论 0原文

我希望能够写:

try:
    import foo
except ImportError:
    install_the_module("foo")

处理这种情况的推荐/惯用方法是什么?

我见过很多脚本只是打印错误或警告,通知用户缺少模块,并(有时)提供有关如何安装的说明。但是,如果我知道该模块在 PyPI 上可用,那么我肯定可以更进一步安装过程。不?

I would like to be able to write:

try:
    import foo
except ImportError:
    install_the_module("foo")

What is the recommended/idiomatic way to handle this scenario?

I've seen a lot of scripts simply print an error or warning notifying the user about the missing module and (sometimes) providing instructions on how to install. However, if I know the module is available on PyPI, then I could surely take this a step further an initiate the installation process. No?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

亢潮 2024-11-16 17:32:30

冒着投反对票的风险,我想建议一个快速破解方法。请注意,我完全同意接受的答案:依赖关系应该在外部进行管理。

但对于您绝对需要破解类似自包含的东西的情况,您可以尝试如下所示:

import os

try:
  import requests
except ImportError:
  print "Trying to Install required module: requests\n"
  os.system('python -m pip install requests')
# -- above lines try to install requests module if not present
# -- if all went well, import required module again ( for global access)
import requests

Risking negative votes, I would like to suggest a quick hack. Please note that I'm completely on board with accepted answer that dependencies should be managed externally.

But for situations where you absolutely need to hack something that acts like self contained, you can try something like below:

import os

try:
  import requests
except ImportError:
  print "Trying to Install required module: requests\n"
  os.system('python -m pip install requests')
# -- above lines try to install requests module if not present
# -- if all went well, import required module again ( for global access)
import requests
韵柒 2024-11-16 17:32:30

安装问题不是源代码的主题!

您可以在包的 setup.py 中正确定义依赖项
使用 install_requires 配置。

这就是要走的路......由于 ImportError 安装某些东西
有点奇怪和可怕。不要这样做。

Installation issues are not subject of the source code!

You define your dependencies properly inside the setup.py of your package
using the install_requires configuration.

That's the way to go...installing something as a result of an ImportError
is kind of weird and scary. Don't do it.

嘿咻 2024-11-16 17:32:30
try:
    import foo
except ImportError:
    sys.exit("""You need foo!
                install it from http://pypi.python.org/pypi/foo
                or run pip install foo.""")

不要碰用户的安装。

try:
    import foo
except ImportError:
    sys.exit("""You need foo!
                install it from http://pypi.python.org/pypi/foo
                or run pip install foo.""")

Don't touch user's installation.

以为你会在 2024-11-16 17:32:30

这是我整理的解决方案,我将其称为pyInstall.py。它实际上检查模块是否已安装,而不是依赖 ImportError (在我看来,使用 if 而不是 try 来处理此问题看起来更干净/除外)。

我在版本 2.6 和 2.7 下使用过它...如果我不想将 print 作为函数处理...它可能会在旧版本中工作...并且我认为它会在旧版本中工作3.0+版本,但我从未尝试过。

另外,正如我在 getPip 函数的注释中指出的那样,我认为该特定函数无法在 OS X 下工作。

from __future__ import print_function
from subprocess import call

def installPip(log=print):
    """
    Pip is the standard package manager for Python. Starting with Python 3.4
    it's included in the default installation, but older versions may need to
    download and install it. This code should pretty cleanly do just that.
    """
    log("Installing pip, the standard Python Package Manager, first")
    from os     import remove
    from urllib import urlretrieve
    urlretrieve("https://bootstrap.pypa.io/get-pip.py", "get-pip.py")
    call(["python", "get-pip.py"])

    # Clean up now...
    remove("get-pip.py")

def getPip(log=print):
    """
    Pip is the standard package manager for Python.
    This returns the path to the pip executable, installing it if necessary.
    """
    from os.path import isfile, join
    from sys     import prefix
    # Generate the path to where pip is or will be installed... this has been
    # tested and works on Windows, but will likely need tweaking for other OS's.
    # On OS X, I seem to have pip at /usr/local/bin/pip?
    pipPath = join(prefix, 'Scripts', 'pip.exe')

    # Check if pip is installed, and install it if it isn't.
    if not isfile(pipPath):
        installPip(log)
        if not isfile(pipPath):
            raise("Failed to find or install pip!")
    return pipPath

def installIfNeeded(moduleName, nameOnPip=None, notes="", log=print):
    """ Installs a Python library using pip, if it isn't already installed. """
    from pkgutil import iter_modules

    # Check if the module is installed
    if moduleName not in [tuple_[1] for tuple_ in iter_modules()]:
        log("Installing " + moduleName + notes + " Library for Python")
        call([getPip(log), "install", nameOnPip if nameOnPip else moduleName])

以下是一些使用示例:

from datetime  import datetime
from pyInstall import installIfNeeded

# I like to have my messages timestamped so I can get an idea of how long they take.
def log(message):
    print(datetime.now().strftime("%a %b %d %H:%M:%S") + " - " + str(message))

# The name fabric doesn't really convey to the end user why the module is needed,
# so I include a very quick note that it's used for SSH.
installIfNeeded("fabric", notes = " (ssh)", log = log)

# SoftLayer is actually named softlayer on pip.
installIfNeeded("SoftLayer", "softlayer", log = log)

编辑:A获取 pipPath 的更多跨平台方法是:

from subprocess import Popen, PIPE
finder = Popen(['where' if isWindows() else 'which', 'pip'], stdout = PIPE, stderr = PIPE)
pipPath = finder.communicate()[0].strip()

这假设 pip 已/将安装在系统路径上。它在非 Windows 平台上往往相当可靠,但在 Windows 上,最好使用我原来答案中的代码。

Here's the solution I put together which I call pyInstall.py. It actually checks whether the module is installed rather than relying on ImportError (it just looks cleaner, in my opinion, to handle this with an if rather than a try/except).

I've used it under version 2.6 and 2.7... it would probably work in older versions if I didn't want to handle print as a function... and I think it'll work in version 3.0+ but I've never tried it.

Also, as I note in the comments of my getPip function, I don't think that particular function will work under OS X.

from __future__ import print_function
from subprocess import call

def installPip(log=print):
    """
    Pip is the standard package manager for Python. Starting with Python 3.4
    it's included in the default installation, but older versions may need to
    download and install it. This code should pretty cleanly do just that.
    """
    log("Installing pip, the standard Python Package Manager, first")
    from os     import remove
    from urllib import urlretrieve
    urlretrieve("https://bootstrap.pypa.io/get-pip.py", "get-pip.py")
    call(["python", "get-pip.py"])

    # Clean up now...
    remove("get-pip.py")

def getPip(log=print):
    """
    Pip is the standard package manager for Python.
    This returns the path to the pip executable, installing it if necessary.
    """
    from os.path import isfile, join
    from sys     import prefix
    # Generate the path to where pip is or will be installed... this has been
    # tested and works on Windows, but will likely need tweaking for other OS's.
    # On OS X, I seem to have pip at /usr/local/bin/pip?
    pipPath = join(prefix, 'Scripts', 'pip.exe')

    # Check if pip is installed, and install it if it isn't.
    if not isfile(pipPath):
        installPip(log)
        if not isfile(pipPath):
            raise("Failed to find or install pip!")
    return pipPath

def installIfNeeded(moduleName, nameOnPip=None, notes="", log=print):
    """ Installs a Python library using pip, if it isn't already installed. """
    from pkgutil import iter_modules

    # Check if the module is installed
    if moduleName not in [tuple_[1] for tuple_ in iter_modules()]:
        log("Installing " + moduleName + notes + " Library for Python")
        call([getPip(log), "install", nameOnPip if nameOnPip else moduleName])

Here are some usage examples:

from datetime  import datetime
from pyInstall import installIfNeeded

# I like to have my messages timestamped so I can get an idea of how long they take.
def log(message):
    print(datetime.now().strftime("%a %b %d %H:%M:%S") + " - " + str(message))

# The name fabric doesn't really convey to the end user why the module is needed,
# so I include a very quick note that it's used for SSH.
installIfNeeded("fabric", notes = " (ssh)", log = log)

# SoftLayer is actually named softlayer on pip.
installIfNeeded("SoftLayer", "softlayer", log = log)

Edit: A more cross-platform way of getting pipPath is:

from subprocess import Popen, PIPE
finder = Popen(['where' if isWindows() else 'which', 'pip'], stdout = PIPE, stderr = PIPE)
pipPath = finder.communicate()[0].strip()

This makes the assumption that pip is/will be installed on the system path. It tends to be pretty reliable on non-Windows platforms, but on Windows it may be better to use the code in my original answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文