Plugins/UiExtensionPlugins/PipInterface/Pip.py

changeset 6342
c79ecba9cde7
parent 6331
758b1cb7a2e6
child 6361
53f6bd7fb238
--- 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):

eric ide

mercurial