我希望能够写:
try:
import foo
except ImportError:
install_the_module("foo")
处理这种情况的推荐/惯用方法是什么?
我见过很多脚本只是简单地打印错误或警告通知用户缺少模块,并且(有时)提供有关如何安装的说明。但是,如果我知道该模块在PyPI上可用,那么我肯定可以更进一步启动安装过程。不?
冒着反对票的风险,我想建议一个快速破解。请注意,我完全同意应在外部管理依赖项的答案。
但是对于你绝对需要破解一些像自包含的东西的情况,你可以尝试下面的方法:
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
安装问题不在源代码范围内!
setup.py
您可以使用配置在包中正确定义依赖项install_requires
。
这就是要走的路……安装一些东西ImportError
是一种奇怪和可怕的结果。不要这样做。
try:
import foo
except ImportError:
sys.exit("""You need foo!
install it from http://pypi.python.org/pypi/foo
or run pip install foo.""")
不要触摸用户的安装。
这是我放在一起的解决方案,我称之为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'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)
编辑:获取 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 上,使用我原始答案中的代码可能会更好。