Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2@file
3@brief Helpers for virtualenv
4"""
5from __future__ import print_function
7import os
8import sys
9from .install_cmd_helper import run_cmd
11if sys.version_info[0] == 2:
12 FileNotFoundError = Exception
15class VirtualEnvError(Exception):
16 """
17 exception raised by the function implemented in this file
18 """
19 pass
22def build_venv_cmd(params, posparams):
23 """
24 builds the command line for virtual env
26 @param params dictionary of parameters
27 @param posparams positional arguments
28 @return string
29 """
30 import venv
31 dir(venv)
32 exe = sys.executable.replace("w.exe", "").replace(".exe", "")
33 cmd = [exe, "-m", "venv"]
34 for k, v in params.items():
35 if v is None:
36 cmd.append("--" + k)
37 else:
38 cmd.append("--" + k + "=" + v)
39 cmd.extend(posparams)
40 return " ".join(cmd)
43def create_virtual_env(where, symlinks=False, system_site_packages=False,
44 clear=True, packages=None, fLOG=print,
45 temp_folder=None):
46 """
47 .. index:: virtual environment
49 create a virtual environment
51 @param where location of this virtual environment
52 @param symlinks attempt to symlink rather than copy
53 @param system_site_packages Give the virtual environment access to the system site-packages dir
54 @param clear Delete the environment directory if it already exists.
55 If not specified and the directory exists, an error is raised.
56 @param packages list of packages to install (it will install module
57 :epkg:`pymyinstall`).
58 @param fLOG logging function
59 @param temp_folder temporary folder (to download module if needed), by default ``<where>/download``
60 @return stand output
62 .. exref::
63 :title: Create a virtual environment
65 The following example creates a virtual environment.
66 Packages can be added by specifying the parameter *package*.
68 ::
70 from pyquickhelper.pycode import create_virtual_env
71 fold = "my_env"
72 if not os.path.exists(fold):
73 os.mkdir(fold)
74 create_virtual_env(fold)
75 """
76 fLOG("[pymy] create virtual environment at:", where)
77 params = {}
78 if symlinks:
79 params["symlinks"] = None
80 if system_site_packages:
81 params["system-site-packages"] = None
82 if clear:
83 params["clear"] = None
84 cmd = build_venv_cmd(params, [where])
85 out, err = run_cmd(cmd, wait=True, fLOG=fLOG)
86 if len(err) > 0:
87 raise VirtualEnvError(
88 "unable to create virtual environement at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-G:\n{1}".format(out, err, where, cmd))
90 if sys.platform.startswith("win"):
91 scripts = os.path.join(where, "Scripts")
92 else:
93 scripts = os.path.join(where, "bin")
95 if not os.path.exists(scripts):
96 files = "\n ".join(os.listdir(where))
97 raise FileNotFoundError(
98 "unable to find {0}, content:\n {1}".format(scripts, files))
100 in_scripts = os.listdir(scripts)
101 pips = [_ for _ in in_scripts if _.startswith("pip")]
102 if len(pips) == 0:
103 out += venv_install(where, "pip", fLOG=fLOG,
104 temp_folder=temp_folder)
105 in_scripts = os.listdir(scripts)
106 pips = [_ for _ in in_scripts if _.startswith("pip")]
107 if len(pips) == 0:
108 raise FileNotFoundError(
109 "unable to find pip in {0}, content:\n {1}".format(scripts, in_scripts))
111 if packages is not None and len(packages) > 0:
112 fLOG("[pymy] install packages in:", where)
113 packages = [_ for _ in packages if _ != "pymyinstall" and _ != "pip"]
114 if len(packages) > 0:
115 out += venv_install(where, packages, fLOG=fLOG,
116 temp_folder=temp_folder)
117 return out
120def venv_install(venv, packages, fLOG=print, temp_folder=None):
121 """
122 install a package or a list of packages in a virtual environment
124 @param venv location of the virtual environment
125 @param packages a package (str) or a list of packages(list[str])
126 @param fLOG logging function
127 @param temp_folder temporary folder (to download module if needed), by default ``<where>/download``
128 @return standard output
129 """
130 if temp_folder is None:
131 temp_folder = os.path.join(venv, "download")
133 if isinstance(packages, str):
134 packages = [packages]
136 if packages == "pip" or packages == ["pip"]:
137 from .get_pip import __file__ as pip_loc
138 ppath = os.path.abspath(pip_loc.replace(".pyc", ".py"))
139 script = ["-u", ppath]
140 out = run_venv_script(venv, script, fLOG=fLOG, is_cmd=True)
142 if sys.platform.startswith("win"):
143 scripts = os.path.join(venv, "Scripts")
144 else:
145 scripts = os.path.join(venv, "bin")
146 in_scripts = os.listdir(scripts)
147 pips = [_ for _ in in_scripts if _.startswith("pip")]
148 if len(pips) == 0:
149 raise FileNotFoundError(
150 "unable to find pip in {0},\nvenv:\n{2}\nppath:\n{3}\ncontent:\n {1}".format(scripts, in_scripts, venv, ppath))
151 return out
152 else:
153 p = os.path.normpath(os.path.join(
154 os.path.abspath(os.path.dirname(__file__)), "..", ".."))
155 ls = ','.join("'{0}'".format(_) for _ in packages)
156 script = ["import sys",
157 "sys.path.append('{0}')".format(p.replace("\\", "\\\\")),
158 "import pymyinstall",
159 "ps=[{0}]".format(ls),
160 "t='{0}'".format(temp_folder.replace("\\", "\\\\")),
161 "pymyinstall.packaged.install_all(temp_folder=t,list_module=ps,up_pip=False)"]
162 return run_venv_script(venv, "\n".join(script), fLOG=fLOG)
165def run_venv_script(venv, script, fLOG=print, file=False, is_cmd=False):
166 """
167 run a script on a virtual environment (the script should be simple
169 @param venv virtual environment
170 @param script script as a string (not a file)
171 @param fLOG logging function
172 @param file is script a file or a string to execute
173 @param is_cmd if True, script is a command line to run (as a list) for python executable
174 @return output
175 """
176 if sys.platform.startswith("win"):
177 exe = os.path.join(venv, "Scripts", "python")
178 else:
179 exe = os.path.join(venv, "bin", "python")
180 if is_cmd:
181 cmd = " ".join([exe, script])
182 out, err = run_cmd(cmd, wait=True, fLOG=fLOG)
183 if len(err) > 0:
184 raise VirtualEnvError(
185 "unable to run cmd at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-H:\n{1}".format(out, err, venv, cmd))
186 return out
187 else:
188 script = ";".join(script.split("\n"))
189 if file:
190 if not os.path.exists(script):
191 raise FileNotFoundError(script)
192 cmd = " ".join([exe, "-u", '"{0}"'.format(script)])
193 else:
194 cmd = " ".join([exe, "-u", "-c", '"{0}"'.format(script)])
195 out, err = run_cmd(cmd, wait=True, fLOG=fLOG)
196 if len(err) > 0:
197 raise VirtualEnvError(
198 "unable to run script at {2}\nCMD:\n{3}\nOUT:\n{0}\nERR-I:\n{1}".format(out, err, venv, cmd))
199 return out
202def run_cmd_path(python_path, script, fLOG=print, file=False, is_cmd=False, **kwargs):
203 """
204 run a script knowing python path, it does not raise an exception.
206 @param python_path python path
207 @param script script as a string (not a file) or command line if *is_cmd* is True
208 @param fLOG logging function
209 @param file is script a file or a string to execute
210 @param is_cmd if True, script is a command line to run (as a list) for python executable
211 @param kwargs extra parameters
212 @return output, error
213 """
214 if sys.platform.startswith("win"):
215 exe = os.path.join(python_path, "python")
216 else:
217 python_name = "python" if sys.version_info[
218 0] == 2 else "python%d" % sys.version_info[0]
219 exe = os.path.join(python_path, python_name)
220 if not os.path.exists(exe):
221 exe = os.path.join(python_path, "bin", python_name)
222 if is_cmd:
223 cmd = " ".join([exe] + script)
224 out, err = run_cmd(cmd, wait=True, fLOG=fLOG, **kwargs)
225 return out, err
226 else:
227 script = ";".join(script.split("\n"))
228 if file:
229 if not os.path.exists(script):
230 raise FileNotFoundError(script)
231 cmd = " ".join([exe, "-u", '"{0}"'.format(script)])
232 else:
233 cmd = " ".join([exe, "-u", "-c", '"{0}"'.format(script)])
234 out, err = run_cmd(cmd, wait=True, fLOG=fLOG, **kwargs)
235 return out, err