Tue, 12 Jun 2018 19:01:06 +0200
pip Interface: changed to use the new VirtualEnv Manager
--- a/Plugins/PluginPipInterface.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/PluginPipInterface.py Tue Jun 12 19:01:06 2018 +0200 @@ -9,15 +9,12 @@ from __future__ import unicode_literals -import os -import platform -from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication, QProcess +from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication from E5Gui.E5Application import e5App import Preferences -import Utilities import UI.Info # Start-Of-Header @@ -58,19 +55,17 @@ "PipInterfacePlugin", "Package Management - pip"), "exe": "dummyExe", "versionCommand": "--version", - "versionStartsWith": "dummyExe", + "versionStartsWith": "pip", "versionPosition": 1, "version": "", "versionCleanup": None, + "exeModule": ["-m", "pip"], } - if pipPluginObject is not None: - executables = pipPluginObject.getPreferences("PipExecutables") - if not executables: - executables = ["pip3", "pip2", "pip"] - for exePath in executables: - data["exe"] = exePath - data["versionStartsWith"] = "pip" - dataList.append(data.copy()) + virtualenvManager = e5App().getObject("VirtualEnvManager") + for venvName in virtualenvManager.getVirtualenvNames(): + interpreter = virtualenvManager.getVirtualenvInterpreter(venvName) + data["exe"] = interpreter + dataList.append(data.copy()) return dataList @@ -111,142 +106,16 @@ Preferences.Prefs.settings.remove(PipInterfacePlugin.PreferencesKey) -def _findDefaultExecutables(majorVersion): - """ - Restricted function to determine the name and path of the executables. - - @param majorVersion major python version of the executables (int) - @return path names of the executables (list of string) - """ - # Determine Python Version - if majorVersion == 3: - minorVersions = range(10) - elif majorVersion == 2: - minorVersions = range(6, 8) - else: - return [] - - executables = set() - if Utilities.isWindowsPlatform(): - # - # Windows - # - try: - import winreg - except ImportError: - import _winreg as winreg # __IGNORE_WARNING__ - - def getExePath(branch, access, versionStr): - exes = [] - try: - software = winreg.OpenKey(branch, 'Software', 0, access) - python = winreg.OpenKey(software, 'Python', 0, access) - pcore = winreg.OpenKey(python, 'PythonCore', 0, access) - version = winreg.OpenKey(pcore, versionStr, 0, access) - installpath = winreg.QueryValue(version, 'InstallPath') - exe = os.path.join(installpath, 'Scripts', 'pip.exe') - if os.access(exe, os.X_OK): - exes.append(exe) - except (WindowsError, OSError): # __IGNORE_WARNING__ - pass - return exes - - versionSuffixes = ["", "-32", "-64"] - for minorVersion in minorVersions: - for versionSuffix in versionSuffixes: - versionStr = '{0}.{1}{2}'.format(majorVersion, minorVersion, - versionSuffix) - exePaths = getExePath( - winreg.HKEY_CURRENT_USER, - winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) - for exePath in exePaths: - executables.add(exePath) - - exePaths = getExePath( - winreg.HKEY_LOCAL_MACHINE, - winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) - for exePath in exePaths: - executables.add(exePath) - - # Even on Intel 64-bit machines it's 'AMD64' - if platform.machine() == 'AMD64': - exePaths = getExePath( - winreg.HKEY_CURRENT_USER, - winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) - for exePath in exePaths: - executables.add(exePath) - - exePath = getExePath( - winreg.HKEY_LOCAL_MACHINE, - winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) - for exePath in exePaths: - executables.add(exePath) - else: - # - # Linux, Unix ... - pipScript = 'pip' - scriptSuffixes = ["", - "{0}".format(majorVersion), - "-{0}".format(majorVersion), - ] - for minorVersion in minorVersions: - scriptSuffixes.append( - "{0}.{1}".format(majorVersion, minorVersion)) - scriptSuffixes.append( - "-{0}.{1}".format(majorVersion, minorVersion)) - # There could be multiple pip executables in the path - # e.g. for different python variants - path = Utilities.getEnvironmentEntry('PATH') - # environment variable not defined - if path is None: - return [] - - # step 1: determine possible candidates - exes = [] - dirs = path.split(os.pathsep) - for directory in dirs: - for suffix in scriptSuffixes: - exe = os.path.join(directory, pipScript + suffix) - if os.access(exe, os.X_OK): - exes.append(exe) - - # step 2: determine the Python variant - _exePy2 = set() - _exePy3 = set() - versionArgs = ["-c", "import sys; print(sys.version_info[0])"] - for exe in exes: - try: - f = open(exe, "r") - line0 = f.readline() - program = line0.replace("#!", "").strip() - process = QProcess() - process.start(program, versionArgs) - process.waitForFinished(5000) - # get a QByteArray of the output - versionBytes = process.readAllStandardOutput() - versionStr = str(versionBytes, encoding='utf-8').strip() - if versionStr == "3": - _exePy3.add(exe) - elif versionStr == "2": - _exePy2.add(exe) - finally: - f.close() - - executables = _exePy3 if majorVersion == 3 else _exePy2 - - return list(executables) - - class PipInterfacePlugin(QObject): """ Class implementing the pip interface plug-in. - @signal currentPipChanged(exe) emitted to signal a change of the current - pip executable + @signal currentEnvironmentChanged(str) emitted to signal a change of the + currently selected virtual environment """ PreferencesKey = "PipPlugin" - currentPipChanged = pyqtSignal(str) + currentEnvironmentChanged = pyqtSignal(str) def __init__(self, ui): """ @@ -259,8 +128,7 @@ self.__initialize() self.__defaults = { - "PipExecutables": [], - "CurrentPipExecutable": "", + "CurrentEnvironment": "", "PipSearchIndex": "", # used by the search command } @@ -277,7 +145,8 @@ """ Public method to activate this plugin. - @return tuple of None and activation status (boolean) + @return tuple of None and activation status + @rtype tuple of (None, bool) """ global error error = "" # clear previous error @@ -294,23 +163,6 @@ self.__mainMenu = self.__object.initMenu() self.__mainAct = menu.addMenu(self.__mainMenu) - if self.getPreferences("PipExecutables"): - # remove all executables, that don't exist anymore - executables = [] - for executable in self.getPreferences("PipExecutables"): - if os.access(executable, os.X_OK): - executables.append(executable) - self.setPreferences("PipExecutables", executables) - - current = self.getPreferences("CurrentPipExecutable") - if current not in executables: - current = "" - self.setPreferences("CurrentPipExecutable", current) - else: - # load the list with default executables - self.setPreferences("PipExecutables", - self.getDefaultPipExecutables()) - return None, True def deactivate(self): @@ -327,38 +179,40 @@ def getPreferences(self, key): """ - Public method to retrieve the various refactoring settings. + Public method to retrieve the various pip related settings. @param key the key of the value to get - @return the requested refactoring setting + @type str + @return the requested setting + @rtype any """ - if key in ["PipExecutables"]: - return Preferences.toList(Preferences.Prefs.settings.value( - self.PreferencesKey + "/" + key, self.__defaults[key])) - else: - return Preferences.Prefs.settings.value( - self.PreferencesKey + "/" + key, self.__defaults[key]) + return Preferences.Prefs.settings.value( + self.PreferencesKey + "/" + key, self.__defaults[key]) def setPreferences(self, key, value): """ - Public method to store the various refactoring settings. + Public method to store the various pip related settings. - @param key the key of the setting to be set (string) + @param key the key of the setting to be set + @type str @param value the value to be set + @type any """ Preferences.Prefs.settings.setValue( self.PreferencesKey + "/" + key, value) - if key == "CurrentPipExecutable": - self.currentPipChanged.emit(value) + if key == "CurrentEnvironment": + self.currentEnvironmentChanged.emit(value) def getMenu(self, name): """ Public method to get a reference to the requested menu. - @param name name of the menu (string) - @return reference to the menu (QMenu) or None, if no + @param name name of the menu + @type str + @return reference to the menu or None, if no menu with the given name exists + @rtype QMenu or None """ if self.__object is not None: return self.__object.getMenu(name) @@ -369,20 +223,13 @@ """ Public method to get the names of all menus. - @return menu names (list of string) + @return menu names + @rtype list of str """ if self.__object is not None: return list(self.__menus.keys()) else: return [] - - def getDefaultPipExecutables(self): - """ - Public method to get the default list of pip executables. - - @return list of pip executables (list of string) - """ - return _findDefaultExecutables(2) + _findDefaultExecutables(3) # # eflag: noqa = M801
--- a/Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.py Tue Jun 12 19:01:06 2018 +0200 @@ -4,35 +4,28 @@ # """ -Package implementing the configuration page. +Package implementing the pip configuration page. """ from __future__ import unicode_literals -import os - -from PyQt5.QtCore import pyqtSlot, Qt, QSortFilterProxyModel, QStringListModel - -from E5Gui import E5FileDialog - from Preferences.ConfigurationPages.ConfigurationPageBase import \ ConfigurationPageBase from .Ui_PipPage import Ui_PipPage from .. import DefaultPyPiUrl -import Utilities - class PipPage(ConfigurationPageBase, Ui_PipPage): """ - Class implementing the configuration page. + Class implementing the pip configuration page. """ def __init__(self, plugin): """ Constructor @param plugin reference to the plugin object + @type PipInterfacePlugin """ super(PipPage, self).__init__() self.setupUi(self) @@ -40,71 +33,17 @@ self.__plugin = plugin - self.__model = QStringListModel(self) - self.__proxyModel = QSortFilterProxyModel(self) - self.__proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) - self.__proxyModel.setSourceModel(self.__model) - self.stringList.setModel(self.__proxyModel) - - self.removeButton.clicked.connect(self.stringList.removeSelected) - self.removeAllButton.clicked.connect(self.stringList.removeAll) - self.indexLabel.setText(self.tr( '<b>Note:</b> Leave empty to use the default index URL (' '<a href="{0}">{0}</a>).') .format(DefaultPyPiUrl)) # set initial values - self.__model.setStringList( - self.__plugin.getPreferences("PipExecutables")) - self.__model.sort(0) self.indexEdit.setText(self.__plugin.getPreferences("PipSearchIndex")) - @pyqtSlot() - def on_addButton_clicked(self): - """ - Private slot used to add an executable to the list. - """ - executable = E5FileDialog.getOpenFileName( - self, - self.tr("Add pip executable"), - os.path.expanduser("~"), - "") - executable = Utilities.toNativeSeparators(executable) - if executable != "" and executable not in self.__model.stringList(): - self.__model.insertRow(self.__model.rowCount()) - self.__model.setData( - self.__model.index(self.__model.rowCount() - 1), executable) - self.__model.sort(0) - - @pyqtSlot() - def on_defaultListButton_clicked(self): - """ - Private slot to load the default list of pip executables. - """ - self.stringList.removeAll() - defaults = self.__plugin.getDefaultPipExecutables() - for executable in defaults: - self.__model.insertRow(self.__model.rowCount()) - self.__model.setData( - self.__model.index(self.__model.rowCount() - 1), executable) - self.__model.sort(0) - def save(self): """ Public slot to save the pip configuration. """ - executables = self.__model.stringList()[:] - self.__plugin.setPreferences( - "PipExecutables", executables) self.__plugin.setPreferences( "PipSearchIndex", self.indexEdit.text().strip()) - if executables: - if self.__plugin.getPreferences("CurrentPipExecutable") \ - not in executables: - self.__plugin.setPreferences( - "CurrentPipExecutable", "") - else: - # reset the current executable if none have been configured - self.__plugin.setPreferences( - "CurrentPipExecutable", "")
--- a/Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.ui Tue Jun 12 19:01:06 2018 +0200 @@ -58,115 +58,22 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>pip Executables</string> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0" rowspan="7"> - <widget class="E5ListView" name="stringList"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="selectionMode"> - <enum>QAbstractItemView::ExtendedSelection</enum> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="addButton"> - <property name="toolTip"> - <string>Press to add an entry</string> - </property> - <property name="text"> - <string>&Add...</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="Line" name="line_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QPushButton" name="removeButton"> - <property name="toolTip"> - <string>Press to remove the selected entries</string> - </property> - <property name="text"> - <string>&Remove</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QPushButton" name="removeAllButton"> - <property name="toolTip"> - <string>Press to remove all entries</string> - </property> - <property name="text"> - <string>R&emove All</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="Line" name="line_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QPushButton" name="defaultListButton"> - <property name="toolTip"> - <string>Press to load the default list</string> - </property> - <property name="text"> - <string>&Default</string> - </property> - </widget> - </item> - <item row="6" column="1"> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>196</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>234</height> + </size> + </property> + </spacer> </item> </layout> </widget> - <customwidgets> - <customwidget> - <class>E5ListView</class> - <extends>QListView</extends> - <header>E5Gui/E5ListView.h</header> - </customwidget> - </customwidgets> <tabstops> <tabstop>indexEdit</tabstop> - <tabstop>stringList</tabstop> - <tabstop>addButton</tabstop> - <tabstop>removeButton</tabstop> - <tabstop>removeAllButton</tabstop> </tabstops> <resources/> <connections/>
--- a/Plugins/UiExtensionPlugins/PipInterface/Pip.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/Pip.py Tue Jun 12 19:01:06 2018 +0200 @@ -14,23 +14,22 @@ pass import os -import re import sys -from PyQt5.QtCore import pyqtSlot, QObject, QProcess, QDir +from PyQt5.QtCore import pyqtSlot, QObject, QProcess from PyQt5.QtWidgets import QMenu, QInputDialog, QDialog -from E5Gui import E5MessageBox, E5FileDialog +from E5Gui import E5MessageBox from E5Gui.E5Action import E5Action from E5Gui.E5Application import e5App from .PipDialog import PipDialog +from . import DefaultIndexUrlXml import Preferences import Globals -# TODO: 1) change all uses of pip to python3 -m pip class Pip(QObject): """ Class implementing the pip GUI logic. @@ -40,38 +39,42 @@ Constructor @param plugin reference to the plugin object - @param parent parent (QObject) + @type PipInterfacePlugin + @param parent parent + @type QObject """ super(Pip, self).__init__(parent) self.__plugin = plugin self.__ui = parent + self.__virtualenvManager = e5App().getObject("VirtualEnvManager") + self.__menus = {} # dictionary with references to menus - self.__plugin.currentPipChanged.connect(self.__handleTearOffMenu) + self.__plugin.currentEnvironmentChanged.connect( + self.__handleTearOffMenu) def initActions(self): """ - Public method to define the Django actions. + Public method to define the actions. """ self.actions = [] - self.selectExecutableAct = E5Action( - self.tr('pip Executable'), - self.tr('pip &Executable'), + self.selectEnvironmentAct = E5Action( + self.tr('Virtual Environment for pip'), + self.tr('&Virtual Environment for pip'), 0, 0, - self, 'pip_select_executable') - self.selectExecutableAct.setStatusTip(self.tr( - 'Selects the pip executable to be used')) - self.selectExecutableAct.setWhatsThis(self.tr( - """<b>pip Executable</b>""" - """<p>This selects the pip executable to be used. Multiple""" - """ executables can be pre-configured via the configuration""" - """ dialog.</p>""" + self, 'pip_select_environment') + self.selectEnvironmentAct.setStatusTip(self.tr( + 'Selects the virtual environment to be used for pip')) + self.selectEnvironmentAct.setWhatsThis(self.tr( + """<b>Virtual Environment for pip</b>""" + """<p>This selects the virtual environment to be used for pip.""" + """</p>""" )) - self.selectExecutableAct.triggered.connect(self.__selectPipExecutable) - self.actions.append(self.selectExecutableAct) + self.selectEnvironmentAct.triggered.connect(self.__selectPipVirtualenv) + self.actions.append(self.selectEnvironmentAct) ############################################## ## Actions for listing packages @@ -184,26 +187,9 @@ """<b>Install Pip</b>""" """<p>This installs the pip package itself.</p>""" )) - self.installPipAct.triggered.connect( - lambda: self.__installPip(userSite=False)) + self.installPipAct.triggered.connect(self.__installPip) self.actions.append(self.installPipAct) - self.installPipUserAct = E5Action( - self.tr('Install Pip to User-Site'), - self.tr('Install Pip to User-Site'), - 0, 0, - self, 'pip_install_pip_user') - self.installPipUserAct.setStatusTip(self.tr( - 'Install the pip package itself to the user directory')) - self.installPipUserAct.setWhatsThis(self.tr( - """<b>Install Pip to User-Site</b>""" - """<p>This installs the pip package itself to the user""" - """ directory.</p>""" - )) - self.installPipUserAct.triggered.connect( - lambda: self.__installPip(userSite=True)) - self.actions.append(self.installPipUserAct) - self.repairPipAct = E5Action( self.tr('Repair Pip'), self.tr('Repair Pip'), @@ -371,23 +357,23 @@ def initMenu(self): """ - Public slot to initialize the Django menu. + Public slot to initialize the menu. - @return the menu generated (QMenu) + @return the menu generated + @rtype QMenu """ self.__menus = {} # clear menus references menu = QMenu(self.tr('P&ython Package Management'), self.__ui) menu.setTearOffEnabled(True) - menu.addAction(self.selectExecutableAct) + menu.addAction(self.selectEnvironmentAct) menu.addSeparator() menu.addAction(self.listPackagesAct) menu.addAction(self.listUptodatePackagesAct) menu.addAction(self.listOutdatedPackagesAct) menu.addSeparator() menu.addAction(self.installPipAct) - menu.addAction(self.installPipUserAct) menu.addSeparator() menu.addAction(self.installPackagesAct) menu.addAction(self.installLocalPackageAct) @@ -420,11 +406,10 @@ """ Private slot to set the action enabled status. """ - enable = bool(self.__plugin.getPreferences("CurrentPipExecutable")) + enable = bool(self.__plugin.getPreferences("CurrentEnvironment")) for act in self.actions: - if act not in [self.selectExecutableAct, + if act not in [self.selectEnvironmentAct, self.installPipAct, - self.installPipUserAct, self.editUserConfigAct, self.editVirtualenvConfigAct, self.pipConfigAct]: @@ -434,9 +419,11 @@ """ Public method to get a reference to the requested menu. - @param name name of the menu (string) - @return reference to the menu (QMenu) or None, if no + @param name name of the menu + @type str + @return reference to the menu or None, if no menu with the given name exists + @rtype QMenu or None """ if name in self.__menus: return self.__menus[name] @@ -447,29 +434,30 @@ """ Public method to get the names of all menus. - @return menu names (list of string) + @return menu names + @rtype list of str """ return list(self.__menus.keys()) - def __handleTearOffMenu(self, pip): + def __handleTearOffMenu(self, venvName): """ - Private slot to handle a change of the pip executable. + Private slot to handle a change of the selected virtual environment. - @param pip path of the pip executable + @param venvName logical name of the virtual environment @type str """ if self.__menus["main"].isTearOffMenuVisible(): # determine, if torn off menu needs to be refreshed enabled = self.listPackagesAct.isEnabled() - if ((bool(pip) and not enabled) or - (not bool(pip) and enabled)): + if ((bool(venvName) and not enabled) or + (not bool(venvName) and enabled)): self.__menus["main"].hideTearOffMenu() ########################################################################## ## Methods below implement some utility functions ########################################################################## - def runProcess(self, args, cmd=""): + def runProcess(self, args, interpreter): """ Public method to execute the current pip with the given arguments. @@ -478,18 +466,16 @@ @param args list of command line arguments @type list of str - @param cmd pip executable to be used + @param interpreter path of the Python interpreter to be used @type str @return tuple containing a flag indicating success and the output of the process @rtype tuple of (bool, str) """ - if not cmd: - cmd = self.__plugin.getPreferences("CurrentPipExecutable") ioEncoding = Preferences.getSystem("IOEncoding") process = QProcess() - process.start(cmd, args) + process.start(interpreter, args) procStarted = process.waitForStarted() if procStarted: finished = process.waitForFinished(30000) @@ -499,22 +485,25 @@ 'replace') return True, output else: - return False, self.tr("pip exited with an error ({0}).")\ - .format(process.exitCode()) + return (False, + self.tr("python exited with an error ({0}).") + .format(process.exitCode())) else: process.terminate() process.waitForFinished(2000) process.kill() process.waitForFinished(3000) - return False, self.tr("pip did not finish within 30 seconds.") + return False, self.tr("python did not finish within" + " 30 seconds.") - return False, self.tr("pip could not be started.") + return False, self.tr("python could not be started.") def __getUserConfig(self): """ Private method to get the name of the user configuration file. - @return path of the user configuration file (string) + @return path of the user configuration file + @rtype str """ # Unix: ~/.config/pip/pip.conf # OS X: ~/Library/Application Support/pip/pip.conf @@ -540,7 +529,8 @@ """ Private method to get the name of the virtualenv configuration file. - @return path of the virtualenv configuration file (string) + @return path of the virtualenv configuration file + @rtype str """ # Unix, OS X: $VIRTUAL_ENV/pip.conf # Windows: %VIRTUAL_ENV%\pip.ini @@ -550,48 +540,86 @@ else: pip = "pip.conf" try: - virtualenv = os.environ["VIRTUAL_ENV"] + venvDirectory = os.environ["VIRTUAL_ENV"] except KeyError: - # determine from pip executable file - virtualenv = os.path.dirname(os.path.dirname( - self.__plugin.getPreferences("CurrentPipExecutable"))) + venvName = self.__plugin.getPreferences("CurrentEnvironment") + venvDirectory = self.__virtualenvManager.getVirtualenvDirectory( + venvName) + + return os.path.join(venvDirectory, pip) + + def getDefaultEnvironmentString(self): + """ + Public method to get the string for the default environment. + + @return string for the default environment + @rtype str + """ + return self.tr("<default>") + + def getVirtualenvInterpreter(self, venvName): + """ + Public method to get the interpreter for a virtual environment. - return os.path.join(virtualenv, pip) + @param venvName logical name for the virtual environment + @type str + @return interpreter path + @rtype str + """ + if venvName == self.getDefaultEnvironmentString(): + venvName = self.__plugin.getPreferences("CurrentEnvironment") + + interpreter = self.__virtualenvManager.getVirtualenvInterpreter( + venvName) + if not interpreter: + E5MessageBox.critical( + None, + self.tr("Interpreter for Virtual Environment"), + self.tr("""No interpreter configured for the selected""" + """ virtual environment.""")) + + return interpreter + + def getVirtualenvNames(self): + """ + Public method to get a sorted list of virtual environment names. + + @return sorted list of virtual environment names + @rtype list of str + """ + return sorted(self.__virtualenvManager.getVirtualenvNames()) ########################################################################## ## Methods below implement the individual menu entries ########################################################################## - def __selectPipExecutable(self): + def __selectPipVirtualenv(self): """ - Private method to select the pip executable to be used. + Private method to select the virtual environment to be used. """ - pipExecutables = sorted(self.__plugin.getPreferences("PipExecutables")) - if pipExecutables: - currentExecutable = self.__plugin.getPreferences( - "CurrentPipExecutable") + environments = self.getVirtualenvNames() + if environments: + currentEnvironment = self.__plugin.getPreferences( + "CurrentEnvironment") try: - index = pipExecutables.index(currentExecutable) + index = environments.index(currentEnvironment) except ValueError: index = 0 - executable, ok = QInputDialog.getItem( + environment, ok = QInputDialog.getItem( None, - self.tr("pip Executable"), - self.tr("Select pip Executable to be used:"), - pipExecutables, index, False) + self.tr("Virtual Environment for pip"), + self.tr("Select the virtual environment to be used:"), + environments, index, False) - if ok and executable: - self.__plugin.setPreferences("CurrentPipExecutable", - executable) + if ok and environment: + self.__plugin.setPreferences("CurrentEnvironment", + environment) else: - res = E5MessageBox.yesNo( + E5MessageBox.warning( None, - self.tr("pip Executable"), - self.tr("""No pip executables have been configured yet.""" - """ Shall this be done now?"""), - yesDefault=True) - if res: - e5App().getObject("UserInterface").showPreferences("pipPage") + self.tr("Virtual Environment for pip"), + self.tr("""No virtual environments have been configured yet.""" + """ Please use the Virtualenv Manager to do that.""")) def __listPackages(self): """ @@ -599,7 +627,8 @@ """ from .PipListDialog import PipListDialog self.__listDialog = PipListDialog( - self, "list", self.__plugin, self.tr("Installed Packages")) + self, "list", self.__plugin.getPreferences("PipSearchIndex"), + self.tr("Installed Packages")) self.__listDialog.show() self.__listDialog.start() @@ -609,7 +638,8 @@ """ from .PipListDialog import PipListDialog self.__listUptodateDialog = PipListDialog( - self, "uptodate", self.__plugin, self.tr("Up-to-date Packages")) + self, "uptodate", self.__plugin.getPreferences("PipSearchIndex"), + self.tr("Up-to-date Packages")) self.__listUptodateDialog.show() self.__listUptodateDialog.start() @@ -619,7 +649,8 @@ """ from .PipListDialog import PipListDialog self.__listOutdatedDialog = PipListDialog( - self, "outdated", self.__plugin, self.tr("Outdated Packages")) + self, "outdated", self.__plugin.getPreferences("PipSearchIndex"), + self.tr("Outdated Packages")) self.__listOutdatedDialog.show() self.__listOutdatedDialog.start() @@ -640,7 +671,8 @@ Private method to edit a configuration. @param virtualenv flag indicating to edit the current virtualenv - configuration file (boolean) + configuration file + @type bool """ from QScintilla.MiniEditor import MiniEditor if virtualenv: @@ -652,7 +684,7 @@ E5MessageBox.critical( None, self.tr("Edit Configuration"), - self.tr("""No valid configuartion path determined.""" + self.tr("""No valid configuration path determined.""" """ Is a virtual environment selected? Aborting""")) return @@ -663,7 +695,7 @@ E5MessageBox.critical( None, self.tr("Edit Configuration"), - self.tr("""No valid configuartion path determined.""" + self.tr("""No valid configuration path determined.""" """ Is a virtual environment selected? Aborting""")) return @@ -696,50 +728,43 @@ directory @type bool """ - python = E5FileDialog.getOpenFileName( - None, - self.tr("Select Python Executable")) - if python: - python = QDir.toNativeSeparators(python) - dia = PipDialog(self.tr('Install PIP')) - if userSite: - commands = [(python, ["-m", "ensurepip", "--user"])] - else: - commands = [(python, ["-m", "ensurepip"])] - if self.__plugin.getPreferences("PipSearchIndex"): - indexUrl = \ - self.__plugin.getPreferences("PipSearchIndex") + "/simple" - args = ["-m", "pip", "install", "--index-url", indexUrl, - "--upgrade"] - else: - args = ["-m", "pip", "install", "--upgrade"] - if userSite: - args.append("--user") - args.append("pip") - commands.append((python, args[:])) + from .PipSelectionDialog import PipSelectionDialog + dlg = PipSelectionDialog(self) + if dlg.exec_() != QDialog.Accepted: + return + + venvName, userSite = dlg.getData() + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return - res = dia.startProcesses(commands) - if res: - dia.exec_() - pip = E5FileDialog.getOpenFileName( - None, - self.tr("Select PIP Executable"), - os.path.dirname(python)) - if pip: - pip = QDir.toNativeSeparators(pip) - pipExecutables = \ - self.__plugin.getPreferences("PipExecutables") - if pip not in pipExecutables: - pipExecutables.append(pip) - self.__plugin.setPreferences( - "PipExecutables", pipExecutables) + dia = PipDialog(self.tr('Install PIP')) + if userSite: + commands = [(interpreter, ["-m", "ensurepip", "--user"])] + else: + commands = [(interpreter, ["-m", "ensurepip"])] + if self.__plugin.getPreferences("PipSearchIndex"): + indexUrl = \ + self.__plugin.getPreferences("PipSearchIndex") + "/simple" + args = ["-m", "pip", "install", "--index-url", indexUrl, + "--upgrade"] + else: + args = ["-m", "pip", "install", "--upgrade"] + if userSite: + args.append("--user") + args.append("pip") + commands.append((interpreter, args[:])) + + res = dia.startProcesses(commands) + if res: + dia.exec_() @pyqtSlot() - def upgradePip(self, pip="", userSite=False): + def upgradePip(self, venvName="", userSite=False): """ Public method to upgrade pip itself. - @param pip pip command to be used + @param venvName name of the virtual environment to be used @type str @param userSite flag indicating an install to the user install directory @@ -750,27 +775,17 @@ # Upgrading pip needs to be treated specially because # it must be done using the python executable - if not pip: + if not venvName: from .PipSelectionDialog import PipSelectionDialog - dlg = PipSelectionDialog(self.__plugin) + dlg = PipSelectionDialog(self) if dlg.exec_() != QDialog.Accepted: return - pip, userSite = dlg.getData() - - if not pip: - pip = self.__plugin.getPreferences("CurrentPipExecutable") + venvName, userSite = dlg.getData() - python = self.__getPython(pip) - if not python: - python = E5FileDialog.getOpenFileName( - None, - self.tr("Select Python Executable"), - os.path.dirname(pip)) - if python: - python = QDir.toNativeSeparators(python) - else: - return False + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ @@ -784,7 +799,7 @@ args.append("pip") dia = PipDialog(self.tr('Upgrade PIP')) - res = dia.startProcess(python, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() return res @@ -798,27 +813,16 @@ @rtype bool """ from .PipSelectionDialog import PipSelectionDialog - dlg = PipSelectionDialog(self.__plugin) + dlg = PipSelectionDialog(self) if dlg.exec_() != QDialog.Accepted: return False - pip, userSite = dlg.getData() - - if not pip: - pip = self.__plugin.getPreferences("CurrentPipExecutable") + venvName, userSite = dlg.getData() + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return - python = self.__getPython(pip) - if not python: - python = E5FileDialog.getOpenFileName( - None, - self.tr("Select Python Executable"), - os.path.dirname(pip)) - if python: - python = QDir.toNativeSeparators(python) - else: - return False - - # pip install --ignore-installed pip + # python -m pip install --ignore-installed pip if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" @@ -831,55 +835,10 @@ args.append("pip") dia = PipDialog(self.tr('Repair PIP')) - res = dia.startProcess(python, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() - def __getPython(self, cmd): - """ - Private method to derive the path to the python executable given the - path to the pip executable. - - @param cmd path of the pip executable - @type str - @return path of the python executable - @rtype str - """ - path, prog = os.path.split(cmd) - paths = (path, os.path.split(path)[0]) # to try the parent directory - if Globals.isWindowsPlatform(): - subPatterns = ((r"\d\.\d", ""), - (r"\d\.", ".")) - for pyname in ("python", "pypy"): - python = prog.replace("pip", pyname) - for pattern, repl in subPatterns: - if re.search(pattern, python): - python = re.sub(pattern, repl, python) - break - for path in paths: - pypath = os.path.join(path, python) - if os.path.exists(pypath): - return pypath - else: - subPatterns = ((r"\.\d$", ""), - (r"\d\.\d$", ""), - (r"\d$", "")) - for pyname in ("python", "pypy"): - python = prog.replace("pip", pyname) - for path in paths: - pypath = os.path.join(path, python) - if os.path.exists(pypath): - return pypath - - for pattern, repl in subPatterns: - if re.search(pattern, cmd): - newpy = re.sub(pattern, repl, python) - pypath = os.path.join(path, newpy) - if os.path.exists(pypath): - return pypath - - return "" - def __checkUpgradePyQt(self, packages): """ Private method to check, if an upgrade of PyQt packages is attempted. @@ -906,13 +865,13 @@ return abort - def upgradePackages(self, packages, cmd="", userSite=False): + def upgradePackages(self, packages, venvName="", userSite=False): """ Public method to upgrade the given list of packages. @param packages list of packages to upgrade @type list of str - @param cmd pip command to be used + @param venvName name of the virtual environment to be used @type str @param userSite flag indicating an install to the user install directory @@ -923,19 +882,24 @@ if self.__checkUpgradePyQt(packages): return False - if not cmd: - cmd = self.__plugin.getPreferences("CurrentPipExecutable") + if not venvName: + venvName = self.__plugin.getPreferences("CurrentEnvironment") + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return + if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" - args = ["install", "--index-url", indexUrl, "--upgrade"] + args = ["-m", "pip", "install", "--index-url", indexUrl, + "--upgrade"] else: - args = ["install", "--upgrade"] + args = ["-m", "pip", "install", "--upgrade"] if userSite: args.append("--user") args += packages dia = PipDialog(self.tr('Upgrade Packages')) - res = dia.startProcess(cmd, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() return res @@ -945,38 +909,42 @@ Private slot to upgrade packages to be given by the user. """ from .PipPackagesInputDialog import PipPackagesInputDialog - dlg = PipPackagesInputDialog( - self.__plugin, self.tr("Upgrade Packages")) + dlg = PipPackagesInputDialog(self, self.tr("Upgrade Packages")) if dlg.exec_() == QDialog.Accepted: - command, packages, user = dlg.getData() + venvName, packages, user = dlg.getData() if packages: - self.upgradePackages(packages, cmd=command, userSite=user) + self.upgradePackages(packages, venvName=venvName, + userSite=user) - def installPackages(self, packages, cmd="", userSite=False): + def installPackages(self, packages, venvName="", userSite=False): """ Public method to install the given list of packages. @param packages list of packages to install @type list of str - @param cmd pip command to be used + @param venvName name of the virtual environment to be used @type str @param userSite flag indicating an install to the user install directory @type bool """ - if not cmd: - cmd = self.__plugin.getPreferences("CurrentPipExecutable") + if not venvName: + venvName = self.__plugin.getPreferences("CurrentEnvironment") + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return + if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + "/simple" - args = ["install", "--index-url", indexUrl] + args = ["-m", "pip", "install", "--index-url", indexUrl] else: - args = ["install"] + args = ["-m", "pip", "install"] if userSite: args.append("--user") args += packages dia = PipDialog(self.tr('Install Packages')) - res = dia.startProcess(cmd, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() @@ -988,55 +956,60 @@ dlg = PipPackagesInputDialog( self.__plugin, self.tr("Install Packages")) if dlg.exec_() == QDialog.Accepted: - command, packages, user = dlg.getData() + venvName, packages, user = dlg.getData() if packages: - self.installPackages(packages, cmd=command, userSite=user) + self.installPackages(packages, venvName=venvName, + userSite=user) def __installLocalPackage(self): """ Private slot to install a package available on local storage. """ from .PipFileSelectionDialog import PipFileSelectionDialog - dlg = PipFileSelectionDialog(self.__plugin, "package") + dlg = PipFileSelectionDialog(self, "package") if dlg.exec_() == QDialog.Accepted: - command, package, user = dlg.getData() + venvName, package, user = dlg.getData() if package and os.path.exists(package): - self.installPackages([package], cmd=command, userSite=user) + self.installPackages([package], venvName=venvName, + userSite=user) def __installRequirements(self): """ Private slot to install packages as given in a requirements file. """ from .PipFileSelectionDialog import PipFileSelectionDialog - dlg = PipFileSelectionDialog(self.__plugin, "requirements") + dlg = PipFileSelectionDialog(self, "requirements") if dlg.exec_() == QDialog.Accepted: - command, requirements, user = dlg.getData() + venvName, requirements, user = dlg.getData() if requirements and os.path.exists(requirements): - if not command: - command = self.__plugin.getPreferences( - "CurrentPipExecutable") + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return if self.__plugin.getPreferences("PipSearchIndex"): indexUrl = \ self.__plugin.getPreferences("PipSearchIndex") + \ "/simple" - args = ["install", "--index-url", indexUrl] + args = ["-m", "pip", "install", "--index-url", indexUrl] else: - args = ["install"] + args = ["-m", "pip", "install"] if user: args.append("--user") args += ["--requirement", requirements] dia = PipDialog(self.tr('Install Packages from Requirements')) - res = dia.startProcess(command, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() - def uninstallPackages(self, packages, cmd=""): + def uninstallPackages(self, packages, venvName=""): """ Public method to uninstall the given list of packages. - @param packages list of packages to uninstall (list of string) - @param cmd pip command to be used (string) - @return flag indicating a successful execution (boolean) + @param packages list of packages to uninstall + @type list of str + @param venvName name of the virtual environment to be used + @type str + @return flag indicating a successful execution + @rtype bool """ res = False if packages: @@ -1049,11 +1022,15 @@ "Do you really want to uninstall these packages?"), packages) if dlg.exec_() == QDialog.Accepted: - if not cmd: - cmd = self.__plugin.getPreferences("CurrentPipExecutable") - args = ["uninstall", "--yes"] + packages + if not venvName: + venvName = self.__plugin.getPreferences( + "CurrentEnvironment") + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return + args = ["-m", "pip", "uninstall", "--yes"] + packages dia = PipDialog(self.tr('Uninstall Packages')) - res = dia.startProcess(cmd, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() return res @@ -1064,21 +1041,21 @@ """ from .PipPackagesInputDialog import PipPackagesInputDialog dlg = PipPackagesInputDialog( - self.__plugin, self.tr("Uninstall Packages"), install=False) + self, self.tr("Uninstall Packages"), install=False) if dlg.exec_() == QDialog.Accepted: - command, packages, _user = dlg.getData() + venvName, packages, _user = dlg.getData() if packages: - self.uninstallPackages(packages, cmd=command) + self.uninstallPackages(packages, venvName=venvName) def __uninstallRequirements(self): """ Private slot to uninstall packages as given in a requirements file. """ from .PipFileSelectionDialog import PipFileSelectionDialog - dlg = PipFileSelectionDialog(self.__plugin, "requirements", + dlg = PipFileSelectionDialog(self, "requirements", install=False) if dlg.exec_() == QDialog.Accepted: - command, requirements, _user = dlg.getData() + venvName, requirements, _user = dlg.getData() if requirements and os.path.exists(requirements): try: f = open(requirements, "r") @@ -1096,13 +1073,17 @@ "Do you really want to uninstall these packages?"), reqs) if dlg.exec_() == QDialog.Accepted: - if not command: - command = self.__plugin.getPreferences( - "CurrentPipExecutable") - args = ["uninstall", "--requirement", requirements] + if not venvName: + venvName = self.__plugin.getPreferences( + "CurrentEnvironment") + interpreter = self.getVirtualenvInterpreter(venvName) + if not interpreter: + return + args = ["-m", "pip", "uninstall", "--requirement", + requirements] dia = PipDialog( self.tr('Uninstall Packages from Requirements')) - res = dia.startProcess(command, args) + res = dia.startProcess(interpreter, args) if res: dia.exec_() @@ -1111,7 +1092,7 @@ Private slot to generate the contents for a requirements file. """ from .PipFreezeDialog import PipFreezeDialog - self.__freezeDialog = PipFreezeDialog(self, self.__plugin) + self.__freezeDialog = PipFreezeDialog(self) self.__freezeDialog.show() self.__freezeDialog.start() @@ -1120,7 +1101,13 @@ Private slot to search the Python Package Index. """ from .PipSearchDialog import PipSearchDialog - self.__searchDialog = PipSearchDialog(self, self.__plugin) + + if self.__plugin.getPreferences("PipSearchIndex"): + indexUrl = self.__plugin.getPreferences("PipSearchIndex") + "/pypi" + else: + indexUrl = DefaultIndexUrlXml + + self.__searchDialog = PipSearchDialog(self, indexUrl) self.__searchDialog.show() def __pipConfigure(self):
--- a/Plugins/UiExtensionPlugins/PipInterface/PipDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -26,14 +26,17 @@ class PipDialog(QDialog, Ui_PipDialog): """ - Class implementing a dialog showing the output of a pip command. + Class implementing a dialog showing the output of a 'python -m pip' + command. """ def __init__(self, text, parent=None): """ Constructor - @param text text to be shown by the label (string) - @param parent reference to the parent widget (QWidget) + @param text text to be shown by the label + @type str + @param parent reference to the parent widget + @type QWidget """ super(PipDialog, self).__init__(parent) self.setupUi(self) @@ -51,7 +54,8 @@ """ Protected slot implementing a close event handler. - @param e close event (QCloseEvent) + @param e close event + @type QCloseEvent """ self.__processQueue = [] @@ -92,7 +96,8 @@ """ Private slot called by a button of the button box clicked. - @param button button that was clicked (QAbstractButton) + @param button button that was clicked + @type QAbstractButton """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() @@ -101,8 +106,10 @@ """ Private slot connected to the finished signal. - @param exitCode exit code of the process (integer) - @param exitStatus exit status of the process (QProcess.ExitStatus) + @param exitCode exit code of the process + @type int + @param exitStatus exit status of the process + @type QProcess.ExitStatus """ self.__finish() @@ -110,10 +117,14 @@ """ Public slot used to start the process. - @param cmd name of the pip executable to be used (string) - @param args list of arguments for the process (list of strings) - @keyparam showArgs flag indicating to show the arguments (boolean) + @param cmd name of the pip executable to be used + @type str + @param args list of arguments for the process + @type list of str + @keyparam showArgs flag indicating to show the arguments + @type bool @return flag indicating a successful start of the process + @rtype bool """ if len(self.errors.toPlainText()) == 0: self.errorGroup.hide() @@ -144,7 +155,7 @@ @param processParams list of tuples containing the command and arguments - @type list of tuples of str and list of str + @type list of tuples of (str, list of str) @return flag indicating a successful start of the first process @rtype bool """
--- a/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -26,12 +26,12 @@ """ Class implementing a dialog to enter a file to be processed. """ - def __init__(self, plugin, mode, install=True, parent=None): + def __init__(self, pip, mode, install=True, parent=None): """ Constructor - @param plugin reference to the plugin object - @type PipInterfacePlugin + @param pip reference to the pip object + @type Pip @param mode mode of the dialog @type str @param install flag indicating an install action @@ -70,10 +70,8 @@ self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(pip.getVirtualenvNames()) self.userCheckBox.setVisible(install) @@ -97,14 +95,13 @@ """ Public method to get the entered data. - @return tuple with the pip command, the name of the + @return tuple with the environment name, the name of the selected file and a flag indicating to install to the user install directory @rtype tuple of (str, str, bool) """ - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" - - return (command, self.filePicker.text(), - self.userCheckBox.isChecked()) + return ( + self.venvComboBox.currentText(), + self.filePicker.text(), + self.userCheckBox.isChecked() + )
--- a/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>600</width> - <height>144</height> + <height>170</height> </rect> </property> <property name="windowTitle"> @@ -20,21 +20,21 @@ <item> <widget class="QLabel" name="label"> <property name="text"> - <string>Select the pip executable to be used:</string> + <string>Virtual Environment:</string> </property> </widget> </item> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item> <item> <widget class="QLabel" name="fileLabel"> <property name="text"> - <string>Enter file name:</string> + <string>File Name:</string> </property> </widget> </item>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -20,25 +20,26 @@ QApplication from E5Gui import E5MessageBox, E5FileDialog +from E5Gui.E5PathPicker import E5PathPickerModes from E5Gui.E5Application import e5App from .Ui_PipFreezeDialog import Ui_PipFreezeDialog import Utilities -import UI.PixmapCache class PipFreezeDialog(QDialog, Ui_PipFreezeDialog): """ Class implementing a dialog to generate a requirements file. """ - def __init__(self, pip, plugin, parent=None): + def __init__(self, pip, parent=None): """ Constructor - @param pip reference to the master object (Pip) - @param plugin reference to the plugin object (ToolPipPlugin) - @param parent reference to the parent widget (QWidget) + @param pip reference to the master object + @type Pip + @param parent reference to the parent widget + @type QWidget """ super(PipFreezeDialog, self).__init__(parent) self.setupUi(self) @@ -47,14 +48,14 @@ self.__refreshButton = self.buttonBox.addButton( self.tr("&Refresh"), QDialogButtonBox.ActionRole) - self.fileButton.setIcon(UI.PixmapCache.getIcon("open.png")) + self.requirementsFilePicker.setMode(E5PathPickerModes.OpenFileMode) + self.requirementsFilePicker.setFilters( + self.tr("Text Files (*.txt);;All Files (*)")) self.__pip = pip - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(pip.getVirtualenvNames()) self.__requirementsEdited = False self.__requirementsAvailable = False @@ -65,17 +66,19 @@ """ Protected slot implementing a close event handler. - @param e close event (QCloseEvent) + @param e close event + @type QCloseEvent """ QApplication.restoreOverrideCursor() e.accept() @pyqtSlot(str) - def on_pipComboBox_activated(self, txt): + def on_venvComboBox_activated(self, txt): """ - Private slot handling the selection of a pip executable. + Private slot handling the selection of a virtual environment. - @param txt path of the pip executable (string) + @param txt virtual environment + @type str """ self.__refresh() @@ -84,36 +87,22 @@ """ Private slot handling the switching of the local mode. - @param checked state of the local check box (boolean) + @param checked state of the local check box + @type bool """ self.__refresh() @pyqtSlot(str) - def on_requirementsFileEdit_textChanged(self, txt): + def on_requirementsFilePicker_textChanged(self, txt): """ Private slot handling a change of the requirements file name. - @param txt name of the requirements file (string) + @param txt name of the requirements file + @type str """ self.__updateButtons() @pyqtSlot() - def on_fileButton_clicked(self): - """ - Private slot to enter the requirements file via a file selection - dialog. - """ - fileName = E5FileDialog.getOpenFileName( - self, - self.tr("Select the requirements file"), - self.requirementsFileEdit.text() or os.path.expanduser("~"), - self.tr("Text Files (*.txt);;All Files (*)") - ) - if fileName: - self.requirementsFileEdit.setText( - Utilities.toNativeSeparators(fileName)) - - @pyqtSlot() def on_requirementsEdit_textChanged(self): """ Private slot handling changes of the requirements text. @@ -125,7 +114,8 @@ """ Private slot called by a button of the button box clicked. - @param button button that was clicked (QAbstractButton) + @param button button that was clicked + @type QAbstractButton """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() @@ -154,23 +144,23 @@ self.requirementsEdit.clear() self.__requirementsAvailable = False - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" + venvName = self.venvComboBox.currentText() + interpreter = self.__pip.getVirtualenvInterpreter(venvName) + if not interpreter: + return - args = ["freeze"] + args = ["-m", "pip", "freeze"] if self.localCheckBox.isChecked(): args.append("--local") - if self.requirementsFileEdit.text(): + if self.requirementsFilePicker.text(): fileName = Utilities.toNativeSeparators( - self.requirementsFileEdit.text()) + self.requirementsFilePicker.text()) if os.path.exists(fileName): args.append("--requirement") args.append(fileName) QApplication.setOverrideCursor(Qt.WaitCursor) - success, output = self.__pip.runProcess( - args, cmd=command) + success, output = self.__pip.runProcess(args, interpreter) if success: self.requirementsEdit.setPlainText(output) @@ -190,7 +180,7 @@ """ self.saveButton.setEnabled( self.__requirementsAvailable and - bool(self.requirementsFileEdit.text()) + bool(self.requirementsFilePicker.text()) ) self.saveToButton.setEnabled(self.__requirementsAvailable) self.copyButton.setEnabled(self.__requirementsAvailable) @@ -210,7 +200,8 @@ """ Private method to write the requirements text to a file. - @param fileName name of the file to write to (string) + @param fileName name of the file to write to + @type str """ if os.path.exists(fileName): ok = E5MessageBox.warning( @@ -238,7 +229,7 @@ """ Private slot to save the requirements text to the requirements file. """ - fileName = self.requirementsFileEdit.text() + fileName = self.requirementsFilePicker.text() self.__writeToFile(fileName) @pyqtSlot()
--- a/Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -21,9 +21,9 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item> @@ -50,19 +50,15 @@ </widget> </item> <item> - <widget class="QLineEdit" name="requirementsFileEdit"> - <property name="toolTip"> - <string>Enter the path of a requirements file</string> + <widget class="E5PathPicker" name="requirementsFilePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="fileButton"> - <property name="toolTip"> - <string>Select the requirements file through a file selection dialog</string> - </property> - <property name="text"> - <string notr="true"/> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> </property> </widget> </item> @@ -161,11 +157,18 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>E5PathPicker</class> + <extends>QWidget</extends> + <header>E5Gui/E5PathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> <tabstops> - <tabstop>pipComboBox</tabstop> + <tabstop>venvComboBox</tabstop> <tabstop>localCheckBox</tabstop> - <tabstop>requirementsFileEdit</tabstop> - <tabstop>fileButton</tabstop> + <tabstop>requirementsFilePicker</tabstop> <tabstop>requirementsEdit</tabstop> <tabstop>saveButton</tabstop> <tabstop>saveToButton</tabstop>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipListDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipListDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -41,16 +41,20 @@ ShowProcessEntryPointsMode = 2 ShowProcessFilesListMode = 3 - def __init__(self, pip, mode, plugin, title, parent=None): + def __init__(self, pip, mode, indexUrl, title, parent=None): """ Constructor - @param pip reference to the master object (Pip) - @param mode list command mode (string; one of 'list', - 'uptodate', 'outdated') - @param plugin reference to the plugin object (ToolPipPlugin) - @param title title of the dialog (string) - @param parent reference to the parent widget (QWidget) + @param pip reference to the master object + @type Pip + @param mode list command mode (one of 'list', 'uptodate', 'outdated') + @type str + @param indexUrl URL of the pypi index + @type str + @param title title of the dialog + @type str + @param parent reference to the parent widget + @type QWidget """ assert mode in PipListDialog.CommandArguments @@ -79,9 +83,8 @@ self.__pip = pip self.__mode = mode - self.__defaultCommand = plugin.getPreferences("CurrentPipExecutable") self.__ioEncoding = Preferences.getSystem("IOEncoding") - self.__indexUrl = plugin.getPreferences("PipSearchIndex") + self.__indexUrl = indexUrl self.__errors = "" self.__output = [] @@ -91,10 +94,8 @@ "outdated": self.tr("All packages up-to-date"), } - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(self.__pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(self.__pip.getVirtualenvNames()) if mode == "list": self.infoLabel.setText(self.tr("Installed Packages:")) @@ -160,7 +161,8 @@ """ Protected slot implementing a close event handler. - @param e close event (QCloseEvent) + @param e close event + @type QCloseEvent """ self.__stopProcess() e.accept() @@ -188,7 +190,7 @@ E5MessageBox.critical( self, self.windowTitle(), - self.tr("""<p>The pip command failed.</p>""" + self.tr("""<p>The command failed.</p>""" """<p>Reason: {0}</p>""").format( self.__errors.replace("\r\n", "<br/>") .replace("\n", "<br/>").replace("\r", "<br/>") @@ -211,7 +213,8 @@ """ Private slot called by a button of the button box clicked. - @param button button that was clicked (QAbstractButton) + @param button button that was clicked + @type QAbstractButton """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() @@ -230,8 +233,10 @@ """ Private slot connected to the finished signal. - @param exitCode exit code of the process (integer) - @param exitStatus exit status of the process (QProcess.ExitStatus) + @param exitCode exit code of the process + @type int + @param exitStatus exit status of the process + @type QProcess.ExitStatus """ self.__finish() @@ -261,11 +266,12 @@ QApplication.setOverrideCursor(Qt.WaitCursor) QApplication.processEvents() - command = self.pipComboBox.currentText() - if command == self.__default: - command = self.__defaultCommand + venvName = self.venvComboBox.currentText() + interpreter = self.__pip.getVirtualenvInterpreter(venvName) + if not interpreter: + return - args = PipListDialog.CommandArguments[self.__mode][:] + args = ["-m", "pip"] + PipListDialog.CommandArguments[self.__mode] if self.localCheckBox.isChecked(): args.append("--local") if self.notRequiredCheckBox.isChecked(): @@ -277,7 +283,7 @@ args.append("--index-url") args.append(self.__indexUrl + "/simple") - self.process.start(command, args) + self.process.start(interpreter, args) procStarted = self.process.waitForStarted(5000) if not procStarted: self.buttonBox.setFocus() @@ -287,7 +293,7 @@ self.tr('Process Generation Error'), self.tr( 'The process {0} could not be started.' - ).format(command)) + ).format(interpreter)) self.__finish() def __processOutput(self): @@ -338,11 +344,12 @@ self.__ioEncoding, 'replace') @pyqtSlot(str) - def on_pipComboBox_activated(self, txt): + def on_venvComboBox_activated(self, txt): """ - Private slot handling the selection of a pip executable. + Private slot handling the selection of a virtual environment. - @param txt path of the pip executable (string) + @param txt virtual environment + @type str """ self.__refresh() @@ -386,19 +393,20 @@ if len(self.packageList.selectedItems()) == 1: itm = self.packageList.selectedItems()[0] - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" + environment = self.venvComboBox.currentText() + interpreter = self.__pip.getVirtualenvInterpreter(environment) + if not interpreter: + return QApplication.setOverrideCursor(Qt.WaitCursor) - args = ["show"] + args = ["-m", "pip", "show"] if self.verboseCheckBox.isChecked(): args.append("--verbose") if self.installedFilesCheckBox.isChecked(): args.append("--files") args.append(itm.text(0)) - success, output = self.__pip.runProcess(args, cmd=command) + success, output = self.__pip.runProcess(args, interpreter) if success and output: mode = PipListDialog.ShowProcessGeneralMode @@ -501,12 +509,9 @@ """ Private slot to upgrade pip itself. """ - pip = self.pipComboBox.currentText() - if pip == self.__default: - pip = "" - res = self.__pip.upgradePip( - pip=pip, userSite=self.userCheckBox.isChecked()) + venvName=self.venvComboBox.currentText(), + userSite=self.userCheckBox.isChecked()) if res: self.__refresh() @@ -517,12 +522,9 @@ @param packages list of package names to be upgraded @type list of str """ - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" - res = self.__pip.upgradePackages( - packages, cmd=command, userSite=self.userCheckBox.isChecked()) + packages, venvName=self.venvComboBox.currentText(), + userSite=self.userCheckBox.isChecked()) if res: self.__refresh() @@ -535,10 +537,8 @@ packages.append(itm.text(0)) if packages: - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" - - res = self.__pip.uninstallPackages(packages, cmd=command) + res = self.__pip.uninstallPackages( + packages, + venvName=self.venvComboBox.currentText()) if res: self.__refresh()
--- a/Plugins/UiExtensionPlugins/PipInterface/PipListDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipListDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -18,9 +18,9 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item> @@ -222,7 +222,7 @@ </layout> </widget> <tabstops> - <tabstop>pipComboBox</tabstop> + <tabstop>venvComboBox</tabstop> <tabstop>localCheckBox</tabstop> <tabstop>notRequiredCheckBox</tabstop> <tabstop>userCheckBox</tabstop>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipPackageDetailsDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipPackageDetailsDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -28,9 +28,12 @@ """ Constructor - @param detailsData package details (dict) - @param downloadsData downloads information (dict) - @param parent reference to the parent widget (QWidget) + @param detailsData package details + @type dict + @param downloadsData downloads information + @type dict + @param parent reference to the parent widget + @type QWidget """ super(PipPackageDetailsDialog, self).__init__(parent) self.setupUi(self) @@ -56,7 +59,8 @@ """ Private method to populate the details tab. - @param detailsData package details (dict) + @param detailsData package details + @type dict """ self.packageNameLabel.setText( "<h1>{0} {1}</h1".format(self.__sanitize(detailsData["name"]), @@ -99,7 +103,8 @@ """ Private method to populate the download URLs tab. - @param downloadsData downloads information (dict) + @param downloadsData downloads information + @type dict """ index = self.infoWidget.indexOf(self.urls) if downloadsData: @@ -137,7 +142,8 @@ """ Private method to populate the requires/provides tab. - @param detailsData package details (dict) + @param detailsData package details + @type dict """ populatedItems = 0 @@ -163,9 +169,12 @@ """ Private method to clean-up the given text. - @param text raw text (string) - @param forUrl flag indicating to sanitize an URL text (boolean) - @return processed text (string) + @param text raw text + @type str + @param forUrl flag indicating to sanitize an URL text + @type bool + @return processed text + @rtype str """ if text == "UNKNOWN": text = "" @@ -200,8 +209,10 @@ """ Private slot to format the size. - @param size size to be formatted (integer) - @return formatted size (string) + @param size size to be formatted + @type int + @return formatted size + @rtype str """ unit = "" if size < 1024:
--- a/Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -19,12 +19,12 @@ """ Class implementing a dialog to enter package specifications. """ - def __init__(self, plugin, title, install=True, parent=None): + def __init__(self, pip, title, install=True, parent=None): """ Constructor - @param plugin reference to the plugin object - @type ToolPipPlugin + @param pip reference to the pip object + @type Pip @param title dialog title @type str @param install flag indicating an install action @@ -39,10 +39,8 @@ self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(pip.getVirtualenvNames()) self.userCheckBox.setVisible(install) @@ -54,7 +52,8 @@ """ Private slot handling entering package names. - @param txt name of the requirements file (string) + @param txt name of the requirements file + @type str """ self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(bool(txt)) @@ -62,13 +61,15 @@ """ Public method to get the entered data. - @return tuple with the pip command, the list of package specifications - and a flag indicating to install to the user install directory + @return tuple with the environment name, the list of package + specifications and a flag indicating to install to the user + install directory @rtype tuple of (str, list of str, bool) """ - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" packages = [p.strip() for p in self.packagesEdit.text().split()] - return command, packages, self.userCheckBox.isChecked() + return ( + self.venvComboBox.currentText(), + packages, + self.userCheckBox.isChecked() + )
--- a/Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>600</width> - <height>154</height> + <height>186</height> </rect> </property> <property name="windowTitle"> @@ -20,21 +20,21 @@ <item> <widget class="QLabel" name="label"> <property name="text"> - <string>Select the pip executable to be used:</string> + <string>Virtual Environment:</string> </property> </widget> </item> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item> <item> <widget class="QLabel" name="label_2"> <property name="text"> - <string>Enter package specifications (separated by whitespace):</string> + <string>Package Specifications (separated by whitespace):</string> </property> </widget> </item>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -23,8 +23,6 @@ from .Ui_PipSearchDialog import Ui_PipSearchDialog -from . import DefaultIndexUrlXml - class PipSearchDialog(QDialog, Ui_PipSearchDialog): """ @@ -40,13 +38,16 @@ "they", "this", "to", "was", "will", } - def __init__(self, pip, plugin, parent=None): + def __init__(self, pip, indexUrl, parent=None): """ Constructor - @param pip reference to the master object (Pip) - @param plugin reference to the plugin object (ToolPipPlugin) - @param parent reference to the parent widget (QWidget) + @param pip reference to the master object + @type Pip + @param indexUrl URL of XML RPC interface to the pypi index + @type str + @param parent reference to the parent widget + @type QWidget """ super(PipSearchDialog, self).__init__(parent) self.setupUi(self) @@ -67,16 +68,10 @@ self.__showDetailsButton.setEnabled(False) self.__pip = pip - if plugin.getPreferences("PipSearchIndex"): - indexUrl = plugin.getPreferences("PipSearchIndex") + "/pypi" - else: - indexUrl = DefaultIndexUrlXml self.__client = E5XmlRpcClient(indexUrl, self) - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(self.__pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(self.__pip.getVirtualenvNames()) self.searchEdit.setFocus(Qt.OtherFocusReason) @@ -90,7 +85,8 @@ """ Protected slot implementing a close event handler. - @param e close event (QCloseEvent) + @param e close event + @type QCloseEvent """ QApplication.restoreOverrideCursor() @@ -104,7 +100,8 @@ """ Private slot handling a change of the search term. - @param txt search term (string) + @param txt search term + @type str """ self.searchButton.setEnabled(bool(txt)) @@ -132,7 +129,8 @@ """ Private slot called by a button of the button box clicked. - @param button button that was clicked (QAbstractButton) + @param button button that was clicked + @type QAbstractButton """ if button == self.buttonBox.button(QDialogButtonBox.Close): self.close() @@ -177,7 +175,8 @@ """ Private method to process the search result data from PyPI. - @param data result data (tuple) with hits in the first element + @param data result data with hits in the first element + @type tuple """ if data: packages = self.__transformHits(data[0]) @@ -256,8 +255,10 @@ """ Private method handling a search error. - @param errorCode code of the error (integer) - @param errorString error message (string) + @param errorCode code of the error + @type int + @param errorString error message + @type str """ self.__finish() E5MessageBox.warning( @@ -272,8 +273,10 @@ Private method to convert the list returned from pypi into a packages list. - @param hits list returned from pypi (list of dict) - @return list of packages (list of dict) + @param hits list returned from pypi + @type list of dict + @return list of packages + @rtype list of dict """ # we only include the record with the highest score packages = {} @@ -335,15 +338,13 @@ @param userSite flag indicating to install to the user directory @type bool """ - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" + venvName = self.venvComboBox.currentText() packages = [] for itm in self.resultList.selectedItems(): packages.append(itm.text(0).strip()) if packages: - self.__pip.installPackages(packages, cmd=command, + self.__pip.installPackages(packages, venvName=venvName, userSite=userSite) def __showDetails(self): @@ -415,8 +416,8 @@ """ Private method to display the returned package details. - @param data result data (tuple) with downloads information in the first - element + @param data result data with downloads information in the first element + @type tuple """ from .PipPackageDetailsDialog import PipPackageDetailsDialog @@ -434,8 +435,10 @@ """ Private method handling a details error. - @param errorCode code of the error (integer) - @param errorString error message (string) + @param errorCode code of the error + @type int + @param errorString error message + @type str """ self.__finish() self.__showDetailsButton.setEnabled(True) @@ -451,7 +454,9 @@ """ Private slot reacting on an item activation. - @param item reference to the activated item (QTreeWidgetItem) - @param column activated column (integer) + @param item reference to the activated item + @type QTreeWidgetItem + @param column activated column + @type int """ self.__showDetails()
--- a/Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -18,9 +18,9 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use for installing packages</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item>
--- a/Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.py Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.py Tue Jun 12 19:01:06 2018 +0200 @@ -18,22 +18,20 @@ """ Class implementing a dialog to select the pip executable to be used. """ - def __init__(self, plugin, parent=None): + def __init__(self, pip, parent=None): """ Constructor - @param plugin reference to the plugin object - @type ToolPipPlugin + @param pip reference to the pip object + @type Pip @param parent reference to the parent widget @type QWidget """ super(PipSelectionDialog, self).__init__(parent) self.setupUi(self) - self.__default = self.tr("<Default>") - pipExecutables = sorted(plugin.getPreferences("PipExecutables")) - self.pipComboBox.addItem(self.__default) - self.pipComboBox.addItems(pipExecutables) + self.venvComboBox.addItem(pip.getDefaultEnvironmentString()) + self.venvComboBox.addItems(pip.getVirtualenvNames()) msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -42,12 +40,11 @@ """ Public method to get the entered data. - @return tuple with the pip command and a flag indicating to install - to the user install directory + @return tuple with the environment name and a flag indicating to + install to the user install directory @rtype tuple of (str, bool) """ - command = self.pipComboBox.currentText() - if command == self.__default: - command = "" - - return command, self.userCheckBox.isChecked() + return ( + self.venvComboBox.currentText(), + self.userCheckBox.isChecked(), + )
--- a/Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.ui Tue Jun 12 18:59:45 2018 +0200 +++ b/Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.ui Tue Jun 12 19:01:06 2018 +0200 @@ -11,7 +11,7 @@ </rect> </property> <property name="windowTitle"> - <string>Select pip</string> + <string>Select Virtual Environment</string> </property> <property name="sizeGripEnabled"> <bool>true</bool> @@ -20,14 +20,14 @@ <item> <widget class="QLabel" name="label"> <property name="text"> - <string>Select the pip executable to be used:</string> + <string>Virtual Environment:</string> </property> </widget> </item> <item> - <widget class="QComboBox" name="pipComboBox"> + <widget class="QComboBox" name="venvComboBox"> <property name="toolTip"> - <string>Select the pip command to use</string> + <string>Select the virtual environment to be used</string> </property> </widget> </item>
--- a/changelog Tue Jun 12 18:59:45 2018 +0200 +++ b/changelog Tue Jun 12 19:01:06 2018 +0200 @@ -7,6 +7,7 @@ remote repository - pip Interface -- added support for the '--user' option of install and list commands + -- changed to use the new VirtualEnv Manager - VirtualEnv Manager -- added a manager for virtual environments