Plugins/UiExtensionPlugins/VirtualenvInterface/VirtualenvConfigurationDialog.py

changeset 6014
d3375a0a3240
child 6048
82ad8ec9548c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/UiExtensionPlugins/VirtualenvInterface/VirtualenvConfigurationDialog.py	Sun Dec 10 12:27:28 2017 +0100
@@ -0,0 +1,397 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2014 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the parameters for the
+virtual environment.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode
+except NameError:
+    pass
+
+import os
+import sys
+import re
+
+from PyQt5.QtCore import pyqtSlot, QProcess, QTimer
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox
+
+from E5Gui.E5Completers import E5DirCompleter, E5FileCompleter
+from E5Gui import E5FileDialog
+
+from .Ui_VirtualenvConfigurationDialog import Ui_VirtualenvConfigurationDialog
+
+import Preferences
+import Utilities
+import UI.PixmapCache
+
+
+class VirtualenvConfigurationDialog(QDialog, Ui_VirtualenvConfigurationDialog):
+    """
+    Class implementing a dialog to enter the parameters for the
+    virtual environment.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(VirtualenvConfigurationDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.targetDirectoryButton.setIcon(UI.PixmapCache.getIcon("open.png"))
+        self.extraSearchPathButton.setIcon(UI.PixmapCache.getIcon("open.png"))
+        self.pythonExecButton.setIcon(UI.PixmapCache.getIcon("open.png"))
+        
+        self.__targetDirectoryCompleter = \
+            E5DirCompleter(self.targetDirectoryEdit)
+        self.__extraSearchPathCompleter = \
+            E5DirCompleter(self.extraSearchPathEdit)
+        self.__pythonExecCompleter = E5FileCompleter(self.pythonExecEdit)
+        
+        self.__versionRe = re.compile(r""".*?(\d+\.\d+\.\d+).*""")
+        
+        self.__virtualenvFound = False
+        self.__pyvenvFound = False
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
+        
+        self.__mandatoryStyleSheet = "QLineEdit {border: 2px solid;}"
+        self.targetDirectoryEdit.setStyleSheet(self.__mandatoryStyleSheet)
+        
+        self.__setVirtualenvVersion()
+        self.__setPyvenvVersion()
+        if self.__virtualenvFound:
+            self.virtualenvButton.setChecked(True)
+        elif self.__pyvenvFound:
+            self.pyvenvButton.setChecked(True)
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+    
+    def __updateOK(self):
+        """
+        Private method to update the enabled status of the OK button.
+        """
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(
+            (self.__virtualenvFound or self.__pyvenvFound) and
+            bool(self.targetDirectoryEdit.text())
+        )
+    
+    def __updateUi(self):
+        """
+        Private method to update the UI depending on the selected
+        virtual environment creator (virtualenv or pyvenv).
+        """
+        enable = self.virtualenvButton.isChecked()
+        self.extraSearchPathLabel.setEnabled(enable)
+        self.extraSearchPathEdit.setEnabled(enable)
+        self.extraSearchPathButton.setEnabled(enable)
+        self.promptPrefixLabel.setEnabled(enable)
+        self.promptPrefixEdit.setEnabled(enable)
+        self.verbosityLabel.setEnabled(enable)
+        self.verbositySpinBox.setEnabled(enable)
+        self.versionLabel.setEnabled(enable)
+        self.versionComboBox.setEnabled(enable)
+        self.unzipCheckBox.setEnabled(enable)
+        self.noSetuptoolsCheckBox.setEnabled(enable)
+        self.symlinkCheckBox.setEnabled(not enable)
+        self.upgradeCheckBox.setEnabled(not enable)
+    
+    @pyqtSlot()
+    def on_targetDirectoryButton_clicked(self):
+        """
+        Private slot to select the target directory via a directory
+        selection dialog.
+        """
+        target = self.targetDirectoryEdit.text()
+        if not target:
+            target = Utilities.getHomeDir()
+        target = Utilities.fromNativeSeparators(target)
+        target = E5FileDialog.getExistingDirectory(
+            self,
+            self.tr("Virtualenv Target Directory"),
+            target,
+            E5FileDialog.Options(E5FileDialog.ShowDirsOnly))
+        if target:
+            self.targetDirectoryEdit.setText(
+                Utilities.toNativeSeparators(target))
+    
+    @pyqtSlot(str)
+    def on_targetDirectoryEdit_textChanged(self, txt):
+        """
+        Private slot handling a change of the target directory.
+        
+        @param txt target directory (string)
+        """
+        self.__updateOK()
+    
+    @pyqtSlot()
+    def on_extraSearchPathButton_clicked(self):
+        """
+        Private slot to select the extra search path via a directory
+        selection dialog.
+        """
+        extraSearchPath = self.extraSearchPathEdit.text()
+        if not extraSearchPath:
+            extraSearchPath = Utilities.getHomeDir()
+        extraSearchPath = Utilities.fromNativeSeparators(extraSearchPath)
+        extraSearchPath = E5FileDialog.getExistingDirectory(
+            self,
+            self.tr("Extra Search Path for setuptools/pip"),
+            extraSearchPath,
+            E5FileDialog.Options(E5FileDialog.ShowDirsOnly))
+        if extraSearchPath:
+            self.extraSearchPathEdit.setText(
+                Utilities.toNativeSeparators(extraSearchPath))
+    
+    @pyqtSlot()
+    def on_pythonExecButton_clicked(self):
+        """
+        Private slot to select a Python interpreter via a file selection
+        dialog.
+        """
+        pythonExec = self.pythonExecEdit.text()
+        if not pythonExec:
+            pythonExec = sys.executable.replace("w.exe", ".exe")
+        pythonExec = Utilities.fromNativeSeparators(pythonExec)
+        pythonExec = E5FileDialog.getOpenFileName(
+            self,
+            self.tr("Python Interpreter"),
+            pythonExec,
+            "")
+        if pythonExec:
+            self.pythonExecEdit.setText(
+                Utilities.toNativeSeparators(pythonExec))
+    
+    @pyqtSlot(str)
+    def on_pythonExecEdit_textChanged(self, txt):
+        """
+        Private slot to react to a change of the Python executable.
+        
+        @param txt contents of the line edit (string)
+        """
+        self.__setVirtualenvVersion()
+        self.__setPyvenvVersion()
+        self.__updateOK()
+    
+    @pyqtSlot(bool)
+    def on_virtualenvButton_toggled(self, checked):
+        """
+        Private slot to react to the selection of 'virtualenv'.
+        
+        @param checked state of the checkbox (boolean)
+        """
+        self.__updateUi()
+    
+    @pyqtSlot(bool)
+    def on_pyvenvButton_toggled(self, checked):
+        """
+        Private slot to react to the selection of 'pyvenv'.
+        
+        @param checked state of the checkbox (boolean)
+        """
+        self.__updateUi()
+    
+    def __setVirtualenvVersion(self):
+        """
+        Private method to determine the virtualenv version and set the
+        respective label.
+        """
+        calls = [
+            (sys.executable.replace("w.exe", ".exe"),
+             ["-m", "virtualenv", "--version"]),
+            ("virtualenv", ["--version"]),
+        ]
+        if self.pythonExecEdit.text():
+            calls.append((self.pythonExecEdit.text(),
+                          ["-m", "virtualenv", "--version"]))
+        
+        proc = QProcess()
+        for prog, args in calls:
+            proc.start(prog, args)
+            
+            if not proc.waitForStarted(5000):
+                # try next entry
+                continue
+            
+            if not proc.waitForFinished(5000):
+                # process hangs, kill it
+                QTimer.singleShot(2000, proc.kill)
+                proc.waitForFinished(3000)
+                version = self.tr('<virtualenv did not finish within 5s.>')
+                self.__virtualenvFound = False
+                break
+            
+            if proc.exitCode() != 0:
+                # returned with error code, try next
+                continue
+            
+            output = str(proc.readAllStandardOutput(),
+                         Preferences.getSystem("IOEncoding"),
+                         'replace').strip()
+            match = re.match(self.__versionRe, output)
+            if match:
+                self.__virtualenvFound = True
+                version = match.group(1)
+                break
+        else:
+            self.__virtualenvFound = False
+            version = self.tr('<No suitable virtualenv found.>')
+        
+        self.virtualenvButton.setText(self.tr(
+            "virtualenv Version: {0}".format(version)))
+        self.virtualenvButton.setEnabled(self.__virtualenvFound)
+        if not self.__virtualenvFound:
+            self.virtualenvButton.setChecked(False)
+    
+    def __setPyvenvVersion(self):
+        """
+        Private method to determine the pyvenv version and set the respective
+        label.
+        """
+        calls = []
+        if self.pythonExecEdit.text():
+            calls.append((self.pythonExecEdit.text(),
+                          ["-m", "venv"]))
+        calls.extend([
+            (sys.executable.replace("w.exe", ".exe"),
+             ["-m", "venv"]),
+            ("python3", ["-m", "venv"]),
+            ("python", ["-m", "venv"]),
+        ])
+        
+        proc = QProcess()
+        for prog, args in calls:
+            proc.start(prog, args)
+            
+            if not proc.waitForStarted(5000):
+                # try next entry
+                continue
+            
+            if not proc.waitForFinished(5000):
+                # process hangs, kill it
+                QTimer.singleShot(2000, proc.kill)
+                proc.waitForFinished(3000)
+                version = self.tr('<pyvenv did not finish within 5s.>')
+                self.__pyvenvFound = False
+                break
+            
+            if proc.exitCode() not in [0, 2]:
+                # returned with error code, try next
+                continue
+            
+            proc.start(prog, ["--version"])
+            proc.waitForFinished(5000)
+            output = str(proc.readAllStandardOutput(),
+                         Preferences.getSystem("IOEncoding"),
+                         'replace').strip()
+            match = re.match(self.__versionRe, output)
+            if match:
+                self.__pyvenvFound = True
+                version = match.group(1)
+                break
+        else:
+            self.__pyvenvFound = False
+            version = self.tr('<No suitable pyvenv found.>')
+        
+        self.pyvenvButton.setText(self.tr(
+            "pyvenv Version: {0}".format(version)))
+        self.pyvenvButton.setEnabled(self.__pyvenvFound)
+        if not self.__pyvenvFound:
+            self.pyvenvButton.setChecked(False)
+    
+    def __generateTargetDir(self):
+        """
+        Private method to generate a valid target directory path.
+        
+        @return target directory path (string)
+        """
+        targetDirectory = Utilities.toNativeSeparators(
+            self.targetDirectoryEdit.text())
+        if not os.path.isabs(targetDirectory):
+            targetDirectory = os.path.join(os.path.expanduser("~"),
+                                           targetDirectory)
+        return targetDirectory
+    
+    def __generateArguments(self):
+        """
+        Private method to generate the process arguments.
+        
+        @return process arguments (list of string)
+        """
+        args = []
+        if self.virtualenvButton.isChecked():
+            if self.extraSearchPathEdit.text():
+                args.append("--extra-search-dir={0}".format(
+                    Utilities.toNativeSeparators(
+                        self.extraSearchPathEdit.text())))
+            if self.promptPrefixEdit.text():
+                args.append("--prompt={0}".format(
+                    self.promptPrefixEdit.text().replace(" ", "_")))
+            if self.pythonExecEdit.text():
+                args.append("--python={0}".format(
+                    Utilities.toNativeSeparators(self.pythonExecEdit.text())))
+            elif self.versionComboBox.currentText():
+                args.append("--python=python{0}".format(
+                    self.versionComboBox.currentText()))
+            if self.verbositySpinBox.value() == 1:
+                args.append("--verbose")
+            elif self.verbositySpinBox.value() == -1:
+                args.append("--quiet")
+            if self.clearCheckBox.isChecked():
+                args.append("--clear")
+            if self.systemCheckBox.isChecked():
+                args.append("--system-site-packages")
+            if self.unzipCheckBox.isChecked():
+                args.append("--unzip-setuptools")
+            if self.noSetuptoolsCheckBox.isChecked():
+                args.append("--no-setuptools")
+            if self.noPipCcheckBox.isChecked():
+                args.append("--no-pip")
+            if self.copyCheckBox.isChecked():
+                args.append("--always-copy")
+        elif self.pyvenvButton.isChecked():
+            if self.clearCheckBox.isChecked():
+                args.append("--clear")
+            if self.systemCheckBox.isChecked():
+                args.append("--system-site-packages")
+            if self.noPipCcheckBox.isChecked():
+                args.append("--without-pip")
+            if self.copyCheckBox.isChecked():
+                args.append("--copies")
+            if self.symlinkCheckBox.isChecked():
+                args.append("--symlinks")
+            if self.upgradeCheckBox.isChecked():
+                args.append("--upgrade")
+        targetDirectory = self.__generateTargetDir()
+        args.append(targetDirectory)
+        return args
+
+    def getData(self):
+        """
+        Public method to retrieve the dialog data.
+        
+        @return tuple containing a flag indicating the pyvenv selection
+            (boolean), the process arguments (list of string), a flag
+            indicating to open the target directory after creation (boolean),
+            a flag indicating to write a log file (boolean), a flag indicating
+            to write a script (boolean), the name of the target directory
+            (string) and the name of the python interpreter to use (string)
+        """
+        args = self.__generateArguments()
+        targetDirectory = self.__generateTargetDir()
+        return (
+            self.pyvenvButton.isChecked(),
+            args,
+            self.openCheckBox.isChecked(),
+            self.logCheckBox.isChecked(),
+            self.scriptCheckBox.isChecked(),
+            targetDirectory,
+            Utilities.toNativeSeparators(self.pythonExecEdit.text()),
+        )

eric ide

mercurial