如何自动安装缺少的python模块? [重复]

时间:2023-01-12 19:52:59

This question already has an answer here:

这个问题在这里已有答案:

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?

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

4 个解决方案

#1


24  

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.

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

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

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

#2


19  

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.

请勿触摸用户的安装。

#3


9  

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

#4


5  

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

这是我放在一起的解决方案,我称之为pyInstall.py。它实际上检查模块是否已安装而不是依赖于ImportError(在我看来,它看起来更干净,用if而不是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.

我已经在版本2.6和2.7下使用了它...如果我不想将打印作为一个函数处理它可能会在旧版本中使用...而且我认为它可以在版本3.0+中工作但我已经从未尝试过。

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

另外,正如我在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])

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:

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

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.

这假设pip是/将安装在系统路径上。它在非Windows平台上往往非常可靠,但在Windows上,最好在原始答案中使用代码。

#1


24  

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.

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

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

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

#2


19  

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.

请勿触摸用户的安装。

#3


9  

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

#4


5  

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

这是我放在一起的解决方案,我称之为pyInstall.py。它实际上检查模块是否已安装而不是依赖于ImportError(在我看来,它看起来更干净,用if而不是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.

我已经在版本2.6和2.7下使用了它...如果我不想将打印作为一个函数处理它可能会在旧版本中使用...而且我认为它可以在版本3.0+中工作但我已经从未尝试过。

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

另外,正如我在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])

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:

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

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.

这假设pip是/将安装在系统路径上。它在非Windows平台上往往非常可靠,但在Windows上,最好在原始答案中使用代码。