Source code for pymyinstall.installhelper.module_install

"""


Various function to install various python module from various location.

"""
from __future__ import print_function

import sys
import re
import platform
import os
import time
import importlib
import datetime
from .install_cmd_helper import python_version, run_cmd, unzip_files, get_pip_program, get_file_modification_date, get_wheel_version
from .install_memoize import install_memoize

if sys.version_info[0] == 2:
    from urlparse import urlsplit
    import urllib2 as urllib_request
    import urllib2 as urllib_error
    import xmlrpclib as xmlrpc_client
    from codecs import open
    from StringIO import StringIO
else:
    from urllib.parse import urlsplit
    import urllib.request as urllib_request
    import urllib.error as urllib_error
    import importlib.util
    import xmlrpc.client as xmlrpc_client
    from io import StringIO


[docs]class MissingPackageOnPyPiException(Exception): """ raised when a package is not found on pipy """ pass
[docs]class MissingInstalledPackageException(Exception): """ raised when a package is not installed """ pass
[docs]class AnnoyingPackageException(Exception): """ raised when a package is not on pypi """ pass
[docs]class MissingVersionOnPyPiException(Exception): """ raised when a version is missing on pipy """ pass
@install_memoize def get_page_wheel(page): """ get the page :param page: location :return: page content """ req = urllib_request.Request( page, headers={ 'User-agent': 'Mozilla/5.0'}) u = urllib_request.urlopen(req) text = u.read() u.close() text = text.decode("utf8") text = text.replace("&quot;", "'") text = text.replace("&#8209;", "-") return text @install_memoize def get_module_version(module, use_cmd=False): """ return a dictionary { module:version } :param module: unused, None :param use_cmd: use command line :return: dictionary """ if use_cmd: prog = get_pip_program() cmd = prog + " list" out, err = run_cmd(cmd, wait=True, do_not_log=True) else: kout = sys.stdout kerr = sys.stderr sys.stdout = StringIO() sys.stderr = StringIO() import pip pip.main(["list"]) out = sys.stdout.getvalue() err = sys.stderr.getvalue() sys.stdout = kout sys.stderr = kerr if err is not None and len(err) > 0: if len(err.split("\n")) > 3 or \ "You should consider upgrading via the 'pip install --upgrade pip' command." not in err: raise Exception("unable to run, #lines {0}\nCMD:\n{3}\nERR:\n{1}\nOUT:\n{2}".format( len(err.split("\n")), err, out, cmd)) lines = out.split("\n") res = {} for line in lines: if "(" in line: spl = line.split() if len(spl) == 2: a = spl[0] b = spl[1].strip(" \n\r") res[a] = b.strip("()") al = a.lower() if al != a: res[al] = res[a] return res def _get_pypi_version_memoize(f): memo = {} def helper(module_name, full_list=False, url="http://pypi.python.org/pypi"): key = module_name, full_list, url if key not in memo: memo[key] = f(module_name, full_list, url) return memo[key] return helper @_get_pypi_version_memoize def get_pypi_version(module_name, full_list=False, url="http://pypi.python.org/pypi"): """ returns the version of a package on pypi, we skip alpha, beta or dev version :param module_name: module name :param url: pipy server :param full_list: results as a list or return the last stable version :return: version (str or list) See also `installing_python_packages_programatically.py <https://gist.github.com/rwilcox/755524>`_, `pkgtools.pypi: PyPI interface <http://pkgtools.readthedocs.org/en/latest/pypi.html>`_. """ pypi = xmlrpc_client.ServerProxy(url) tried = [module_name] available = pypi.package_releases(module_name, True) if available is None or len(available) == 0: tried.append(module_name.capitalize()) available = pypi.package_releases(tried[-1], True) if available is None or len(available) == 0: tried.append(module_name.replace("-", "_")) available = pypi.package_releases(tried[-1], True) if available is None or len(available) == 0: tried.append(module_name.replace("_", "-")) available = pypi.package_releases(tried[-1], True) if available is None or len(available) == 0: tried.append(module_name.lower()) available = pypi.package_releases(tried[-1], True) if available is None or len(available) == 0: ml = module_name.lower() if ml == "markupsafe": tried.append("MarkupSafe") available = pypi.package_releases(tried[-1], True) elif ml == "flask-sqlalchemy": tried.append("Flask-SQLAlchemy") available = pypi.package_releases(tried[-1], True) elif ml == "apscheduler": tried.append("APScheduler") available = pypi.package_releases(tried[-1], True) elif ml == "datashape": tried.append("DataShape") available = pypi.package_releases(tried[-1], True) elif ml == "pycontracts": tried.append("PyContracts") available = pypi.package_releases(tried[-1], True) elif ml == "pybrain": tried.append("PyBrain") available = pypi.package_releases(tried[-1], True) elif ml == "jsanimation": # github tried.append("JSAnimation") available = ["-"] elif module_name in ModuleInstall.annoying_modules: raise AnnoyingPackageException(module_name) if available is None or len(available) == 0: raise MissingPackageOnPyPiException("tried:\n" + "\n".join(tried)) if full_list: return available for a in available: spl = a.split(".") if len(spl) in (2, 3): last = spl[-1] if "a" not in last and "b" not in last and "dev" not in last: return a else: return a raise MissingVersionOnPyPiException( "{0}\nversion:\n{1}".format(module_name, "\n".join(available)))
[docs]class ModuleInstall: """ defines the necessary information for a module .. _le-module_install-l235: .. _le-InstallationfromGitHub: **Example: Installation from GitHub** .. example(Installation from GitHub;;le-module_install-l235). :: ModuleInstall("pyquickhelper", "github", "sdpython").install(temp_folder="temp") .. endexample. """ allowedKind = ["pip", "github", "exe", "exe_xd", "wheel", "wheel_xd"] expKPage = "onclick=.javascript:dl[(]([,\\[\\]0-9]+) *, *.([0-9&;@?=:A-Zgtl]+).[)]. title(.+)?.>(.+?win32-py3.3.exe)</a>" expKPageWhl = "onclick=.javascript:dl[(]([,\\[\\]0-9]+) *, *.([0-9&;@?=:A-Zgtl]+).[)]. title(.+)?.>(.+?-cp33-none-win32.whl)</a>" exeLocation = "http://www.lfd.uci.edu/~gohlke/pythonlibs/" exeLocationXd = "http://www.xavierdupre.fr/enseignement/setup/" gitexe = r"C:\Program Files (x86)\Git" annoying_modules = {"pygame", "liblinear", "mlpy", "VideoCapture", "libsvm", "opencv_python", "scikits.cuda", "NLopt"} @staticmethod
[docs] def is_annoying(module_name): """ some modules are not available on pipy """ return module_name in ModuleInstall.annoying_modules
[docs] def __init__(self, name, kind="pip", gitrepo=None, mname=None, fLOG=print, version=None, script=None, index_url=None, deps=None, purpose=None, usage=None): """ constructor :param name: name :param kind: kind of installation (*pip*, *github*, *wheel*) :param gitrepo: github repository (example: sdpython) :param mname: sometimes, the module name is different from its official name :param version: to install a specific version (None for the latest) :param fLOG: logging function :param script: some extensions are not a module but an application (such as ``spyder``), the class will check this script is available :param deps: overwrite deps parameters when installing the module :param index_url: to get the package from a custom pypi server :param purpose: purpose of the module :param usage: main usage for the module """ if kind != "pip" and version is not None: raise NotImplementedError( "version can be only specified if kind=='pip'") self.name = name self.kind = kind self.gitrepo = gitrepo self.version = version self.mname = mname self.script = script self.index_url = index_url self.deps = deps self.purpose = purpose self.usage = usage if self.kind not in ModuleInstall.allowedKind: raise Exception( "unable to interpret kind {0}, it should be in {1}".format( kind, ",".join( ModuleInstall.allowedKind))) if self.kind == "github" and self.gitrepo is None: raise Exception("gitrepo cannot be empty") self.fLOG = fLOG
[docs] def copy(self, version=None): """ copy the module, if version is not None, change the version number :param version: version number or None for unchanged :return: :class:`ModuleInstall <pymyinstall.installhelper.module_install.ModuleInstall>` .. versionadded:: 1.0 """ mod = ModuleInstall(**self.as_dict()) if version is not None: mod.version = version return mod
[docs] def as_dict(self): """ returns the members in a dictionary :return: dictionary """ return dict(name=self.name, kind=self.kind, gitrepo=self.gitrepo, version=self.version, mname=self.mname, script=self.script, deps=self.deps, index_url=self.index_url, purpose=self.purpose, usage=self.usage)
[docs] def __cmp__(self, o): """ to sort modules :param o: other module :return: -1, 0, 1 """ def compare(v1, v2): if v1 is None: if v2 is None: return 0 else: return 1 else: if v2 is None: return -1 else: if v1 < v2: return -1 elif v1 > v2: return 1 else: return 0 r = compare(self.usage, o.usage) if r != 0: return r r = compare(self.name.lower(), o.name.lower()) return r
[docs] def __lt__(self, o): """ overload operator ``<`` :param o: other module :return: boolean """ return self.__cmp__(o) < 0
@staticmethod
[docs] def clear_cache(): """ clear the local cache to get wheel link """ if os.path.exists(ModuleInstall._page_cache_html): os.remove(ModuleInstall._page_cache_html)
@property def Purpose(self): """ returns the comment """ return "-" if self.purpose is None else self.purpose @property def Script(self): """ returns the script to run if the extension is an application and not a module """ exe = os.path.split(sys.executable)[0] if sys.platform.startswith("win"): sc = os.path.join(exe, "Scripts", self.script) else: sc = os.path.join(exe, "Scripts", os.path.splitext(self.script)[0]) return sc
[docs] def __str__(self): """ usual """ if self.script is None: return "{0}:{1}:import {2}:v{3}".format( self.name, self.kind, self.ImportName, self.version) else: return "{0}:{1}:{2}:v{3}".format(self.name, self.kind, self.Script, self.version)
@property def ImportName(self): """ return the import name """ if self.mname is not None: return self.mname if self.name.startswith("python-"): return self.name[len("python-"):] else: return self.name
[docs] def IsInstalled(self): """ checks if a module is installed """ if self.script is None: try: if "." in self.ImportName: raise ImportError(self.ImportName) if sys.version_info[0] == 2: r = importlib.import_module(self.ImportName) return r else: r = importlib.util.find_spec(self.ImportName) return r is not None return r is not None except ImportError: txt = "import {0}".format(self.ImportName) try: exec(txt) return True except Exception: return False else: return os.path.exists(self.Script)
_page_cache_html = os.path.join( os.path.abspath(os.path.split(__file__)[0]), "page.html")
[docs] def unzipfiles(self, zipf, whereTo): """ unzip files from a zip archive :param zipf: archive :param whereTo: destination folder :return: list of unzipped files """ return unzip_files(zipf, whereTo, self.fLOG)
[docs] def download( self, temp_folder=".", force=False, unzipFile=True, file_save=None, deps=False): """ download the module without installation :param temp_folder: destination :param force: force the installation even if already installed :param unzipFile: if it can be unzipped, it will be (for github, mostly) :param file_save: for debug purposes, do not change it unless you know what you are doing :param deps: download the dependencies too (only available for pip) :return: downloaded files .. versionchanged:: 0.9 Parameter *deps* was added, the function now downloads a module using pip. .. versionchanged:: 1.0 *deps* is overwritten by *self.deps* if not None """ kind = self.kind deps = deps if self.deps is None else self.deps if kind == "pip": # see https://pip.pypa.io/en/latest/reference/pip_install.html # we use pip install <package> --download=temp_folder pp = get_pip_program() cmd = pp + ' install {0}'.format(self.name) if self.version is not None: cmd += "=={0}".format(self.version) if " " in temp_folder: raise FileNotFoundError( "no space allowed in folders: [" + temp_folder + "]") if deps: cmd += ' --download={0}'.format(temp_folder) else: cmd += ' --download={0} --no-deps'.format(temp_folder) if self.index_url is not None: slash = '' if self.index_url.endswith('/') else '/' cmd += ' --no-cache-dir --index={0}{1}simple/'.format( self.index_url, slash) parsed_uri = urlsplit(self.index_url) cmd += " --trusted-host " + parsed_uri.hostname out, err = run_cmd( cmd, wait=True, do_not_log=True, fLOG=self.fLOG) if "Successfully downloaded" not in out: raise Exception( "unable to download " + str(self) + "\nCMD:\n" + cmd + "\nOUT:\n" + out + "\nERR:\n" + err) else: lines = out.split("\n") for line in lines: if line.strip().startswith("Saved "): return line.split("Saved")[-1].strip() elif line.strip().startswith("File was already downloaded"): return line.split("File was already downloaded")[-1].strip() raise FileNotFoundError( "unable to find downloaded file " + str(self) + "\nCMD:\n" + cmd + "\nOUT:\n" + out + "\nERR:\n" + err) elif kind in ("wheel", "wheel_xd"): ver = python_version() if ver[0] != "win32": # nothing to download, you should use pip return None else: if kind == "wheel": url, whl = self.get_exewheel_url_link( file_save=file_save, wheel=True) else: url, whl = self.get_exewheel_url_link_xd( file_save=file_save, wheel=True) whlname = os.path.join(temp_folder, whl) exi = os.path.exists(whlname) if force or not exi: self.fLOG("downloading", whl) req = urllib_request.Request( url, headers={ 'User-agent': 'Mozilla/5.0'}) u = urllib_request.urlopen(req) text = u.read() u.close() if not os.path.exists(temp_folder): os.makedirs(temp_folder) self.fLOG("writing", whl) with open(whlname, "wb") as f: f.write(text) return whlname elif kind == "github": outfile = os.path.join(temp_folder, self.name + ".zip") if force or not os.path.exists(outfile): zipurl = "https://github.com/{1}/{0}/archive/master.zip".format( self.name, self.gitrepo) self.fLOG("downloading", zipurl) try: req = urllib_request.Request( zipurl, headers={ 'User-agent': 'Mozilla/5.0'}) u = urllib_request.urlopen(req) text = u.read() u.close() except urllib_error.HTTPError as e: raise Exception( "unable to get archive from: " + zipurl) from e if not os.path.exists(temp_folder): os.makedirs(temp_folder) u = open(outfile, "wb") u.write(text) u.close() if unzipFile: self.fLOG("unzipping ", outfile) files = self.unzipfiles(outfile, temp_folder) return files else: return outfile elif kind in ("exe", "exe_xd"): ver = python_version() if ver[0] != "win32": raise Exception( "this option is not available on other systems than Windows, version={0}".format(ver)) else: url, exe = self.get_exewheel_url_link( file_save=file_save) if kind == "exe" else self.get_exewheel_url_link_xd( file_save=file_save) self.fLOG("downloading", exe) req = urllib_request.Request( url, headers={ 'User-agent': 'Mozilla/5.0'}) u = urllib_request.urlopen(req) text = u.read() u.close() if not os.path.exists(temp_folder): os.makedirs(temp_folder) exename = os.path.join(temp_folder, exe) self.fLOG("writing", exe) with open(exename, "wb") as f: f.write(text) return exename else: raise ImportError( "unknown kind: {0} for module {1}".format( kind, self.name))
[docs] def Install(self, *l, **p): """ :meth:`install <pymyinstall.installhelper.module_install.ModuleInstall.install>` """ self.install(*l, **p)
[docs] def get_pypi_version(self, url='http://pypi.python.org/pypi'): """ returns the version of a package on pypi :param url: pipy server :return: version See also `installing_python_packages_programatically.py <https://gist.github.com/rwilcox/755524>`_, `pkgtools.pypi: PyPI interface <http://pkgtools.readthedocs.org/en/latest/pypi.html>`_. """ if url == 'http://pypi.python.org/pypi': # we use a function which caches the result return get_pypi_version(self.name) else: pypi = xmlrpc_client.ServerProxy(url) available = pypi.package_releases(self.name) if available is None or len(available) == 0: available = pypi.package_releases(self.name.capitalize()) if (available is None or len(available) == 0) and self.mnane is not None: available = pypi.package_releases(self.mname) if available is None: raise MissingPackageOnPyPiException( "; ".join([self.name, self.name.capitalize(), self.mname])) return available[0]
@staticmethod
[docs] def numeric_version(vers): """ convert a string into a tuple with numbers whever possible :param vers: string :return: tuple """ if isinstance(vers, tuple): return vers spl = vers.split(".") r = [] for _ in spl: try: i = int(_) r.append(i) except: r.append(_) return tuple(r)
[docs] def get_pypi_numeric_version(self): """ returns the version of a package in pypi :return: tuple """ vers = self.get_pypi_version() if vers is None: return None return ModuleInstall.numeric_version(vers)
[docs] def get_installed_version(self): """ return the version of the installed package :return: version """ vers = get_module_version(None) if self.name in vers: return vers[self.name] cap = self.name.capitalize() if cap in vers: return vers[cap] cap = self.name.replace("-", "_") if cap in vers: return vers[cap] if self.mname is not None and self.mname in vers: return vers[self.mname] return None
[docs] def is_installed(self): """ tells if a module is installed """ return self.get_installed_version() is not None
[docs] def get_installated_numeric_version(self): """ returns the version as number (not string) :return: tuple """ vers = self.get_installed_version() if vers is None: return None return ModuleInstall.numeric_version(vers)
[docs] def has_update(self): """ tells if the package has a newer version on pipy :return: boolean """ if ModuleInstall.is_annoying(self.name): return False vers = self.get_installated_numeric_version() if self.version is None: pypi = self.get_pypi_numeric_version() return ModuleInstall.compare_version(pypi, vers) > 0 else: num = ModuleInstall.numeric_version(self.version) return ModuleInstall.compare_version(num, vers) > 0
@staticmethod
[docs] def compare_version(num, vers): """ compare two versions :param num: first version :param vers: second version :return: -1, 0, 1 """ if num is None: if vers is None: return 0 else: return 1 if vers is None: return -1 if not isinstance(vers, tuple): vers = ModuleInstall.numeric_version(vers) if not isinstance(num, tuple): num = ModuleInstall.numeric_version(num) if len(num) == len(vers): for a, b in zip(num, vers): if isinstance(a, int) and isinstance(b, int): if a < b: return -1 elif a > b: return 1 else: a = str(a) b = str(b) if a < b: return -1 elif a > b: return 1 return 0 else: if len(num) < len(vers): num = num + (0,) * (len(vers) - len(num)) return ModuleInstall.compare_version(num, vers) else: vers = vers + (0,) * (len(num) - len(vers)) return ModuleInstall.compare_version(num, vers)
[docs] def install(self, force_kind=None, force=False, temp_folder=".", log=False, options=None, deps=False): """ install the package :param force_kind: overwrite self.kind :param force: force the installation even if already installed :param temp_folder: folder where to download the setup :param log: display logs or not :param options: other options to add to the command line (see below) in a list :param deps: install the dependencies too (only available for pip) :return: boolean The options mentioned in parameter ``options`` are described here: `pip install <http://www.pip-installer.org/en/latest/usage.html>`_ or `setup.py options <http://docs.python.org/3.4/install/>`_ if you installing a module from github. .. versionchanged:: 1.0 *deps* is overwritten by *self.deps* if not None """ if not force and self.IsInstalled(): return True deps = deps if self.deps is None else self.deps if options is None: options = [] self.fLOG("installation of ", self) kind = force_kind if force_kind is not None else self.kind ret = None if kind == "pip": pp = get_pip_program() cmd = pp + " install {0}".format(self.name) if self.version is not None: cmd += "=={0}".format(self.version) if len(options) > 0: cmd += " " + " ".join(options) if not deps: cmd += ' --no-deps' if self.index_url is not None: slash = '' if self.index_url.endswith('/') else '/' cmd += ' --no-cache-dir --index={0}{1}simple/'.format( self.index_url, slash) else: cmd += " --cache-dir={0}".format(temp_folder) out, err = run_cmd( cmd, wait=True, do_not_log=not log, fLOG=self.fLOG) if "No distributions matching the version" in out: raise Exception( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) elif "Testing of typecheck-decorator passed without failure." in out: ret = True elif "Successfully installed" not in out: if "error: Unable to find vcvarsall.bat" in out: url = "http://www.xavierdupre.fr/blog/2013-07-07_nojs.html" raise Exception( "unable to install " + str(self) + "\nread:\n" + url + "OUT:\n" + out + "\nERR:\n" + err) if "Requirement already satisfied" not in out: raise Exception( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) else: ret = True elif kind in ("wheel", "wheel_xd"): ver = python_version() if ver[0] != "win32": ret = self.install("wheel") whlname = self.name ret = True else: whlname = self.download( temp_folder=temp_folder, force=force, unzipFile=True) vers = self.get_installated_numeric_version() ret = True if vers is not None: whlvers = ModuleInstall.numeric_version( get_wheel_version(whlname)) if ModuleInstall.compare_version(vers, whlvers) >= 0: self.fLOG("skipping, no newer version {0} <= {1}: whl= {2}".format( whlvers, vers, whlname)) ret = False if ret: self.fLOG("installing", os.path.split(whlname)[-1]) pip = get_pip_program() cmd = pip + " install {0}".format(whlname) if self.version is not None: cmd += "=={0}".format(self.version) if len(options) > 0: opts = [_ for _ in options] if len(opts): cmd += " " + " ".join(opts) out, err = run_cmd( cmd, wait=True, do_not_log=not log, fLOG=self.fLOG) if "No distributions matching the version" in out: raise Exception( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) elif "Testing of typecheck-decorator passed without failure." in out: ret = True elif "Successfully installed" not in out: if "error: Unable to find vcvarsall.bat" in out: url = "http://www.xavierdupre.fr/blog/2013-07-07_nojs.html" raise Exception( "unable to install " + str(self) + "\nread:\n" + url + "OUT:\n" + out + "\nERR:\n" + err) if "Requirement already satisfied" not in out: raise Exception( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) else: ret = True elif kind == "github": # the following code requires admin rights # if python_version()[0].startswith("win") and kind == "git" and not os.path.exists(ModuleInstall.gitexe) : # raise FileNotFoundError("you need to install github first: see http://windows.github.com/") # if python_version()[0].startswith("win"): # os.chdir(os.path.join(ModuleInstall.gitexe,"bin")) # cmd = pip + " install -e # git://github.com/{0}/{1}-python.git#egg={1}".format(self.gitrepo, # self.name) files = self.download( temp_folder=temp_folder, force=force, unzipFile=True) setu = [_ for _ in files if _.endswith("setup.py")] if len(setu) == 0: raise Exception( "unable to find setup.py for module " + self.name) elif len(setu) > 1: setu = [(len(_), _) for _ in setu] setu.sort() if setu[0][0] == setu[1][0]: raise Exception( "more than one setup.py for module " + self.name + "\n" + "\n".join( str(_) for _ in setu)) else: self.fLOG("warning: more than one setup: " + str(setu)) setu = [setu[0][1]] setu = os.path.abspath(setu[0]) self.fLOG("install ", setu[0]) cwd = os.getcwd() os.chdir(os.path.split(setu)[0]) cmd = "{0} setup.py install".format( sys.executable.replace( "pythonw.exe", "python.exe")) if len(options) > 0: cmd += " " + " ".join(*options) out, err = run_cmd( cmd, wait=True, do_not_log=not log, fLOG=self.fLOG) os.chdir(cwd) if "Successfully installed" not in out and "install C" not in out: if "Finished processing dependencies" not in out: raise Exception( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) else: self.fLOG( "warning: ``Successfully installed`` or ``install C`` not found") if "Permission denied" in out: raise PermissionError( "unable to install " + str(self) + "\nOUT:\n" + out + "\nERR:\n" + err) ret = True elif kind == "exe": ver = python_version() if ver[0] != "win32": ret = self.install("pip") else: exename = self.download( temp_folder=temp_folder, force=force, unzipFile=True) self.fLOG("executing", os.path.split(exename)[-1]) out, err = run_cmd( exename + " /s /qn /SILENT", wait=True, do_not_log=not log, fLOG=self.fLOG) ret = len(err) == 0 elif kind == "exe_xd": ver = python_version() if ver[0] != "win32": ret = self.install("pip") else: exename = self.download( temp_folder=temp_folder, force=force, unzipFile=True) self.fLOG("executing", os.path.split(exename)[-1]) out, err = run_cmd( exename + " /s /qn", wait=True, do_not_log=not log, fLOG=self.fLOG) ret = len(err) == 0 else: raise ImportError( "unknown kind: {0} for module {1}".format( kind, self.name)) # at this stage, there is a bug, for some executable, the execution # takes longer than expected # if not self.IsInstalled() : # raise Exception("unable to install module: {0}, str:{1}".format(self.name, self)) if ret is not None and ret and self.script is not None: if sys.platform.startswith("win"): # here, we have to wait until the script is installed ti = 0 while not self.IsInstalled(): time.sleep(0.5) ti += 0.5 if ti > 60: self.fLOG( "wait for the end of execution of ", self.name) ti = 0 # we add set path=%path%;PYTHONPATH with open(self.Script, "r") as f: full = f.read() exe = os.path.split(sys.executable)[0] cmd = "set path=%path%;{0}".format(exe) if cmd not in full: self.fLOG("add {0} to {1}".format(cmd, self.Script)) with open(self.Script, "w") as f: if full.startswith("@echo off"): f.write( full.replace( "@echo off", "@echo off\n{0}".format(cmd))) else: f.write(cmd) f.write("\n") f.write(full) return ret
[docs] def update(self, force_kind=None, force=False, temp_folder=".", log=False, options=None, deps=False): """ update the package if necessary, we use ``pip install <module_name> --upgrade --no-deps``, :param force_kind: overwrite self.kind :param force: force the installation even if not need to update :param temp_folder: folder where to download the setup :param log: display logs or not :param options: others options to add to the command line (see below) an a list :param deps: download the dependencies too (only available for pip) :return: boolean The options mentioned in parameter ``options`` are described here: `pip install <http://www.pip-installer.org/en/latest/usage.html>`_ or `setup.py options <http://docs.python.org/3.4/install/>`_ if you installing a module from github. """ if ModuleInstall.is_annoying(self.name): return False if not self.is_installed(): raise MissingInstalledPackageException(self.name) if not force and not self.has_update(): return True self.fLOG("update of ", self) options = [] if options is None else list(options) for opt in ["--upgrade", "--no-deps"]: if opt not in options: if not deps or opt == "--no-deps": options.append(opt) res = self.install(force_kind=force_kind, force=True, temp_folder=temp_folder, log=log, options=options) return res