Hide keyboard shortcuts

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 

6 

7import os 

8import sys 

9from .install_cmd_helper import run_cmd 

10 

11if sys.version_info[0] == 2: 

12 FileNotFoundError = Exception 

13 

14 

15class VirtualEnvError(Exception): 

16 """ 

17 exception raised by the function implemented in this file 

18 """ 

19 pass 

20 

21 

22def build_venv_cmd(params, posparams): 

23 """ 

24 builds the command line for virtual env 

25 

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) 

41 

42 

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 

48 

49 create a virtual environment 

50 

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 

61 

62 .. exref:: 

63 :title: Create a virtual environment 

64 

65 The following example creates a virtual environment. 

66 Packages can be added by specifying the parameter *package*. 

67 

68 :: 

69 

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)) 

89 

90 if sys.platform.startswith("win"): 

91 scripts = os.path.join(where, "Scripts") 

92 else: 

93 scripts = os.path.join(where, "bin") 

94 

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)) 

99 

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)) 

110 

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 

118 

119 

120def venv_install(venv, packages, fLOG=print, temp_folder=None): 

121 """ 

122 install a package or a list of packages in a virtual environment 

123 

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") 

132 

133 if isinstance(packages, str): 

134 packages = [packages] 

135 

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) 

141 

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) 

163 

164 

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 

168 

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 

200 

201 

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. 

205 

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