pip Interface: changed to use the new VirtualEnv Manager

Tue, 12 Jun 2018 19:01:06 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 12 Jun 2018 19:01:06 +0200
changeset 6342
c79ecba9cde7
parent 6341
a00e63f6d766
child 6343
86cea8abd0f7

pip Interface: changed to use the new VirtualEnv Manager

Plugins/PluginPipInterface.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/ConfigurationPage/PipPage.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/Pip.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFileSelectionDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipFreezeDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipListDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipListDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipPackageDetailsDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipPackagesInputDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipSearchDialog.ui file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.py file | annotate | diff | comparison | revisions
Plugins/UiExtensionPlugins/PipInterface/PipSelectionDialog.ui file | annotate | diff | comparison | revisions
changelog file | annotate | diff | comparison | revisions
--- 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>&amp;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>&amp;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&amp;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>&amp;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
 

eric ide

mercurial