PluginPyInstaller.py

Tue, 16 Jan 2018 14:53:10 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 16 Jan 2018 14:53:10 +0100
changeset 1
f7788bc8c08d
parent 0
c6363afe8387
child 2
5109c484bc49
permissions
-rw-r--r--

Implemented support for the programs dialog.

# -*- coding: utf-8 -*-

# Copyright (c) 2018 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the PyInstaller interface plug-in.
"""

from __future__ import unicode_literals

import os
import platform

from PyQt5.QtCore import QObject, QCoreApplication

import Utilities

# Start-Of-Header
name = "PyInstaller Plugin"
author = "Detlev Offenbach <detlev@die-offenbachs.de>"
autoactivate = True
deactivateable = True
version = "0.1.0"
className = "PyInstallerPlugin"
packageName = "PyInstaller"
shortDescription = "Show dialogs to configure and execute PyInstaller."
longDescription = (
    """This plug-in implements dialogs to configure and execute PyInstaller"""
    """ for an eric project. PyInstaller must be available or must be"""
    """ installed via 'pip install PyInstaller'."""
)
needsRestart = False
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""
    
exePy2 = []
exePy3 = []


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
    @rtype list of dict
    """
    dataList = []
    data = {
        "programEntry": True,
        "header": QCoreApplication.translate(
            "PyInstallerPlugin", "Packagers - PyInstaller"),
        "exe": "dummyExe",
        "versionCommand": "--version",
        "versionStartsWith": "dummyExe",
        "versionPosition": -1,
        "version": "",
        "versionCleanup": None,
        "versionRe": "^\d",
    }
    
    if _checkProgram():
        for exePath in (exePy2 + exePy3):
            data["exe"] = exePath
            data["versionStartsWith"] = ""
            dataList.append(data.copy())
    else:
        dataList.append(data)
    return dataList


def _findExecutable(majorVersion):
    """
    Restricted function to determine the names of the executables.
    
    @param majorVersion major python version
    @type int
    @return names of the executables
    @rtype list of str
    """
    # Determine Python Version
    if majorVersion == 3:
        minorVersions = range(10)
    elif majorVersion == 2:
        minorVersions = [7]     # PyInstaller supports just Python 2.7
    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')
                # Look for pyinstaller.exe
                exe = os.path.join(installpath, 'Scripts', 'pyinstaller.exe')
                if os.access(exe, os.X_OK):
                    exes.append(exe)
                # Look for pyi-makespec.exe
                exe = os.path.join(installpath, 'Scripts', 'pyi-makespec.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)
            exePath = getExePath(
                winreg.HKEY_CURRENT_USER,
                winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr)
            if exePath is not None:
                executables.add(exePath)
            
            exePath = getExePath(
                winreg.HKEY_LOCAL_MACHINE,
                winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr)
            if exePath is not None:
                executables.add(exePath)
            
            # Even on Intel 64-bit machines it's 'AMD64'
            if platform.machine() == 'AMD64':
                exePath = getExePath(
                    winreg.HKEY_CURRENT_USER,
                    winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr)
                if exePath is not None:
                    executables.add(exePath)
                
                exePath = getExePath(
                    winreg.HKEY_LOCAL_MACHINE,
                    winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr)
                if exePath is not None:
                    executables.add(exePath)
    else:
        #
        # Linux, Unix ...
        pyinstallerScripts = ['pyinstaller', 'pyi-makespec']
##        scriptSuffixes = [""]
##        for minorVersion in minorVersions:
##            scriptSuffixes.append(
##                "-python{0}.{1}".format(majorVersion, minorVersion))
        # There could be multiple pyinstaller 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 pyinstallerScript in pyinstallerScripts:
                exe = os.path.join(directory, pyinstallerScript)
                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
    
    # sort items, the probably newest topmost
    executables = list(executables)
    executables.sort(reverse=True)
    return executables


def _checkProgram():
    """
    Restricted function to check the availability of pyinstaller.
    
    @return flag indicating availability (boolean)
    """
    global error, exePy2, exePy3
    
    exePy2 = _findExecutable(2)
    exePy3 = _findExecutable(3)
    if (exePy2 + exePy3) == []:
        if Utilities.isWindowsPlatform():
            error = QCoreApplication.translate(
                "PyInstallerPlugin",
                "The pyinstaller.exe executable could not be found."
            )
        else:
            error = QCoreApplication.translate(
                "PyInstallerPlugin",
                "The pyinstaller executable could not be found."
            )
        return False
    else:
        return True


class PyInstallerPlugin(QObject):
    """
    Class documentation goes here.
    """
    def __init__(self, ui):
        """
        Constructor
        
        @param ui reference to the user interface object (UI.UserInterface)
        """
        super(PyInstallerPlugin, self).__init__(ui)
        self.__ui = ui
    
    def activate(self):
        """
        Public method to activate this plugin.
        
        @return tuple of None and activation status (boolean)
        """
        global error
        error = ""     # clear previous error
        
        return None, True
    
    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        pass

eric ide

mercurial