Как автоматически установить отсутствующие модули python?
Я хотел бы иметь возможность написать:
try:
import foo
except ImportError:
install_the_module("foo")
Каков рекомендуемый/идиоматический способ справиться с этим сценарием?
Я видел, что многие скрипты просто печатают сообщение об ошибке или предупреждают пользователя о недостающем модуле и (иногда) предоставляют инструкции по установке. Однако, если я знаю, что модуль доступен на PyPI, то я, безусловно, сделаю шаг вперед инициировать процесс установки. Нет?
Ответы
Ответ 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