Plugins/PluginPipInterface.py

changeset 6011
e6af0dcfbb35
child 6048
82ad8ec9548c
diff -r 7ef7d47a0ad5 -r e6af0dcfbb35 Plugins/PluginPipInterface.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/PluginPipInterface.py	Sat Dec 09 18:32:08 2017 +0100
@@ -0,0 +1,389 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 - 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the pip interface plug-in.
+"""
+
+from __future__ import unicode_literals
+
+import os
+import platform
+
+from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication
+
+from E5Gui.E5Application import e5App
+
+import Preferences
+import Utilities
+import UI.Info
+
+# Start-Of-Header
+name = "pip Interface Plug-in"
+author = "Detlev Offenbach <detlev@die-offenbachs.de>"
+autoactivate = True
+deactivateable = True
+version = UI.Info.VersionOnly
+className = "PipInterfacePlugin"
+packageName = "__core__"
+shortDescription = "Plug-in implementing a simple GUI for the pip command."
+longDescription = (
+    """Plug-in implementing a simple GUI for the pip command."""
+)
+needsRestart = False
+pyqtApi = 2
+python2Compatible = True
+# End-Of-Header
+
+error = ""
+
+pipPluginObject = None
+
+
+def exeDisplayDataList():
+    """
+    Module function to support the display of some executable info.
+    
+    @return list of dictionaries containing the data to query the presence of
+        the executable
+    """
+    global pipPluginObject
+    
+    dataList = []
+    data = {
+        "programEntry": True,
+        "header": QCoreApplication.translate(
+            "PipInterfacePlugin", "Package Management - pip"),
+        "exe": "dummyExe",
+        "versionCommand": "--version",
+        "versionStartsWith": "dummyExe",
+        "versionPosition": 1,
+        "version": "",
+        "versionCleanup": None,
+    }
+    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())
+    return dataList
+
+
+def createPipPage(configDlg):
+    """
+    Module function to create the pip configuration page.
+    
+    @param configDlg reference to the configuration dialog
+    @return reference to the configuration page
+    """
+    global pipPluginObject
+    from UiExtensionPlugins.PipInterface.ConfigurationPage.PipPage import \
+        PipPage
+    page = PipPage(pipPluginObject)
+    return page
+    
+
+def getConfigData():
+    """
+    Module function returning data as required by the configuration dialog.
+    
+    @return dictionary containing the relevant data
+    """
+    return {
+        "pipPage": [
+            QCoreApplication.translate(
+                "PipInterfacePlugin", "Python Package Management"),
+            "preferences-python.png",
+            createPipPage, None, None
+        ],
+    }
+
+
+def prepareUninstall():
+    """
+    Module function to prepare for an un-installation.
+    """
+    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
+        
+        for minorVersion in minorVersions:
+            versionStr = '{0}.{1}'.format(majorVersion, minorVersion)
+            exePaths = getExePath(
+                winreg.HKEY_CURRENT_USER,
+                winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr)
+            if exePaths:
+                for exePath in exePaths:
+                    executables.add(exePath)
+            
+            exePaths = getExePath(
+                winreg.HKEY_LOCAL_MACHINE,
+                winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr)
+            if exePaths:
+                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)
+                if exePaths:
+                    for exePath in exePaths:
+                        executables.add(exePath)
+                
+                exePath = getExePath(
+                    winreg.HKEY_LOCAL_MACHINE,
+                    winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr)
+                if exePaths:
+                    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
+        if Utilities.isMacPlatform():
+            checkStrings = ["Python.framework/Versions/3".lower(),
+                            "python3"]
+        else:
+            checkStrings = ["python3"]
+        
+        _exePy2 = set()
+        _exePy3 = set()
+        for exe in exes:
+            try:
+                f = open(exe, "r")
+                line0 = f.readline()
+                for checkStr in checkStrings:
+                    if checkStr in line0.lower():
+                        _exePy3.add(exe)
+                        break
+                else:
+                    _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
+    """
+    PreferencesKey = "PipPlugin"
+    
+    currentPipChanged = pyqtSignal(str)
+    
+    def __init__(self, ui):
+        """
+        Constructor
+        
+        @param ui reference to the user interface object (UI.UserInterface)
+        """
+        super(PipInterfacePlugin, self).__init__(ui)
+        self.__ui = ui
+        self.__initialize()
+        
+        self.__defaults = {
+            "PipExecutables": [],
+            "CurrentPipExecutable": "",
+            "PipSearchIndex": "",           # used by the search command
+        }
+    
+    def __initialize(self):
+        """
+        Private slot to (re)initialize the plugin.
+        """
+        self.__object = None
+        
+        self.__mainAct = None
+        self.__mainMenu = None
+    
+    def activate(self):
+        """
+        Public method to activate this plugin.
+        
+        @return tuple of None and activation status (boolean)
+        """
+        global error
+        error = ""     # clear previous error
+        
+        global pipPluginObject
+        pipPluginObject = self
+        
+        from UiExtensionPlugins.PipInterface.Pip import Pip
+        self.__object = Pip(self, self.__ui)
+        self.__object.initActions()
+        e5App().registerPluginObject("PipGui", self.__object)
+        
+        menu = self.__ui.getMenu("extras")
+        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):
+        """
+        Public method to deactivate this plugin.
+        """
+        e5App().unregisterPluginObject("PipGui")
+        
+        menu = self.__ui.getMenu("extras")
+        menu.removeAction(self.__mainAct)
+        self.__mainAct = None
+        
+        self.__initialize()
+    
+    def getPreferences(self, key):
+        """
+        Public method to retrieve the various refactoring settings.
+        
+        @param key the key of the value to get
+        @return the requested refactoring setting
+        """
+        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])
+    
+    def setPreferences(self, key, value):
+        """
+        Public method to store the various refactoring settings.
+        
+        @param key the key of the setting to be set (string)
+        @param value the value to be set
+        """
+        Preferences.Prefs.settings.setValue(
+            self.PreferencesKey + "/" + key, value)
+        
+        if key == "CurrentPipExecutable":
+                self.currentPipChanged.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
+            menu with the given name exists
+        """
+        if self.__object is not None:
+            return self.__object.getMenu(name)
+        else:
+            return None
+    
+    def getMenuNames(self):
+        """
+        Public method to get the names of all menus.
+        
+        @return menu names (list of string)
+        """
+        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

eric ide

mercurial