私は書きたいと思います:
try:
import foo
except ImportError:
install_the_module("foo")
このシナリオを処理する推奨/慣用的な方法は何ですか?
多くのスクリプトが、不足しているモジュールについてユーザーに通知し、(場合によっては)インストール方法に関する指示を提供するエラーまたは警告を出力するだけです。ただし、モジュールが PyPI で利用可能であることがわかっている場合は、インストールプロセスを開始するためにこれをさらに一歩進めることができます。番号?
インストールの問題はソースコードの対象ではありません!
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.""")
ユーザーのインストールに触れないでください。
反対票を投じるリスクを冒して、簡単なハックを提案したいと思います。 私は完全に受け入れられた答えを持っている依存関係は外部で管理されるべきであることに注意してください。
ただし、自己完結型のように振る舞うものを絶対にハックする必要がある場合は、次のようなものを試すことができます。
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
これが私がまとめた解決策です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では、元の回答のコードを使用した方が良い場合があります。