#!/usr/bin/env python """ The idea is to try and import a package and if the import fails then try to download and install the package. Yes, you can put the package as a dependency in your pip config for your code. This is intended for the case when you have a bunch of python libs in some shared repository in your organization. People check the code out and expect it to run but it has third party dependencies. There is no install step for your code, per se. Tasks.. - tcl/tk ui when cmd line not available (etc wxpython, qt and so on if available). - batch require? ask only once for a list of packages """ import importlib import pip import sys class IRequireUI: @classmethod def is_available(cls): pass def query_do_install(self, package_name): return False def announce(self, msg): pass class NeverInstallUI(IRequireUI): @classmethod def is_available(cls): return True def query_do_install(self, package_name): return False class AlwaysInstallUI(IRequireUI): @classmethod def is_available(cls): return True def query_do_install(self, package_name): return True class CmdLineUI(IRequireUI): @classmethod def is_available(cls): return sys.stdin.isatty() def query_do_install(self, package_name): print("Package: %s needs to install package: %s" % (package_name, package_name)) print("Type 'y' to install this package or 'n' to exit") while True: response = raw_input().lower() if response in ("y", "yes"): return True elif response in ("n", "no"): return False else: print("Please enter 'yes' or 'no' to proceed.") return def announce(self, msg): print(msg) _uis = [NeverInstallUI(), ] if CmdLineUI.is_available(): _uis.append(CmdLineUI()) # _verbose = True _require_ui = _uis[-1] _install_as_root = False def require(package_name): """ Check if a package is installed. If it isn't ask the user whether we should download and install it. If they say yes do what they asked. """ # try and import the module try: importlib.import_module(package_name) except ImportError: # if it fails then we want to ask permission to install? if _require_ui.query_do_install(package_name): args = ["install" ] if not _install_as_root: if _verbose: _require_ui.announce("Installing for user!"); args.append("--user") args.append(package_name) try: pip.main(args) except error: _require_ui.announce("Install of %s failed!" % package_name); return False else: if _verbose: _require_ui.announce("Install of %s succeeded." % package_name); return True else: _require_ui.announce("User declined to install package: %s" % package_name) return False else: # if it succeeds we don't have to do any work if _verbose: _require_ui.announce("Package %s is installed." % package_name) return True return True if __name__ == "__main__": # proposition is that these would be called as pip.require("foo") require("redis") require("logist")