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

时间:2011-05-25 07:24:05

标签: python module pypi

我希望能够写下:

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

处理此方案的推荐/惯用方法是什么?

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

4 个答案:

答案 0 :(得分:25)

安装问题不受源代码约束!

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

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

答案 1 :(得分:22)

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

请勿触摸用户的安装。

答案 2 :(得分:18)

冒险负面投票,我想建议一个快速的黑客。请注意我完全接受了已接受的答案,应该在外部管理相关性。

但是对于你绝对需要攻击像自包含的东西的情况,你可以尝试类似下面的东西:

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

答案 3 :(得分:6)

这是我放在一起的解决方案,我称之为pyInstall.py。它实际上会检查模块是否已安装而不是依赖于ImportError(在我看来,它只是看起来更清晰,以if而不是try / {{1}来处理})。

我在版本2.6和2.7下使用它...如果我不想将except作为一个函数来处理它可能适用于旧版本......我认为它可以在版本3.0+但我从未尝试过。

另外,正如我在print函数的注释中所述,我认为特定功能在OS X下不起作用。

getPip

以下是一些使用示例:

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])

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

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)

这假设from subprocess import Popen, PIPE finder = Popen(['where' if isWindows() else 'which', 'pip'], stdout = PIPE, stderr = PIPE) pipPath = finder.communicate()[0].strip() 将被安装在系统路径上。它在非Windows平台上往往非常可靠,但在Windows上,最好在原始答案中使用该代码。