diff -r 8baaf3bce895 -r 2af01e538c57 VirtualEnv/VirtualenvConfigurationDialog.py --- a/VirtualEnv/VirtualenvConfigurationDialog.py Sat Jan 26 17:04:11 2019 +0100 +++ b/VirtualEnv/VirtualenvConfigurationDialog.py Sat Jan 26 19:42:53 2019 +0100 @@ -60,22 +60,43 @@ self.pythonExecPicker.setDefaultDirectory( sys.executable.replace("w.exe", ".exe")) + self.condaTargetDirectoryPicker.setMode( + E5PathPickerModes.DirectoryMode) + self.condaTargetDirectoryPicker.setWindowTitle( + self.tr("Conda Environment Location")) + self.condaTargetDirectoryPicker.setDefaultDirectory( + Utilities.getHomeDir()) + + self.condaCloneDirectoryPicker.setMode( + E5PathPickerModes.DirectoryMode) + self.condaCloneDirectoryPicker.setWindowTitle( + self.tr("Conda Environment Location")) + self.condaCloneDirectoryPicker.setDefaultDirectory( + Utilities.getHomeDir()) + self.__versionRe = re.compile(r""".*?(\d+\.\d+\.\d+).*""") self.__virtualenvFound = False self.__pyvenvFound = False + self.__condaFound = False self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) self.__mandatoryStyleSheet = "QLineEdit {border: 2px solid;}" self.targetDirectoryPicker.setStyleSheet(self.__mandatoryStyleSheet) self.nameEdit.setStyleSheet(self.__mandatoryStyleSheet) + self.condaTargetDirectoryPicker.setStyleSheet( + self.__mandatoryStyleSheet) + self.condaNameEdit.setStyleSheet(self.__mandatoryStyleSheet) self.__setVirtualenvVersion() self.__setPyvenvVersion() - if self.__virtualenvFound: + self.__setCondaVersion() + if self.__pyvenvFound: + self.pyvenvButton.setChecked(True) + elif self.__virtualenvFound: self.virtualenvButton.setChecked(True) - elif self.__pyvenvFound: - self.pyvenvButton.setChecked(True) + elif self.__condaFound: + self.condaButton.setChecked(True) msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -84,17 +105,28 @@ """ 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.targetDirectoryPicker.text()) and - bool(self.nameEdit.text()) - ) + if self.virtualenvButton.isChecked() or self.pyvenvButton.isChecked(): + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled( + (self.__virtualenvFound or self.__pyvenvFound) and + bool(self.targetDirectoryPicker.text()) and + bool(self.nameEdit.text()) + ) + elif self.condaButton.isChecked(): + enable = bool(self.condaNameEdit.text()) or \ + bool(self.condaTargetDirectoryPicker.text()) + if self.condaCloneGroup.isChecked(): + enable &= bool(self.condaCloneNameEdit.text()) or \ + bool(self.condaCloneDirectoryPicker.text()) + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable) + else: + self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) def __updateUi(self): """ Private method to update the UI depending on the selected virtual environment creator (virtualenv or pyvenv). """ + # venv page enable = self.virtualenvButton.isChecked() self.extraSearchPathLabel.setEnabled(enable) self.extraSearchPathPicker.setEnabled(enable) @@ -108,6 +140,19 @@ self.noSetuptoolsCheckBox.setEnabled(enable) self.symlinkCheckBox.setEnabled(not enable) self.upgradeCheckBox.setEnabled(not enable) + + # conda page + enable = not self.condaCloneGroup.isChecked() + self.condaPackagesEdit.setEnabled(enable) + self.condaPythonEdit.setEnabled(enable) + self.condaInsecureCheckBox.setEnabled(enable) + self.condaDryrunCheckBox.setEnabled(enable) + + # select page + if self.condaButton.isChecked(): + self.venvStack.setCurrentWidget(self.condaPage) + else: + self.venvStack.setCurrentWidget(self.venvPage) @pyqtSlot(str) def on_targetDirectoryPicker_textChanged(self, txt): @@ -151,6 +196,64 @@ """ self.__updateUi() + @pyqtSlot(bool) + def on_condaButton_toggled(self, checked): + """ + Private slot to react to the selection of 'conda'. + + @param checked state of the checkbox + @type bool + """ + self.__updateUi() + + @pyqtSlot(str) + def on_condaNameEdit_textChanged(self, txt): + """ + Private slot handling a change of the conda environment name. + + @param txt environment name + @type str + """ + self.__updateOK() + + @pyqtSlot(str) + def on_condaTargetDirectoryPicker_textChanged(self, txt): + """ + Private slot handling a change of the conda target directory. + + @param txt target directory + @type str + """ + self.__updateOK() + + @pyqtSlot() + def on_condaCloneGroup_clicked(self): + """ + Private slot handling the selection of the clone group. + """ + self.__updateOK() + self.__updateUi() + + @pyqtSlot(str) + def on_condaCloneNameEdit_textChanged(self, txt): + """ + Private slot handling a change of the conda source environment name. + + @param txt name of the environment to be cloned + @type str + """ + self.__updateOK() + + @pyqtSlot(str) + def on_condaCloneDirectoryPicker_textChanged(self, txt): + """ + Private slot handling a change of the cloned from directory. + + @param txt target directory + @type str + """ + self.__updateOK() + def __setVirtualenvVersion(self): """ Private method to determine the virtualenv version and set the @@ -259,6 +362,38 @@ if not self.__pyvenvFound: self.pyvenvButton.setChecked(False) + def __setCondaVersion(self): + """ + Private method to determine the conda version and set the respective + label. + """ + exe = Preferences.getConda("CondaExecutable") + if not exe: + exe = "conda" + + proc = QProcess() + proc.start(exe, ["--version"]) + if not proc.waitForStarted(5000): + self.__condaFound = False + version = self.tr('<conda not found or not configured.>') + else: + proc.waitForFinished(5000) + output = str(proc.readAllStandardOutput(), + Preferences.getSystem("IOEncoding"), + 'replace').strip() + match = re.match(self.__versionRe, output) + if match: + self.__condaFound = True + version = match.group(1) + else: + self.__condaFound = False + version = self.tr('<conda returned strange version info.') + self.condaButton.setText(self.tr( + "conda Version: {0}".format(version))) + self.condaButton.setEnabled(self.__condaFound) + if not self.__condaFound: + self.condaButton.setChecked(False) + def __generateTargetDir(self): """ Private method to generate a valid target directory path. @@ -281,75 +416,97 @@ @rtype list of str """ args = [] - if self.virtualenvButton.isChecked(): - if self.extraSearchPathPicker.text(): - args.append("--extra-search-dir={0}".format( - Utilities.toNativeSeparators( - self.extraSearchPathPicker.text()))) - if self.promptPrefixEdit.text(): - args.append("--prompt={0}".format( - self.promptPrefixEdit.text().replace(" ", "_"))) - if self.pythonExecPicker.text(): - args.append("--python={0}".format( - Utilities.toNativeSeparators( - self.pythonExecPicker.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) + if self.condaButton.isChecked(): + # TODO: assemble the conda arguments + pass + else: + if self.virtualenvButton.isChecked(): + if self.extraSearchPathPicker.text(): + args.append("--extra-search-dir={0}".format( + Utilities.toNativeSeparators( + self.extraSearchPathPicker.text()))) + if self.promptPrefixEdit.text(): + args.append("--prompt={0}".format( + self.promptPrefixEdit.text().replace(" ", "_"))) + if self.pythonExecPicker.text(): + args.append("--python={0}".format( + Utilities.toNativeSeparators( + self.pythonExecPicker.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, the - process arguments, a name for the virtual environment, a flag - indicating to open the target directory after creation, a flag - indicating to write a log file, a flag indicating to write a - script, the name of the target directory and the name of the - Python interpreter to use - @rtype tuple of (bool, list of str, str, bool, bool, bool, str, str) + @return dictionary containing the data for the two environment + variants. The keys for both variants are 'arguments' containing the + command line arguments, 'logicalName' containing the environment + name to be used with the virtual env manager and 'envType' + containing the environment type (virtualenv, pyvenv or conda). The + virtualenv/pyvenv specific keys are 'openTarget' containg a flag to + open the target directory after creation, 'createLog' containing a + flag to write a log file, 'createScript' containing a flag to write + a script, 'targetDirectory' containing the target directory and + 'pythonExe' containing the Python interpreter to be used. The conda + specific keys are + @rtype dict """ + # TODO: add the conda keys to the above description + # TODO: change to returning a method specific dictionary args = self.__generateArguments() - targetDirectory = self.__generateTargetDir() - return ( - self.pyvenvButton.isChecked(), - args, - self.nameEdit.text(), - self.openCheckBox.isChecked(), - self.logCheckBox.isChecked(), - self.scriptCheckBox.isChecked(), - targetDirectory, - Utilities.toNativeSeparators(self.pythonExecPicker.text()), - ) + resultDict = { + "arguments": args, + "logicalName": self.nameEdit.text(), + } + if self.condaButton.isChecked(): + resultDict.update({ + "envType": "conda", + }) + else: + resultDict.update({ + "envType": ("pyvenv" if self.pyvenvButton.isChecked() else + "virtualenv"), + "openTarget": self.openCheckBox.isChecked(), + "createLog": self.logCheckBox.isChecked(), + "createScript":self.scriptCheckBox.isChecked(), + "targetDirectory": self.__generateTargetDir(), + "pythonExe": Utilities.toNativeSeparators( + self.pythonExecPicker.text()), + }) + + return resultDict