VirtualEnv/VirtualenvConfigurationDialog.py

changeset 6337
c6af560e0039
parent 6048
82ad8ec9548c
child 6338
104ee21d765d
equal deleted inserted replaced
6336:a04ac8bd014b 6337:c6af560e0039
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2018 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to enter the parameters for the
8 virtual environment.
9 """
10
11 from __future__ import unicode_literals
12 try:
13 str = unicode
14 except NameError:
15 pass
16
17 import os
18 import sys
19 import re
20
21 from PyQt5.QtCore import pyqtSlot, QProcess, QTimer
22 from PyQt5.QtWidgets import QDialog, QDialogButtonBox
23
24 from E5Gui.E5PathPicker import E5PathPickerModes
25
26 from .Ui_VirtualenvConfigurationDialog import Ui_VirtualenvConfigurationDialog
27
28 import Preferences
29 import Utilities
30
31
32 class VirtualenvConfigurationDialog(QDialog, Ui_VirtualenvConfigurationDialog):
33 """
34 Class implementing a dialog to enter the parameters for the
35 virtual environment.
36 """
37 def __init__(self, parent=None):
38 """
39 Constructor
40
41 @param parent reference to the parent widget
42 @type QWidget
43 """
44 super(VirtualenvConfigurationDialog, self).__init__(parent)
45 self.setupUi(self)
46
47 self.targetDirectoryPicker.setMode(E5PathPickerModes.DirectoryMode)
48 self.targetDirectoryPicker.setWindowTitle(
49 self.tr("Virtualenv Target Directory"))
50 self.targetDirectoryPicker.setDefaultDirectory(Utilities.getHomeDir())
51
52 self.extraSearchPathPicker.setMode(E5PathPickerModes.DirectoryMode)
53 self.extraSearchPathPicker.setWindowTitle(
54 self.tr("Extra Search Path for setuptools/pip"))
55 self.extraSearchPathPicker.setDefaultDirectory(Utilities.getHomeDir())
56
57 self.pythonExecPicker.setMode(E5PathPickerModes.OpenFileMode)
58 self.pythonExecPicker.setWindowTitle(
59 self.tr("Python Interpreter"))
60 self.pythonExecPicker.setDefaultDirectory(
61 sys.executable.replace("w.exe", ".exe"))
62
63 self.__versionRe = re.compile(r""".*?(\d+\.\d+\.\d+).*""")
64
65 self.__virtualenvFound = False
66 self.__pyvenvFound = False
67 self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
68
69 self.__mandatoryStyleSheet = "QLineEdit {border: 2px solid;}"
70 self.targetDirectoryPicker.setStyleSheet(self.__mandatoryStyleSheet)
71 self.nameEdit.setStyleSheet(self.__mandatoryStyleSheet)
72
73 self.__setVirtualenvVersion()
74 self.__setPyvenvVersion()
75 if self.__virtualenvFound:
76 self.virtualenvButton.setChecked(True)
77 elif self.__pyvenvFound:
78 self.pyvenvButton.setChecked(True)
79
80 msh = self.minimumSizeHint()
81 self.resize(max(self.width(), msh.width()), msh.height())
82
83 def __updateOK(self):
84 """
85 Private method to update the enabled status of the OK button.
86 """
87 self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
88 (self.__virtualenvFound or self.__pyvenvFound) and
89 bool(self.targetDirectoryPicker.text() and
90 bool(self.nameEdit.text()))
91 )
92
93 def __updateUi(self):
94 """
95 Private method to update the UI depending on the selected
96 virtual environment creator (virtualenv or pyvenv).
97 """
98 enable = self.virtualenvButton.isChecked()
99 self.extraSearchPathLabel.setEnabled(enable)
100 self.extraSearchPathPicker.setEnabled(enable)
101 self.promptPrefixLabel.setEnabled(enable)
102 self.promptPrefixEdit.setEnabled(enable)
103 self.verbosityLabel.setEnabled(enable)
104 self.verbositySpinBox.setEnabled(enable)
105 self.versionLabel.setEnabled(enable)
106 self.versionComboBox.setEnabled(enable)
107 self.unzipCheckBox.setEnabled(enable)
108 self.noSetuptoolsCheckBox.setEnabled(enable)
109 self.symlinkCheckBox.setEnabled(not enable)
110 self.upgradeCheckBox.setEnabled(not enable)
111
112 @pyqtSlot(str)
113 def on_targetDirectoryPicker_textChanged(self, txt):
114 """
115 Private slot handling a change of the target directory.
116
117 @param txt target directory
118 @type str
119 """
120 self.__updateOK()
121
122 @pyqtSlot(str)
123 def on_pythonExecPicker_textChanged(self, txt):
124 """
125 Private slot to react to a change of the Python executable.
126
127 @param txt contents of the picker's line edit
128 @type str
129 """
130 self.__setVirtualenvVersion()
131 self.__setPyvenvVersion()
132 self.__updateOK()
133
134 @pyqtSlot(bool)
135 def on_virtualenvButton_toggled(self, checked):
136 """
137 Private slot to react to the selection of 'virtualenv'.
138
139 @param checked state of the checkbox
140 @type bool
141 """
142 self.__updateUi()
143
144 @pyqtSlot(bool)
145 def on_pyvenvButton_toggled(self, checked):
146 """
147 Private slot to react to the selection of 'pyvenv'.
148
149 @param checked state of the checkbox
150 @type bool
151 """
152 self.__updateUi()
153
154 def __setVirtualenvVersion(self):
155 """
156 Private method to determine the virtualenv version and set the
157 respective label.
158 """
159 calls = [
160 (sys.executable.replace("w.exe", ".exe"),
161 ["-m", "virtualenv", "--version"]),
162 ("virtualenv", ["--version"]),
163 ]
164 if self.pythonExecPicker.text():
165 calls.append((self.pythonExecPicker.text(),
166 ["-m", "virtualenv", "--version"]))
167
168 proc = QProcess()
169 for prog, args in calls:
170 proc.start(prog, args)
171
172 if not proc.waitForStarted(5000):
173 # try next entry
174 continue
175
176 if not proc.waitForFinished(5000):
177 # process hangs, kill it
178 QTimer.singleShot(2000, proc.kill)
179 proc.waitForFinished(3000)
180 version = self.tr('<virtualenv did not finish within 5s.>')
181 self.__virtualenvFound = False
182 break
183
184 if proc.exitCode() != 0:
185 # returned with error code, try next
186 continue
187
188 output = str(proc.readAllStandardOutput(),
189 Preferences.getSystem("IOEncoding"),
190 'replace').strip()
191 match = re.match(self.__versionRe, output)
192 if match:
193 self.__virtualenvFound = True
194 version = match.group(1)
195 break
196 else:
197 self.__virtualenvFound = False
198 version = self.tr('<No suitable virtualenv found.>')
199
200 self.virtualenvButton.setText(self.tr(
201 "virtualenv Version: {0}".format(version)))
202 self.virtualenvButton.setEnabled(self.__virtualenvFound)
203 if not self.__virtualenvFound:
204 self.virtualenvButton.setChecked(False)
205
206 def __setPyvenvVersion(self):
207 """
208 Private method to determine the pyvenv version and set the respective
209 label.
210 """
211 calls = []
212 if self.pythonExecPicker.text():
213 calls.append((self.pythonExecPicker.text(),
214 ["-m", "venv"]))
215 calls.extend([
216 (sys.executable.replace("w.exe", ".exe"),
217 ["-m", "venv"]),
218 ("python3", ["-m", "venv"]),
219 ("python", ["-m", "venv"]),
220 ])
221
222 proc = QProcess()
223 for prog, args in calls:
224 proc.start(prog, args)
225
226 if not proc.waitForStarted(5000):
227 # try next entry
228 continue
229
230 if not proc.waitForFinished(5000):
231 # process hangs, kill it
232 QTimer.singleShot(2000, proc.kill)
233 proc.waitForFinished(3000)
234 version = self.tr('<pyvenv did not finish within 5s.>')
235 self.__pyvenvFound = False
236 break
237
238 if proc.exitCode() not in [0, 2]:
239 # returned with error code, try next
240 continue
241
242 proc.start(prog, ["--version"])
243 proc.waitForFinished(5000)
244 output = str(proc.readAllStandardOutput(),
245 Preferences.getSystem("IOEncoding"),
246 'replace').strip()
247 match = re.match(self.__versionRe, output)
248 if match:
249 self.__pyvenvFound = True
250 version = match.group(1)
251 break
252 else:
253 self.__pyvenvFound = False
254 version = self.tr('<No suitable pyvenv found.>')
255
256 self.pyvenvButton.setText(self.tr(
257 "pyvenv Version: {0}".format(version)))
258 self.pyvenvButton.setEnabled(self.__pyvenvFound)
259 if not self.__pyvenvFound:
260 self.pyvenvButton.setChecked(False)
261
262 def __generateTargetDir(self):
263 """
264 Private method to generate a valid target directory path.
265
266 @return target directory path
267 @rtype str
268 """
269 targetDirectory = Utilities.toNativeSeparators(
270 self.targetDirectoryPicker.text())
271 if not os.path.isabs(targetDirectory):
272 targetDirectory = os.path.join(os.path.expanduser("~"),
273 targetDirectory)
274 return targetDirectory
275
276 def __generateArguments(self):
277 """
278 Private method to generate the process arguments.
279
280 @return process arguments
281 @rtype list of str
282 """
283 args = []
284 if self.virtualenvButton.isChecked():
285 if self.extraSearchPathPicker.text():
286 args.append("--extra-search-dir={0}".format(
287 Utilities.toNativeSeparators(
288 self.extraSearchPathPicker.text())))
289 if self.promptPrefixEdit.text():
290 args.append("--prompt={0}".format(
291 self.promptPrefixEdit.text().replace(" ", "_")))
292 if self.pythonExecPicker.text():
293 args.append("--python={0}".format(
294 Utilities.toNativeSeparators(
295 self.pythonExecPicker.text())))
296 elif self.versionComboBox.currentText():
297 args.append("--python=python{0}".format(
298 self.versionComboBox.currentText()))
299 if self.verbositySpinBox.value() == 1:
300 args.append("--verbose")
301 elif self.verbositySpinBox.value() == -1:
302 args.append("--quiet")
303 if self.clearCheckBox.isChecked():
304 args.append("--clear")
305 if self.systemCheckBox.isChecked():
306 args.append("--system-site-packages")
307 if self.unzipCheckBox.isChecked():
308 args.append("--unzip-setuptools")
309 if self.noSetuptoolsCheckBox.isChecked():
310 args.append("--no-setuptools")
311 if self.noPipCcheckBox.isChecked():
312 args.append("--no-pip")
313 if self.copyCheckBox.isChecked():
314 args.append("--always-copy")
315 elif self.pyvenvButton.isChecked():
316 if self.clearCheckBox.isChecked():
317 args.append("--clear")
318 if self.systemCheckBox.isChecked():
319 args.append("--system-site-packages")
320 if self.noPipCcheckBox.isChecked():
321 args.append("--without-pip")
322 if self.copyCheckBox.isChecked():
323 args.append("--copies")
324 if self.symlinkCheckBox.isChecked():
325 args.append("--symlinks")
326 if self.upgradeCheckBox.isChecked():
327 args.append("--upgrade")
328 targetDirectory = self.__generateTargetDir()
329 args.append(targetDirectory)
330 return args
331
332 def getData(self):
333 """
334 Public method to retrieve the dialog data.
335
336 @return tuple containing a flag indicating the pyvenv selection, the
337 process arguments, a name for the virtual environment, a flag
338 indicating to open the target directory after creation, a flag
339 indicating to write a log file, a flag indicating to write a
340 script, the name of the target directory and the name of the
341 Python interpreter to use
342 @rtype tuple of (bool, list of str, str, bool, bool, bool, str, str)
343 """
344 args = self.__generateArguments()
345 targetDirectory = self.__generateTargetDir()
346 return (
347 self.pyvenvButton.isChecked(),
348 args,
349 self.nameEdit.text(),
350 self.openCheckBox.isChecked(),
351 self.logCheckBox.isChecked(),
352 self.scriptCheckBox.isChecked(),
353 targetDirectory,
354 Utilities.toNativeSeparators(self.pythonExecPicker.text()),
355 )

eric ide

mercurial