VirtualEnv/VirtualenvManager.py

branch
maintenance
changeset 6826
c6dda2cbe081
parent 6792
9dd854f05c83
child 6896
3716c4af48bb
equal deleted inserted replaced
6764:d14ddbfbbd36 6826:c6dda2cbe081
13 import sys 13 import sys
14 import shutil 14 import shutil
15 import json 15 import json
16 import copy 16 import copy
17 17
18 from PyQt5.QtCore import pyqtSlot, QObject 18 from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject
19 from PyQt5.QtWidgets import QDialog 19 from PyQt5.QtWidgets import QDialog
20 20
21 from E5Gui import E5MessageBox 21 from E5Gui import E5MessageBox
22 from E5Gui.E5Application import e5App
22 23
23 import Preferences 24 import Preferences
24 import Utilities
25 25
26 26
27 class VirtualenvManager(QObject): 27 class VirtualenvManager(QObject):
28 """ 28 """
29 Class implementing an object to manage Python virtual environments. 29 Class implementing an object to manage Python virtual environments.
30
31 @signal virtualEnvironmentAdded() emitted to indicate the addition of
32 a virtual environment
33 @signal virtualEnvironmentRemoved() emitted to indicate the removal and
34 deletion of a virtual environment
35 @signal virtualEnvironmentChanged(name) emitted to indicate a change of
36 a virtual environment
30 """ 37 """
31 DefaultKey = "<default>" 38 DefaultKey = "<default>"
39
40 virtualEnvironmentAdded = pyqtSignal()
41 virtualEnvironmentRemoved = pyqtSignal()
42 virtualEnvironmentChanged = pyqtSignal(str)
32 43
33 def __init__(self, parent=None): 44 def __init__(self, parent=None):
34 """ 45 """
35 Constructor 46 Constructor
36 47
59 # (empty for a global environment) 70 # (empty for a global environment)
60 # interpreter: the path of the Python interpreter 71 # interpreter: the path of the Python interpreter
61 # variant: Python variant (2 or 3) 72 # variant: Python variant (2 or 3)
62 # is_global: a flag indicating a global environment 73 # is_global: a flag indicating a global environment
63 # is_conda: a flag indicating an Anaconda environment 74 # is_conda: a flag indicating an Anaconda environment
75 # is_remote: a flag indicating a remotely accessed environment
64 # exec_path: a string to be prefixed to the PATH environment 76 # exec_path: a string to be prefixed to the PATH environment
65 # setting 77 # setting
66 # 78 #
67 for venvName in environments: 79 for venvName in environments:
68 interpreter = environments[venvName]["interpreter"] 80 environment = environments[venvName]
69 if os.access(interpreter, os.X_OK): 81 if ("is_remote" in environment and environment["is_remote"]) or \
70 environment = environments[venvName] 82 os.access(environment["interpreter"], os.X_OK):
71 if "is_global" not in environment: 83 if "is_global" not in environment:
72 environment["is_global"] = environment["path"] == "" 84 environment["is_global"] = environment["path"] == ""
73 if "is_conda" not in environment: 85 if "is_conda" not in environment:
74 environment["is_conda"] = False 86 environment["is_conda"] = False
87 if "is_remote" not in environment:
88 environment["is_remote"] = False
75 if "exec_path" not in environment: 89 if "exec_path" not in environment:
76 environment["exec_path"] = "" 90 environment["exec_path"] = ""
77 self.__virtualEnvironments[venvName] = environment 91 self.__virtualEnvironments[venvName] = environment
78 92
79 # check, if the interpreter used to run eric is in the environments 93 # check, if the interpreter used to run eric is in the environments
90 "path": "", 104 "path": "",
91 "interpreter": defaultPy, 105 "interpreter": defaultPy,
92 "variant": sys.version_info[0], 106 "variant": sys.version_info[0],
93 "is_global": True, 107 "is_global": True,
94 "is_conda": False, 108 "is_conda": False,
109 "is_remote": False,
95 "exec_path": "", 110 "exec_path": "",
96 } 111 }
97 112
98 self.__saveSettings() 113 self.__saveSettings()
99 114
103 """ 118 """
104 Preferences.Prefs.settings.setValue( 119 Preferences.Prefs.settings.setValue(
105 "PyVenv/VirtualEnvironments", 120 "PyVenv/VirtualEnvironments",
106 json.dumps(self.__virtualEnvironments) 121 json.dumps(self.__virtualEnvironments)
107 ) 122 )
123 Preferences.syncPreferences()
108 124
109 def getDefaultEnvironment(self): 125 def getDefaultEnvironment(self):
110 """ 126 """
111 Public method to get the default virtual environment. 127 Public method to get the default virtual environment.
112 128
145 from .VirtualenvConfigurationDialog import \ 161 from .VirtualenvConfigurationDialog import \
146 VirtualenvConfigurationDialog 162 VirtualenvConfigurationDialog
147 163
148 dlg = VirtualenvConfigurationDialog() 164 dlg = VirtualenvConfigurationDialog()
149 if dlg.exec_() == QDialog.Accepted: 165 if dlg.exec_() == QDialog.Accepted:
150 (pyvenv, args, name, openTarget, createLog, createScript, 166 resultDict = dlg.getData()
151 targetDir, interpreter) = dlg.getData()
152 167
153 # now do the call 168 if resultDict["envType"] == "conda":
154 from .VirtualenvExecDialog import VirtualenvExecDialog 169 # create the conda environment
155 dia = VirtualenvExecDialog(pyvenv, targetDir, name, openTarget, 170 conda = e5App().getObject("Conda")
156 createLog, createScript, interpreter, 171 ok, prefix, interpreter = conda.createCondaEnvironment(
157 self) 172 resultDict["arguments"])
158 dia.show() 173 if ok and "--dry-run" not in resultDict["arguments"]:
159 dia.start(args) 174 self.addVirtualEnv(resultDict["logicalName"],
160 dia.exec_() 175 prefix,
176 venvInterpreter=interpreter,
177 isConda=True)
178 else:
179 # now do the call
180 from .VirtualenvExecDialog import VirtualenvExecDialog
181 dia = VirtualenvExecDialog(resultDict, self)
182 dia.show()
183 dia.start(resultDict["arguments"])
184 dia.exec_()
161 185
162 def addVirtualEnv(self, venvName, venvDirectory, venvInterpreter="", 186 def addVirtualEnv(self, venvName, venvDirectory, venvInterpreter="",
163 venvVariant=3, isGlobal=False, isConda=False, 187 venvVariant=3, isGlobal=False, isConda=False,
164 execPath=""): 188 isRemote=False, execPath=""):
165 """ 189 """
166 Public method to add a virtual environment. 190 Public method to add a virtual environment.
167 191
168 @param venvName logical name for the virtual environment 192 @param venvName logical name for the virtual environment
169 @type str 193 @type str
174 @param venvVariant Python variant of the virtual environment 198 @param venvVariant Python variant of the virtual environment
175 @type int 199 @type int
176 @param isGlobal flag indicating a global environment 200 @param isGlobal flag indicating a global environment
177 @type bool 201 @type bool
178 @param isConda flag indicating an Anaconda virtual environment 202 @param isConda flag indicating an Anaconda virtual environment
203 @type bool
204 @param isRemote flag indicating a remotely accessed environment
179 @type bool 205 @type bool
180 @param execPath search path string to be prepended to the PATH 206 @param execPath search path string to be prepended to the PATH
181 environment variable 207 environment variable
182 @type str 208 @type str
183 """ 209 """
188 self.tr("""A virtual environment named <b>{0}</b> exists""" 214 self.tr("""A virtual environment named <b>{0}</b> exists"""
189 """ already. Shall it be replaced?""") 215 """ already. Shall it be replaced?""")
190 .format(venvName), 216 .format(venvName),
191 icon=E5MessageBox.Warning) 217 icon=E5MessageBox.Warning)
192 if not ok: 218 if not ok:
193 return 219 from .VirtualenvNameDialog import VirtualenvNameDialog
220 dlg = VirtualenvNameDialog(
221 list(self.__virtualEnvironments.keys()),
222 venvName)
223 if dlg.exec_() != QDialog.Accepted:
224 return
225
226 venvName = dlg.getName()
194 227
195 if not venvInterpreter: 228 if not venvInterpreter:
196 from .VirtualenvInterpreterSelectionDialog import \ 229 from .VirtualenvInterpreterSelectionDialog import \
197 VirtualenvInterpreterSelectionDialog 230 VirtualenvInterpreterSelectionDialog
198 dlg = VirtualenvInterpreterSelectionDialog(venvName, venvDirectory) 231 dlg = VirtualenvInterpreterSelectionDialog(venvName, venvDirectory)
199 if dlg.exec_() == QDialog.Accepted: 232 if dlg.exec_() == QDialog.Accepted:
200 venvInterpreter, venvVariant = dlg.getData() 233 venvInterpreter, venvVariant = dlg.getData()
201 if not Utilities.startswithPath(venvInterpreter,
202 venvDirectory):
203 isGlobal = True
204 234
205 if venvInterpreter: 235 if venvInterpreter:
206 self.__virtualEnvironments[venvName] = { 236 self.__virtualEnvironments[venvName] = {
207 "path": venvDirectory, 237 "path": venvDirectory,
208 "interpreter": venvInterpreter, 238 "interpreter": venvInterpreter,
209 "variant": venvVariant, 239 "variant": venvVariant,
210 "is_global": isGlobal, 240 "is_global": isGlobal,
211 "is_conda": isConda, 241 "is_conda": isConda,
242 "is_remote": isRemote,
212 "exec_path": execPath, 243 "exec_path": execPath,
213 } 244 }
214 245
215 self.__saveSettings() 246 self.__saveSettings()
216 247
248 self.virtualEnvironmentAdded.emit()
217 if self.__virtualenvManagerDialog: 249 if self.__virtualenvManagerDialog:
218 self.__virtualenvManagerDialog.refresh() 250 self.__virtualenvManagerDialog.refresh()
219 251
220 def setVirtualEnv(self, venvName, venvDirectory, venvInterpreter, 252 def setVirtualEnv(self, venvName, venvDirectory, venvInterpreter,
221 venvVariant, isGlobal, isConda, execPath): 253 venvVariant, isGlobal, isConda, isRemote,
254 execPath):
222 """ 255 """
223 Public method to change a virtual environment. 256 Public method to change a virtual environment.
224 257
225 @param venvName logical name of the virtual environment 258 @param venvName logical name of the virtual environment
226 @type str 259 @type str
231 @param venvVariant Python variant of the virtual environment 264 @param venvVariant Python variant of the virtual environment
232 @type int 265 @type int
233 @param isGlobal flag indicating a global environment 266 @param isGlobal flag indicating a global environment
234 @type bool 267 @type bool
235 @param isConda flag indicating an Anaconda virtual environment 268 @param isConda flag indicating an Anaconda virtual environment
269 @type bool
270 @param isRemote flag indicating a remotely accessed environment
236 @type bool 271 @type bool
237 @param execPath search path string to be prepended to the PATH 272 @param execPath search path string to be prepended to the PATH
238 environment variable 273 environment variable
239 @type str 274 @type str
240 """ 275 """
252 "path": venvDirectory, 287 "path": venvDirectory,
253 "interpreter": venvInterpreter, 288 "interpreter": venvInterpreter,
254 "variant": venvVariant, 289 "variant": venvVariant,
255 "is_global": isGlobal, 290 "is_global": isGlobal,
256 "is_conda": isConda, 291 "is_conda": isConda,
292 "is_remote": isRemote,
257 "exec_path": execPath, 293 "exec_path": execPath,
258 } 294 }
259 295
260 self.__saveSettings() 296 self.__saveSettings()
261 297
298 self.virtualEnvironmentChanged.emit(venvName)
262 if self.__virtualenvManagerDialog: 299 if self.__virtualenvManagerDialog:
263 self.__virtualenvManagerDialog.refresh() 300 self.__virtualenvManagerDialog.refresh()
264 301
265 def renameVirtualEnv(self, oldVenvName, venvName, venvDirectory, 302 def renameVirtualEnv(self, oldVenvName, venvName, venvDirectory,
266 venvInterpreter, venvVariant, isGlobal, isConda, 303 venvInterpreter, venvVariant, isGlobal, isConda,
267 execPath): 304 isRemote, execPath):
268 """ 305 """
269 Public method to substitute a virtual environment entry with a new 306 Public method to substitute a virtual environment entry with a new
270 name. 307 name.
271 308
272 @param oldVenvName old name of the virtual environment 309 @param oldVenvName old name of the virtual environment
280 @param venvVariant Python variant of the virtual environment 317 @param venvVariant Python variant of the virtual environment
281 @type int 318 @type int
282 @param isGlobal flag indicating a global environment 319 @param isGlobal flag indicating a global environment
283 @type bool 320 @type bool
284 @param isConda flag indicating an Anaconda virtual environment 321 @param isConda flag indicating an Anaconda virtual environment
322 @type bool
323 @param isRemote flag indicating a remotely accessed environment
285 @type bool 324 @type bool
286 @param execPath search path string to be prepended to the PATH 325 @param execPath search path string to be prepended to the PATH
287 environment variable 326 environment variable
288 @type str 327 @type str
289 """ 328 """
297 icon=E5MessageBox.Warning) 336 icon=E5MessageBox.Warning)
298 return 337 return
299 338
300 del self.__virtualEnvironments[oldVenvName] 339 del self.__virtualEnvironments[oldVenvName]
301 self.addVirtualEnv(venvName, venvDirectory, venvInterpreter, 340 self.addVirtualEnv(venvName, venvDirectory, venvInterpreter,
302 venvVariant, isGlobal, isConda, execPath) 341 venvVariant, isGlobal, isConda, isRemote,
342 execPath)
303 343
304 def deleteVirtualEnvs(self, venvNames): 344 def deleteVirtualEnvs(self, venvNames):
305 """ 345 """
306 Public method to delete virtual environments from the list and disk. 346 Public method to delete virtual environments from the list and disk.
307 347
325 venvMessages 365 venvMessages
326 ) 366 )
327 if dlg.exec_() == QDialog.Accepted: 367 if dlg.exec_() == QDialog.Accepted:
328 for venvName in venvNames: 368 for venvName in venvNames:
329 if self.__isEnvironmentDeleteable(venvName): 369 if self.__isEnvironmentDeleteable(venvName):
330 shutil.rmtree( 370 if self.isCondaEnvironment(venvName):
331 self.__virtualEnvironments[venvName]["path"], True) 371 conda = e5App().getObject("Conda")
332 del self.__virtualEnvironments[venvName] 372 path = self.__virtualEnvironments[venvName]["path"]
373 res = conda.removeCondaEnvironment(prefix=path)
374 if res:
375 del self.__virtualEnvironments[venvName]
376 else:
377 shutil.rmtree(
378 self.__virtualEnvironments[venvName]["path"],
379 True)
380 del self.__virtualEnvironments[venvName]
333 381
334 self.__saveSettings() 382 self.__saveSettings()
335 383
384 self.virtualEnvironmentRemoved.emit()
336 if self.__virtualenvManagerDialog: 385 if self.__virtualenvManagerDialog:
337 self.__virtualenvManagerDialog.refresh() 386 self.__virtualenvManagerDialog.refresh()
338 387
339 def __isEnvironmentDeleteable(self, venvName): 388 def __isEnvironmentDeleteable(self, venvName):
340 """ 389 """
349 ok = False 398 ok = False
350 if venvName in self.__virtualEnvironments: 399 if venvName in self.__virtualEnvironments:
351 ok = True 400 ok = True
352 ok &= bool(self.__virtualEnvironments[venvName]["path"]) 401 ok &= bool(self.__virtualEnvironments[venvName]["path"])
353 ok &= not self.__virtualEnvironments[venvName]["is_global"] 402 ok &= not self.__virtualEnvironments[venvName]["is_global"]
403 ok &= not self.__virtualEnvironments[venvName]["is_remote"]
354 ok &= os.access(self.__virtualEnvironments[venvName]["path"], 404 ok &= os.access(self.__virtualEnvironments[venvName]["path"],
355 os.W_OK) 405 os.W_OK)
356 406
357 return ok 407 return ok
358 408
383 if venvName in self.__virtualEnvironments: 433 if venvName in self.__virtualEnvironments:
384 del self.__virtualEnvironments[venvName] 434 del self.__virtualEnvironments[venvName]
385 435
386 self.__saveSettings() 436 self.__saveSettings()
387 437
438 self.virtualEnvironmentRemoved.emit()
388 if self.__virtualenvManagerDialog: 439 if self.__virtualenvManagerDialog:
389 self.__virtualenvManagerDialog.refresh() 440 self.__virtualenvManagerDialog.refresh()
390 441
391 def getEnvironmentEntries(self): 442 def getEnvironmentEntries(self):
392 """ 443 """
519 if venvName in self.__virtualEnvironments: 570 if venvName in self.__virtualEnvironments:
520 return self.__virtualEnvironments[venvName]["is_conda"] 571 return self.__virtualEnvironments[venvName]["is_conda"]
521 else: 572 else:
522 return False 573 return False
523 574
575 def isRemoteEnvironment(self, venvName):
576 """
577 Public method to test, if a given environment is a remotely accessed
578 environment.
579
580 @param venvName logical name of the virtual environment
581 @type str
582 @return flag indicating a remotely accessed environment
583 @rtype bool
584 """
585 if venvName in self.__virtualEnvironments:
586 return self.__virtualEnvironments[venvName]["is_remote"]
587 else:
588 return False
589
524 def getVirtualenvExecPath(self, venvName): 590 def getVirtualenvExecPath(self, venvName):
525 """ 591 """
526 Public method to get the search path prefix of a virtual environment. 592 Public method to get the search path prefix of a virtual environment.
527 593
528 @param venvName logical name for the virtual environment 594 @param venvName logical name for the virtual environment

eric ide

mercurial