Source code for pymyinstall.installhelper.install_venv_helper

"""
Helpers for virtualenv


:githublink:`%|py|5`
"""
from __future__ import print_function

import os
import sys
from .install_cmd_helper import run_cmd

if sys.version_info[0] == 2:
    FileNotFoundError = Exception


[docs]class VirtualEnvError(Exception): """ exception raised by the function implemented in this file :githublink:`%|py|18` """ pass
[docs]def build_venv_cmd(params, posparams): """ builds the command line for virtual env :param params: dictionary of parameters :param posparams: positional arguments :return: string :githublink:`%|py|29` """ import venv dir(venv) exe = sys.executable.replace("w.exe", "").replace(".exe", "") cmd = [exe, "-m", "venv"] for k, v in params.items(): if v is None: cmd.append("--" + k) else: cmd.append("--" + k + "=" + v) cmd.extend(posparams) return " ".join(cmd)
[docs]def create_virtual_env(where, symlinks=False, system_site_packages=False, clear=True, packages=None, fLOG=print, temp_folder=None): """ .. index:: virtual environment create a virtual environment :param where: location of this virtual environment :param symlinks: attempt to symlink rather than copy :param system_site_packages: Give the virtual environment access to the system site-packages dir :param clear: Delete the environment directory if it already exists. If not specified and the directory exists, an error is raised. :param packages: list of packages to install (it will install module :epkg:`pymyinstall`). :param fLOG: logging function :param temp_folder: temporary folder (to download module if needed), by default ``<where>/download`` :return: stand output .. exref:: :title: Create a virtual environment The following example creates a virtual environment. Packages can be added by specifying the parameter *package*. :: from pyquickhelper.pycode import create_virtual_env fold = "my_env" if not os.path.exists(fold): os.mkdir(fold) create_virtual_env(fold) :githublink:`%|py|75` """ fLOG("[pymy] create virtual environment at:", where) params = {} if symlinks: params["symlinks"] = None if system_site_packages: params["system-site-packages"] = None if clear: params["clear"] = None cmd = build_venv_cmd(params, [where]) out, err = run_cmd(cmd, wait=True, fLOG=fLOG) if len(err) > 0: raise VirtualEnvError( "unable to create virtual environement at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-G:\n{1}".format(out, err, where, cmd)) if sys.platform.startswith("win"): scripts = os.path.join(where, "Scripts") else: scripts = os.path.join(where, "bin") if not os.path.exists(scripts): files = "\n ".join(os.listdir(where)) raise FileNotFoundError( "unable to find {0}, content:\n {1}".format(scripts, files)) in_scripts = os.listdir(scripts) pips = [_ for _ in in_scripts if _.startswith("pip")] if len(pips) == 0: out += venv_install(where, "pip", fLOG=fLOG, temp_folder=temp_folder) in_scripts = os.listdir(scripts) pips = [_ for _ in in_scripts if _.startswith("pip")] if len(pips) == 0: raise FileNotFoundError( "unable to find pip in {0}, content:\n {1}".format(scripts, in_scripts)) if packages is not None and len(packages) > 0: fLOG("[pymy] install packages in:", where) packages = [_ for _ in packages if _ != "pymyinstall" and _ != "pip"] if len(packages) > 0: out += venv_install(where, packages, fLOG=fLOG, temp_folder=temp_folder) return out
[docs]def venv_install(venv, packages, fLOG=print, temp_folder=None): """ install a package or a list of packages in a virtual environment :param venv: location of the virtual environment :param packages: a package (str) or a list of packages(list[str]) :param fLOG: logging function :param temp_folder: temporary folder (to download module if needed), by default ``<where>/download`` :return: standard output :githublink:`%|py|129` """ if temp_folder is None: temp_folder = os.path.join(venv, "download") if isinstance(packages, str): packages = [packages] if packages == "pip" or packages == ["pip"]: from .get_pip import __file__ as pip_loc ppath = os.path.abspath(pip_loc.replace(".pyc", ".py")) script = ["-u", ppath] out = run_venv_script(venv, script, fLOG=fLOG, is_cmd=True) if sys.platform.startswith("win"): scripts = os.path.join(venv, "Scripts") else: scripts = os.path.join(venv, "bin") in_scripts = os.listdir(scripts) pips = [_ for _ in in_scripts if _.startswith("pip")] if len(pips) == 0: raise FileNotFoundError( "unable to find pip in {0},\nvenv:\n{2}\nppath:\n{3}\ncontent:\n {1}".format(scripts, in_scripts, venv, ppath)) return out else: p = os.path.normpath(os.path.join( os.path.abspath(os.path.dirname(__file__)), "..", "..")) ls = ','.join("'{0}'".format(_) for _ in packages) script = ["import sys", "sys.path.append('{0}')".format(p.replace("\\", "\\\\")), "import pymyinstall", "ps=[{0}]".format(ls), "t='{0}'".format(temp_folder.replace("\\", "\\\\")), "pymyinstall.packaged.install_all(temp_folder=t,list_module=ps,up_pip=False)"] return run_venv_script(venv, "\n".join(script), fLOG=fLOG)
[docs]def run_venv_script(venv, script, fLOG=print, file=False, is_cmd=False): """ run a script on a virtual environment (the script should be simple :param venv: virtual environment :param script: script as a string (not a file) :param fLOG: logging function :param file: is script a file or a string to execute :param is_cmd: if True, script is a command line to run (as a list) for python executable :return: output :githublink:`%|py|175` """ if sys.platform.startswith("win"): exe = os.path.join(venv, "Scripts", "python") else: exe = os.path.join(venv, "bin", "python") if is_cmd: cmd = " ".join([exe, script]) out, err = run_cmd(cmd, wait=True, fLOG=fLOG) if len(err) > 0: raise VirtualEnvError( "unable to run cmd at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-H:\n{1}".format(out, err, venv, cmd)) return out else: script = ";".join(script.split("\n")) if file: if not os.path.exists(script): raise FileNotFoundError(script) cmd = " ".join([exe, "-u", '"{0}"'.format(script)]) else: cmd = " ".join([exe, "-u", "-c", '"{0}"'.format(script)]) out, err = run_cmd(cmd, wait=True, fLOG=fLOG) if len(err) > 0: raise VirtualEnvError( "unable to run script at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-I:\n{1}".format(out, err, venv, cmd)) return out
[docs]def run_cmd_path(python_path, script, fLOG=print, file=False, is_cmd=False, **kwargs): """ run a script knowing python path, it does not raise an exception. :param python_path: python path :param script: script as a string (not a file) or command line if *is_cmd* is True :param fLOG: logging function :param file: is script a file or a string to execute :param is_cmd: if True, script is a command line to run (as a list) for python executable :param kwargs: extra parameters :return: output, error :githublink:`%|py|213` """ if sys.platform.startswith("win"): exe = os.path.join(python_path, "python") else: python_name = "python" if sys.version_info[ 0] == 2 else "python%d" % sys.version_info[0] exe = os.path.join(python_path, python_name) if not os.path.exists(exe): exe = os.path.join(python_path, "bin", python_name) if is_cmd: cmd = " ".join([exe] + script) out, err = run_cmd(cmd, wait=True, fLOG=fLOG, **kwargs) return out, err else: script = ";".join(script.split("\n")) if file: if not os.path.exists(script): raise FileNotFoundError(script) cmd = " ".join([exe, "-u", '"{0}"'.format(script)]) else: cmd = " ".join([exe, "-u", "-c", '"{0}"'.format(script)]) out, err = run_cmd(cmd, wait=True, fLOG=fLOG, **kwargs) return out, err