Plugins/UiExtensionPlugins/VirtualenvInterface/VirtualenvConfigurationDialog.py

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

eric ide

mercurial