Подтвердить что ты не робот

Как автоматически установить отсутствующие модули python?

Я хотел бы иметь возможность написать:

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

Каков рекомендуемый/идиоматический способ справиться с этим сценарием?

Я видел, что многие скрипты просто печатают сообщение об ошибке или предупреждают пользователя о недостающем модуле и (иногда) предоставляют инструкции по установке. Однако, если я знаю, что модуль доступен на PyPI, то я, безусловно, сделаю шаг вперед инициировать процесс установки. Нет?

4b9b3361

Ответ 1

Проблемы с установкой не относятся к исходному коду!

Вы правильно определяете свои зависимости внутри setup.py вашего пакета используя конфигурацию install_requires.

Что нужно сделать... установить что-то в результате ImportError это странно и страшно. Не делайте этого.

Ответ 2

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

Не прикасайтесь к установке пользователя.

Ответ 3

Здесь решение, которое я собрал, которое я называю pyInstall.py. Он фактически проверяет, установлен ли модуль, а не полагается на ImportError (он просто выглядит более чистым, на мой взгляд, для обработки этого с помощью if, а не try/except).

Я использовал его под версиями 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 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 used for SSH.
installIfNeeded("fabric", notes = " (ssh)", log = log)

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

Изменить. Более кросс-платформенный способ получения 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 это может быть лучше использовать код в моем первоначальном ответе.

Ответ 4

Рискуя отрицательные голоса, я хотел бы предложить быстрый взлом. Обратите внимание, что Я полностью на борту с принятым ответом, что зависимости должны управляться извне.

Но для ситуаций, когда вам абсолютно необходимо взломать что-то, что действует как автономное, вы можете попробовать что-то вроде ниже:

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