Wed, 21 Sep 2022 16:45:00 +0200
Reformatted source code with 'Black'.
--- a/.hgignore Thu Dec 30 11:55:51 2021 +0100 +++ b/.hgignore Wed Sep 21 16:45:00 2022 +0200 @@ -1,6 +1,7 @@ glob:.eric6project glob:.eric7project glob:.ropeproject +glob:.jedi glob:.directory glob:**.pyc glob:**.pyo
--- a/PluginPyInstaller.epj Thu Dec 30 11:55:51 2021 +0100 +++ b/PluginPyInstaller.epj Wed Sep 21 16:45:00 2022 +0200 @@ -1,19 +1,21 @@ { "header": { "comment": "eric project file for project PluginPyInstaller", - "copyright": "Copyright (C) 2021 Detlev Offenbach, detlev@die-offenbachs.de" + "copyright": "Copyright (C) 2022 Detlev Offenbach, detlev@die-offenbachs.de" }, "project": { "AUTHOR": "Detlev Offenbach", "CHECKERSPARMS": { "Pep8Checker": { "AnnotationsChecker": { + "AllowStarArgAny": false, "AllowUntypedDefs": false, "AllowUntypedNested": false, "DispatchDecorators": [ "singledispatch", "singledispatchmethod" ], + "ForceFutureAnnotations": false, "MaximumComplexity": 3, "MaximumLength": 7, "MinimumCoverage": 75, @@ -59,20 +61,25 @@ }, "CopyrightAuthor": "", "CopyrightMinFileSize": 0, - "DocstringType": "eric", + "DocstringType": "eric_black", "EnabledCheckerCategories": "C, D, E, M, N, S, Y, W", "ExcludeFiles": "*/Ui_*.py, */*_rc.py,", - "ExcludeMessages": "C101,E265,E266,E305,E402,M201,M301,M302,M303,M304,M305,M306,M307,M308,M311,M312,M313,M314,M315,M321,M701,M702,M811,M834,N802,N803,N807,N808,N821,W293,W504,Y119,Y401,Y402", + "ExcludeMessages": "C101,E265,E266,E305,E402,M201,M301,M302,M303,M304,M305,M306,M307,M308,M311,M312,M313,M314,M315,M321,M701,M702,M811,M834,N802,N803,N807,N808,N821,W293,W503,Y119,Y401,Y402", "FixCodes": "", "FixIssues": false, "FutureChecker": "", "HangClosing": false, + "ImportsChecker": { + "ApplicationPackageNames": [], + "BanRelativeImports": "", + "BannedModules": [] + }, "IncludeMessages": "", "LineComplexity": 25, "LineComplexityScore": 10, "MaxCodeComplexity": 10, - "MaxDocLineLength": 79, - "MaxLineLength": 79, + "MaxDocLineLength": 88, + "MaxLineLength": 88, "NoFixCodes": "E501", "RepeatMessages": true, "SecurityChecker": { @@ -129,6 +136,7 @@ } }, "EMAIL": "detlev@die-offenbachs.de", + "EMBEDDED_VENV": false, "EOL": 1, "FILETYPES": { "*.epj": "OTHERS", @@ -152,9 +160,9 @@ "makefile": "OTHERS" }, "FORMS": [ + "PyInstallerInterface/PyInstallerCleanupDialog.ui", "PyInstallerInterface/PyInstallerConfigDialog.ui", - "PyInstallerInterface/PyInstallerExecDialog.ui", - "PyInstallerInterface/PyInstallerCleanupDialog.ui" + "PyInstallerInterface/PyInstallerExecDialog.ui" ], "HASH": "3a7e5bc36f1ae73d45efc807f5aeb2c0236daa13", "IDLPARAMS": { @@ -164,6 +172,7 @@ }, "INTERFACES": [], "LEXERASSOCS": {}, + "LICENSE": "GNU General Public License v3 or later (GPLv3+)", "MAINSCRIPT": "PluginPyInstaller.py", "MAKEPARAMS": { "MakeEnabled": false, @@ -178,12 +187,29 @@ ".hgignore", "ChangeLog", "PKGLIST", + "PluginPyInstaller.epj", "PluginPyInstaller.zip", - "PluginPyInstaller.epj", "PyInstallerInterface/Documentation/LICENSE.GPL3", "PyInstallerInterface/Documentation/source" ], - "OTHERTOOLSPARMS": {}, + "OTHERTOOLSPARMS": { + "Black": { + "exclude": "/(\\.direnv|\\.eggs|\\.git|\\.hg|\\.mypy_cache|\\.nox|\\.tox|\\.venv|venv|\\.svn|_build|buck-out|build|dist|__pypackages__)/", + "extend-exclude": "", + "force-exclude": "", + "line-length": 88, + "skip-magic-trailing-comma": false, + "skip-string-normalization": false, + "source": "project", + "target-version": [ + "py311", + "py310", + "py39", + "py38", + "py37" + ] + } + }, "PACKAGERSPARMS": {}, "PROGLANGUAGE": "Python3", "PROJECTTYPE": "E7Plugin", @@ -198,27 +224,28 @@ "RESOURCES": [], "SOURCES": [ "PluginPyInstaller.py", - "__init__.py", - "PyInstallerInterface/__init__.py", + "PyInstallerInterface/PyInstallerCleanupDialog.py", + "PyInstallerInterface/PyInstallerConfigDialog.py", "PyInstallerInterface/PyInstallerExecDialog.py", - "PyInstallerInterface/PyInstallerConfigDialog.py", - "PyInstallerInterface/PyInstallerCleanupDialog.py" + "PyInstallerInterface/__init__.py", + "__init__.py" ], "SPELLEXCLUDES": "", "SPELLLANGUAGE": "en_US", "SPELLWORDS": "", + "TESTING_FRAMEWORK": "", "TRANSLATIONEXCEPTIONS": [], "TRANSLATIONPATTERN": "PyInstallerInterface/i18n/pyinstaller_%language%.ts", "TRANSLATIONS": [ - "PyInstallerInterface/i18n/pyinstaller_en.ts", + "PyInstallerInterface/i18n/pyinstaller_de.qm", "PyInstallerInterface/i18n/pyinstaller_de.ts", - "PyInstallerInterface/i18n/pyinstaller_ru.ts", - "PyInstallerInterface/i18n/pyinstaller_es.ts", + "PyInstallerInterface/i18n/pyinstaller_empty.ts", + "PyInstallerInterface/i18n/pyinstaller_en.qm", + "PyInstallerInterface/i18n/pyinstaller_en.ts", "PyInstallerInterface/i18n/pyinstaller_es.qm", - "PyInstallerInterface/i18n/pyinstaller_en.qm", - "PyInstallerInterface/i18n/pyinstaller_de.qm", - "PyInstallerInterface/i18n/pyinstaller_empty.ts", - "PyInstallerInterface/i18n/pyinstaller_ru.qm" + "PyInstallerInterface/i18n/pyinstaller_es.ts", + "PyInstallerInterface/i18n/pyinstaller_ru.qm", + "PyInstallerInterface/i18n/pyinstaller_ru.ts" ], "TRANSLATIONSBINPATH": "", "UICPARAMS": {
--- a/PluginPyInstaller.py Thu Dec 30 11:55:51 2021 +0100 +++ b/PluginPyInstaller.py Wed Sep 21 16:45:00 2022 +0200 @@ -12,9 +12,7 @@ import platform import shutil -from PyQt6.QtCore import ( - pyqtSlot, QObject, QCoreApplication, QTranslator, QProcess -) +from PyQt6.QtCore import pyqtSlot, QObject, QCoreApplication, QTranslator, QProcess from PyQt6.QtWidgets import QDialog from EricWidgets import EricMessageBox @@ -42,14 +40,14 @@ # End-Of-Header error = "" - + 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 @@ -58,7 +56,8 @@ data = { "programEntry": True, "header": QCoreApplication.translate( - "PyInstallerPlugin", "Packagers - PyInstaller"), + "PyInstallerPlugin", "Packagers - PyInstaller" + ), "exe": "dummyExe", "versionCommand": "--version", "versionStartsWith": "dummyExe", @@ -67,7 +66,7 @@ "versionCleanup": None, "versionRe": "^\\d", } - + if _checkProgram(): for exePath in exePy3: data["exe"] = exePath @@ -81,7 +80,7 @@ def _findExecutable(majorVersion): """ Restricted function to determine the names of the executables. - + @param majorVersion major python version @type int @return names of the executables @@ -92,7 +91,7 @@ minorVersions = range(16) else: return [] - + executables = set() if Utilities.isWindowsPlatform(): # @@ -101,61 +100,70 @@ try: import winreg except ImportError: - import _winreg as winreg # __IGNORE_WARNING__ - + import _winreg as winreg # __IGNORE_WARNING__ + def getExePath(branch, access, versionStr): exes = [] with contextlib.suppress(WindowsError, OSError): - software = winreg.OpenKey(branch, 'Software', 0, access) - python = winreg.OpenKey(software, 'Python', 0, access) - pcore = winreg.OpenKey(python, 'PythonCore', 0, access) + 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') + installpath = winreg.QueryValue(version, "InstallPath") # Look for pyinstaller.exe - exe = os.path.join(installpath, 'Scripts', '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') + exe = os.path.join(installpath, "Scripts", "pyi-makespec.exe") if os.access(exe, os.X_OK): exes.append(exe) return exes - + versionSuffixes = ["", "-32", "-64"] for minorVersion in minorVersions: for versionSuffix in versionSuffixes: - versionStr = '{0}.{1}{2}'.format(majorVersion, minorVersion, - versionSuffix) + versionStr = "{0}.{1}{2}".format( + majorVersion, minorVersion, versionSuffix + ) exePaths = getExePath( winreg.HKEY_CURRENT_USER, - winreg.KEY_WOW64_32KEY | winreg.KEY_READ, versionStr) + 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) + 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': + if platform.machine() == "AMD64": exePaths = getExePath( winreg.HKEY_CURRENT_USER, - winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) + winreg.KEY_WOW64_64KEY | winreg.KEY_READ, + versionStr, + ) for exePath in exePaths: executables.add(exePath) - + exePaths = getExePath( winreg.HKEY_LOCAL_MACHINE, - winreg.KEY_WOW64_64KEY | winreg.KEY_READ, versionStr) + winreg.KEY_WOW64_64KEY | winreg.KEY_READ, + versionStr, + ) for exePath in exePaths: executables.add(exePath) - + if not executables and majorVersion >= 3: # check the PATH environment variable if nothing was found # Python 3 only - path = Utilities.getEnvironmentEntry('PATH') + path = Utilities.getEnvironmentEntry("PATH") if path: dirs = path.split(os.pathsep) for directory in dirs: @@ -166,15 +174,15 @@ else: # # Linux, Unix ... - pyinstallerScripts = ['pyinstaller', 'pyi-makespec'] - + pyinstallerScripts = ["pyinstaller", "pyi-makespec"] + # There could be multiple pyinstaller executables in the path # e.g. for different python variants - path = Utilities.getEnvironmentEntry('PATH') + path = Utilities.getEnvironmentEntry("PATH") # environment variable not defined if path is None: return [] - + # step 1: determine possible candidates exes = [] dirs = path.split(os.pathsep) @@ -183,7 +191,7 @@ exe = os.path.join(directory, pyinstallerScript) if os.access(exe, os.X_OK): exes.append(exe) - + # step 2: determine the Python variant _exePy3 = set() versionArgs = ["-c", "import sys; print(sys.version_info[0])"] @@ -196,12 +204,12 @@ process.waitForFinished(5000) # get a QByteArray of the output versionBytes = process.readAllStandardOutput() - versionStr = str(versionBytes, encoding='utf-8').strip() + versionStr = str(versionBytes, encoding="utf-8").strip() if versionStr == "3": _exePy3.add(exe) - + executables = _exePy3 - + # sort items, the probably newest topmost executables = list(executables) executables.sort(reverse=True) @@ -211,23 +219,22 @@ def _checkProgram(): """ Restricted function to check the availability of pyinstaller. - + @return flag indicating availability @rtype bool """ global error, exePy3 - + exePy3 = _findExecutable(3) if not exePy3: if Utilities.isWindowsPlatform(): error = QCoreApplication.translate( "PyInstallerPlugin", - "The pyinstaller.exe executable could not be found." + "The pyinstaller.exe executable could not be found.", ) else: error = QCoreApplication.translate( - "PyInstallerPlugin", - "The pyinstaller executable could not be found." + "PyInstallerPlugin", "The pyinstaller executable could not be found." ) return False else: @@ -238,112 +245,130 @@ """ Class implementing the PyInstaller interface plug-in. """ + def __init__(self, ui): """ Constructor - + @param ui reference to the user interface object @type UI.UserInterface """ super().__init__(ui) self.__ui = ui - + self.__initialize() _checkProgram() - + self.__translator = None self.__loadTranslator() - + def __initialize(self): """ Private slot to (re)initialize the plug-in. """ self.__projectActs = [] self.__projectSeparator = None - + def activate(self): """ Public method to activate this plug-in. - + @return tuple of None and activation status @rtype tuple of (None, bool) """ global error - + # There is already an error, don't activate if error: return None, False - + # pyinstaller interface is only activated if it is available if not _checkProgram(): return None, False - + # clear previous error error = "" - + project = ericApp().getObject("Project") menu = project.getMenu("Packagers") if menu: self.__projectSeparator = menu.addSeparator() - + # Execute PyInstaller act = EricAction( - self.tr('Execute PyInstaller'), - self.tr('Execute Py&Installer'), 0, 0, - self, 'packagers_pyinstaller_run') + self.tr("Execute PyInstaller"), + self.tr("Execute Py&Installer"), + 0, + 0, + self, + "packagers_pyinstaller_run", + ) act.setStatusTip( - self.tr('Generate a distribution package using PyInstaller')) - act.setWhatsThis(self.tr( - """<b>Execute PyInstaller</b>""" - """<p>Generate a distribution package using PyInstaller.""" - """ The command is executed in the project path. All""" - """ files and directories must be given as absolute paths or""" - """ as paths relative to the project path.</p>""" - )) + self.tr("Generate a distribution package using PyInstaller") + ) + act.setWhatsThis( + self.tr( + """<b>Execute PyInstaller</b>""" + """<p>Generate a distribution package using PyInstaller.""" + """ The command is executed in the project path. All""" + """ files and directories must be given as absolute paths or""" + """ as paths relative to the project path.</p>""" + ) + ) act.triggered.connect(self.__pyinstaller) menu.addAction(act) self.__projectActs.append(act) - + # Execute pyi-makespec act = EricAction( - self.tr('Make PyInstaller Spec File'), - self.tr('Make PyInstaller &Spec File'), 0, 0, - self, 'packagers_pyinstaller_spec') - act.setStatusTip( - self.tr('Generate a spec file to be used by PyInstaller')) - act.setWhatsThis(self.tr( - """<b>Make PyInstaller Spec File</b>""" - """<p>Generate a spec file to be used by PyInstaller.""" - """ The command is executed in the project path. All""" - """ files and directories must be given as absolute paths or""" - """ as paths relative to the project path.</p>""" - )) + self.tr("Make PyInstaller Spec File"), + self.tr("Make PyInstaller &Spec File"), + 0, + 0, + self, + "packagers_pyinstaller_spec", + ) + act.setStatusTip(self.tr("Generate a spec file to be used by PyInstaller")) + act.setWhatsThis( + self.tr( + """<b>Make PyInstaller Spec File</b>""" + """<p>Generate a spec file to be used by PyInstaller.""" + """ The command is executed in the project path. All""" + """ files and directories must be given as absolute paths or""" + """ as paths relative to the project path.</p>""" + ) + ) act.triggered.connect(self.__pyiMakeSpec) menu.addAction(act) self.__projectActs.append(act) - + # clean the pyinstaller created directories act = EricAction( - self.tr('Clean PyInstaller'), - self.tr('&Clean PyInstaller'), 0, 0, - self, 'packagers_pyinstaller_clean') - act.setStatusTip( - self.tr('Remove the PyInstaller created directories')) - act.setWhatsThis(self.tr( - """<b>Clean PyInstaller</b>""" - """<p>Remove the PyInstaller created directories (dist and""" - """ build). These are subdirectories within the project""" - """ path.</p>""" - )) + self.tr("Clean PyInstaller"), + self.tr("&Clean PyInstaller"), + 0, + 0, + self, + "packagers_pyinstaller_clean", + ) + act.setStatusTip(self.tr("Remove the PyInstaller created directories")) + act.setWhatsThis( + self.tr( + """<b>Clean PyInstaller</b>""" + """<p>Remove the PyInstaller created directories (dist and""" + """ build). These are subdirectories within the project""" + """ path.</p>""" + ) + ) act.triggered.connect(self.__pyinstallerCleanup) menu.addAction(act) self.__projectActs.append(act) - + project.addEricActions(self.__projectActs) project.showMenu.connect(self.__projectShowMenu) - + return None, True - + def deactivate(self): """ Public method to deactivate this plug-in. @@ -354,30 +379,26 @@ menu.removeAction(act) if self.__projectSeparator: menu.removeAction(self.__projectSeparator) - - ericApp().getObject("Project").removeEricActions( - self.__projectActs) - + + ericApp().getObject("Project").removeEricActions(self.__projectActs) + self.__initialize() - + def __projectShowMenu(self, menuName, menu): """ Private slot called, when the the project menu or a submenu is about to be shown. - + @param menuName name of the menu to be shown @type str @param menu reference to the menu @type QMenu """ if menuName == "Packagers": - enable = ( - ericApp().getObject("Project").getProjectLanguage() == - "Python3" - ) + enable = ericApp().getObject("Project").getProjectLanguage() == "Python3" for act in self.__projectActs: act.setEnabled(enable) - + def __loadTranslator(self): """ Private method to load the translation file. @@ -385,8 +406,9 @@ if self.__ui is not None: loc = self.__ui.getLocale() if loc and loc != "C": - locale_dir = os.path.join(os.path.dirname(__file__), - "PyInstallerInterface", "i18n") + locale_dir = os.path.join( + os.path.dirname(__file__), "PyInstallerInterface", "i18n" + ) translation = "pyinstaller_{0}".format(loc) translator = QTranslator(None) loaded = translator.load(translation, locale_dir) @@ -394,10 +416,12 @@ self.__translator = translator ericApp().installTranslator(self.__translator) else: - print("Warning: translation file '{0}' could not be" - " loaded.".format(translation)) + print( + "Warning: translation file '{0}' could not be" + " loaded.".format(translation) + ) print("Using default.") - + @pyqtSlot() def __pyinstaller(self): """ @@ -407,40 +431,46 @@ project = ericApp().getObject("Project") majorVersionStr = project.getProjectLanguage() if majorVersionStr == "Python3": - executables = [f for f in exePy3 if - f.endswith(("pyinstaller", "pyinstaller.exe"))] + executables = [ + f for f in exePy3 if f.endswith(("pyinstaller", "pyinstaller.exe")) + ] if not executables: EricMessageBox.critical( self.__ui, self.tr("pyinstaller"), - self.tr("""The pyinstaller executable could not be""" - """ found.""")) + self.tr( + """The pyinstaller executable could not be""" """ found.""" + ), + ) return - + # check if all files saved and errorfree before continue if not project.checkAllScriptsDirty(reportSyntaxErrors=True): return - + from PyInstallerInterface.PyInstallerConfigDialog import ( - PyInstallerConfigDialog + PyInstallerConfigDialog, ) - params = project.getData('PACKAGERSPARMS', "PYINSTALLER") - dlg = PyInstallerConfigDialog(project, executables, params, - mode="installer") + + params = project.getData("PACKAGERSPARMS", "PYINSTALLER") + dlg = PyInstallerConfigDialog( + project, executables, params, mode="installer" + ) if dlg.exec() == QDialog.DialogCode.Accepted: args, params, script = dlg.generateParameters() - project.setData('PACKAGERSPARMS', "PYINSTALLER", params) - + project.setData("PACKAGERSPARMS", "PYINSTALLER", params) + # now do the call from PyInstallerInterface.PyInstallerExecDialog import ( - PyInstallerExecDialog + PyInstallerExecDialog, ) + dia = PyInstallerExecDialog("pyinstaller") dia.show() res = dia.start(args, params, project, script) if res: dia.exec() - + @pyqtSlot() def __pyiMakeSpec(self): """ @@ -450,50 +480,55 @@ project = ericApp().getObject("Project") majorVersionStr = project.getProjectLanguage() if majorVersionStr == "Python3": - executables = [f for f in exePy3 if - f.endswith(("pyi-makespec", "pyi-makespec.exe"))] + executables = [ + f for f in exePy3 if f.endswith(("pyi-makespec", "pyi-makespec.exe")) + ] if not executables: EricMessageBox.critical( self.__ui, self.tr("pyi-makespec"), - self.tr("""The pyi-makespec executable could not be""" - """ found.""")) + self.tr( + """The pyi-makespec executable could not be""" """ found.""" + ), + ) return - + # check if all files saved and errorfree before continue if not project.checkAllScriptsDirty(reportSyntaxErrors=True): return - + from PyInstallerInterface.PyInstallerConfigDialog import ( - PyInstallerConfigDialog + PyInstallerConfigDialog, ) - params = project.getData('PACKAGERSPARMS', "PYINSTALLER") - dlg = PyInstallerConfigDialog(project, executables, params, - mode="spec") + + params = project.getData("PACKAGERSPARMS", "PYINSTALLER") + dlg = PyInstallerConfigDialog(project, executables, params, mode="spec") if dlg.exec() == QDialog.DialogCode.Accepted: args, params, script = dlg.generateParameters() - project.setData('PACKAGERSPARMS', "PYINSTALLER", params) - + project.setData("PACKAGERSPARMS", "PYINSTALLER", params) + # now do the call from PyInstallerInterface.PyInstallerExecDialog import ( - PyInstallerExecDialog + PyInstallerExecDialog, ) + dia = PyInstallerExecDialog("pyinstaller") dia.show() res = dia.start(args, params, project, script) if res: dia.exec() - + @pyqtSlot() def __pyinstallerCleanup(self): """ Private slot to remove the directories created by pyinstaller. """ project = ericApp().getObject("Project") - + from PyInstallerInterface.PyInstallerCleanupDialog import ( - PyInstallerCleanupDialog + PyInstallerCleanupDialog, ) + dlg = PyInstallerCleanupDialog() if dlg.exec() == QDialog.DialogCode.Accepted: removeDirs = dlg.getDirectories() @@ -505,14 +540,15 @@ def installDependencies(pipInstall): """ Function to install dependencies of this plug-in. - + @param pipInstall function to be called with a list of package names. @type function """ try: - import PyInstaller # __IGNORE_WARNING__ + import PyInstaller # __IGNORE_WARNING__ except ImportError: pipInstall(["pyinstaller"]) + # # eflag: noqa = M801
--- a/PyInstallerInterface/PyInstallerCleanupDialog.py Thu Dec 30 11:55:51 2021 +0100 +++ b/PyInstallerInterface/PyInstallerCleanupDialog.py Wed Sep 21 16:45:00 2022 +0200 @@ -16,34 +16,35 @@ """ Class implementing a dialog to select the cleanup action. """ + BuildPath = "build" DistPath = "dist" - + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent widget @type QWidget """ super().__init__(parent) self.setupUi(self) - + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def getDirectories(self): """ Public method to get the project relative directories to be cleaned. - + @return list of directories to be removed @rtype list of str """ dirs = [] - + if self.buildButton.isChecked() or self.bothButton.isChecked(): dirs.append(PyInstallerCleanupDialog.BuildPath) if self.distButton.isChecked() or self.bothButton.isChecked(): dirs.append(PyInstallerCleanupDialog.DistPath) - + return dirs
--- a/PyInstallerInterface/PyInstallerConfigDialog.py Thu Dec 30 11:55:51 2021 +0100 +++ b/PyInstallerInterface/PyInstallerConfigDialog.py Wed Sep 21 16:45:00 2022 +0200 @@ -24,11 +24,13 @@ Class implementing a dialog to enter the parameters for pyinstaller and pyi-makespec. """ - def __init__(self, project, executables, params=None, mode="installer", - parent=None): + + def __init__( + self, project, executables, params=None, mode="installer", parent=None + ): """ Constructor - + @param project reference to the project object @type Project.Project @param executables names of the pyinstaller executables @@ -42,75 +44,77 @@ """ super().__init__(parent) self.setupUi(self) - + self.__project = project self.__mode = mode - + self.inputFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.inputFilePicker.setDefaultDirectory( - self.__project.getProjectPath()) + self.inputFilePicker.setDefaultDirectory(self.__project.getProjectPath()) if self.__mode == "installer": - self.inputFilePicker.setFilters(self.tr( - "Python Files (*.py *.py3);;" - "Python GUI Files (*.pyw *.pyw3);;" - "Spec Files (*.spec);;" - "All Files (*)" - )) + self.inputFilePicker.setFilters( + self.tr( + "Python Files (*.py *.py3);;" + "Python GUI Files (*.pyw *.pyw3);;" + "Spec Files (*.spec);;" + "All Files (*)" + ) + ) elif self.__mode == "spec": - self.inputFilePicker.setFilters(self.tr( - "Python Files (*.py *.py3);;" - "Python GUI Files (*.pyw *.pyw3);;" - "All Files (*)" - )) - + self.inputFilePicker.setFilters( + self.tr( + "Python Files (*.py *.py3);;" + "Python GUI Files (*.pyw *.pyw3);;" + "All Files (*)" + ) + ) + self.executableCombo.addItems(executables) - + if not bool(project.getMainScript()): # no main script defined self.selectedScriptButton.setChecked(True) self.mainScriptButton.setEnabled(False) - + self.iconFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE) - self.iconFilePicker.setDefaultDirectory( - self.__project.getProjectPath()) + self.iconFilePicker.setDefaultDirectory(self.__project.getProjectPath()) if Globals.isMacPlatform(): - self.iconFilePicker.setFilters(self.tr( - "Icon Files (*.icns);;" - "All Files (*)" - )) + self.iconFilePicker.setFilters( + self.tr("Icon Files (*.icns);;" "All Files (*)") + ) elif Globals.isWindowsPlatform(): - self.iconFilePicker.setFilters(self.tr( - "Icon Files (*.ico);;" - "Executable Files (*.exe);;" - "All Files (*)" - )) - + self.iconFilePicker.setFilters( + self.tr( + "Icon Files (*.ico);;" "Executable Files (*.exe);;" "All Files (*)" + ) + ) + # disable platform specific tabs self.tabWidget.setTabEnabled( self.tabWidget.indexOf(self.windowsMacTab), - Globals.isMacPlatform() or Globals.isWindowsPlatform()) + Globals.isMacPlatform() or Globals.isWindowsPlatform(), + ) self.tabWidget.setTabEnabled( - self.tabWidget.indexOf(self.macTab), - Globals.isMacPlatform()) - + self.tabWidget.indexOf(self.macTab), Globals.isMacPlatform() + ) + self.__initializeDefaults() - + # get a copy of the defaults to store the user settings self.__parameters = copy.deepcopy(self.__defaults) - + # combine it with the values of params if params is not None: self.__parameters.update(params) - + # initialize general tab if mode == "installer" and bool(self.__parameters["pyinstaller"]): self.executableCombo.setCurrentIndex( - self.executableCombo.findText( - self.__parameters["pyinstaller"])) + self.executableCombo.findText(self.__parameters["pyinstaller"]) + ) elif mode == "spec" and bool(self.__parameters["pyi-makespec"]): self.executableCombo.setCurrentIndex( - self.executableCombo.findText( - self.__parameters["pyi-makespec"])) + self.executableCombo.findText(self.__parameters["pyi-makespec"]) + ) if self.__parameters["mainscript"]: self.mainScriptButton.setChecked(True) else: @@ -123,7 +127,7 @@ self.nameEdit.setText(self.__parameters["name"]) self.keyEdit.setText(self.__parameters["encryptionKey"]) self.cleanCheckBox.setChecked(self.__parameters["cleanBeforeBuilding"]) - + # initialize Windows and macOS tab if self.__parameters["consoleApplication"]: self.consoleButton.setChecked(True) @@ -131,20 +135,19 @@ self.windowedButton.setChecked(True) self.iconFilePicker.setText(self.__parameters["iconFile"]) self.iconIdEdit.setText(self.__parameters["iconId"]) - + # initialize maxOS specific tab - self.bundleIdentifierEdit.setText( - self.__parameters["bundleIdentifier"]) - + self.bundleIdentifierEdit.setText(self.__parameters["bundleIdentifier"]) + self.__updateOkButton() - + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) - + def __initializeDefaults(self): """ Private method to set the default values. - + These are needed later on to generate the command line parameters. """ self.__defaults = { @@ -157,32 +160,30 @@ "name": "", "encryptionKey": "", "cleanBeforeBuilding": False, - # Windows and macOS options "consoleApplication": True, "iconFile": "", "iconId": "", - # macOS specific options "bundleIdentifier": "", } - + def generateParameters(self): """ Public method that generates the command line parameters. - + It generates a list of strings to be used to set the QProcess arguments for the pyinstaller/pyi-makespec call and a list containing the non default parameters. The second list can be passed back upon object generation to overwrite the default settings. - + @return a tuple of the command line parameters, non default parameters and the script path @rtype tuple of (list of str, dict, str) """ parms = {} args = [] - + # 1. the program name if self.__mode == "installer": args.append(self.__parameters["pyinstaller"]) @@ -190,13 +191,13 @@ elif self.__mode == "spec": args.append(self.__parameters["pyi-makespec"]) parms["pyi-makespec"] = self.__parameters["pyi-makespec"] - + # 2. the commandline options # 2.1 general options, input if not self.__parameters["mainscript"]: parms["mainscript"] = False parms["inputFile"] = self.__parameters["inputFile"] - + runWithSpec = self.__parameters["inputFile"].endswith(".spec") if not runWithSpec: # 2.2 general options, part 1 @@ -207,22 +208,17 @@ parms["name"] = self.__parameters["name"] args.append("--name") args.append(self.__parameters["name"]) - if ( - self.__parameters["encryptionKey"] != - self.__defaults["encryptionKey"] - ): + if self.__parameters["encryptionKey"] != self.__defaults["encryptionKey"]: parms["encryptionKey"] = self.__parameters["encryptionKey"] args.append("--key") args.append(self.__parameters["encryptionKey"]) - + # 2.3 Windows and macOS options if ( - self.__parameters["consoleApplication"] != - self.__defaults["consoleApplication"] + self.__parameters["consoleApplication"] + != self.__defaults["consoleApplication"] ): - parms["consoleApplication"] = ( - self.__parameters["consoleApplication"] - ) + parms["consoleApplication"] = self.__parameters["consoleApplication"] args.append("--windowed") if self.__parameters["iconFile"] != self.__defaults["iconFile"]: parms["iconFile"] = self.__parameters["iconFile"] @@ -233,145 +229,127 @@ iconId = self.__parameters["iconId"] else: iconId = "0" - args.append("{0},{1}".format( - self.__parameters["iconFile"], iconId)) + args.append("{0},{1}".format(self.__parameters["iconFile"], iconId)) else: args.append(self.__parameters["iconFile"]) - + # 2.4 macOS specific options if ( - self.__parameters["bundleIdentifier"] != - self.__defaults["bundleIdentifier"] + self.__parameters["bundleIdentifier"] + != self.__defaults["bundleIdentifier"] ): - parms["bundleIdentifier"] = ( - self.__parameters["bundleIdentifier"] - ) + parms["bundleIdentifier"] = self.__parameters["bundleIdentifier"] args.append("--osx-bundle-identifier") args.append(self.__parameters["bundleIdentifier"]) - + # 2.5 general options, part 2 if ( - self.__parameters["cleanBeforeBuilding"] != - self.__defaults["cleanBeforeBuilding"] + self.__parameters["cleanBeforeBuilding"] + != self.__defaults["cleanBeforeBuilding"] ): - parms["cleanBeforeBuilding"] = ( - self.__parameters["cleanBeforeBuilding"] - ) + parms["cleanBeforeBuilding"] = self.__parameters["cleanBeforeBuilding"] args.append("--clean") - + # 3. always add these arguments if self.__mode == "installer": args.append("--noconfirm") # don't ask the user - + # determine the script to be processed script = ( self.__project.getMainScript() - if self.__parameters["mainscript"] else - self.__parameters["inputFile"] + if self.__parameters["mainscript"] + else self.__parameters["inputFile"] ) - + return args, parms, script def accept(self): """ Public method called by the Ok button. - + It saves the values in the parameters dictionary. """ # get data of general tab if self.__mode == "installer": - self.__parameters["pyinstaller"] = ( - self.executableCombo.currentText() - ) + self.__parameters["pyinstaller"] = self.executableCombo.currentText() elif self.__mode == "spec": - self.__parameters["pyi-makespec"] = ( - self.executableCombo.currentText() - ) + self.__parameters["pyi-makespec"] = self.executableCombo.currentText() self.__parameters["mainscript"] = self.mainScriptButton.isChecked() self.__parameters["inputFile"] = self.inputFilePicker.text() self.__parameters["oneDirectory"] = self.oneDirButton.isChecked() self.__parameters["name"] = self.nameEdit.text() self.__parameters["encryptionKey"] = self.keyEdit.text() - self.__parameters["cleanBeforeBuilding"] = ( - self.cleanCheckBox.isChecked() - ) - + self.__parameters["cleanBeforeBuilding"] = self.cleanCheckBox.isChecked() + # get data of Windows and macOS tab - self.__parameters["consoleApplication"] = ( - self.consoleButton.isChecked() - ) + self.__parameters["consoleApplication"] = self.consoleButton.isChecked() self.__parameters["iconFile"] = self.iconFilePicker.text() self.__parameters["iconId"] = self.iconIdEdit.text() - + # get data of macOS specific tab - self.__parameters["bundleIdentifier"] = ( - self.bundleIdentifierEdit.text() - ) + self.__parameters["bundleIdentifier"] = self.bundleIdentifierEdit.text() # call the accept slot of the base class super().accept() - + def __updateOkButton(self): """ Private method to update the enabled state of the OK button. """ enable = True - + # If not to be run with the project main script, a script or # spec file must be selected. - if ( - self.selectedScriptButton.isChecked() and - not bool(self.inputFilePicker.text()) + if self.selectedScriptButton.isChecked() and not bool( + self.inputFilePicker.text() ): enable = False - + # If the icon shall be picked from a .exe file, an icon ID # must be entered (Windows only). - if ( - self.iconFilePicker.text().endswith(".exe") and - not bool(self.iconIdEdit.text()) + if self.iconFilePicker.text().endswith(".exe") and not bool( + self.iconIdEdit.text() ): enable = False - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Ok).setEnabled(enable) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable) + @pyqtSlot(bool) def on_selectedScriptButton_toggled(self, checked): """ Private slot to handle changes of the radio button state. - + @param checked state of the radio button @type bool """ self.__updateOkButton() - + @pyqtSlot(str) def on_inputFilePicker_textChanged(self, txt): """ Private slot to handle changes of the input file. - + @param txt text of the file edit @type str """ self.__updateOkButton() - + @pyqtSlot(str) def on_iconFilePicker_textChanged(self, txt): """ Private slot to handle changes of the icon file. - + @param txt text of the file edit @type str """ self.iconIdEdit.setEnabled(txt.endswith(".exe")) self.__updateOkButton() - + @pyqtSlot(str) def on_iconIdEdit_textChanged(self, txt): """ Private slot to handle changes of the icon ID. - + @param txt iconID @type str """
--- a/PyInstallerInterface/PyInstallerExecDialog.py Thu Dec 30 11:55:51 2021 +0100 +++ b/PyInstallerInterface/PyInstallerExecDialog.py Wed Sep 21 16:45:00 2022 +0200 @@ -24,14 +24,15 @@ """ Class implementing a dialog to show the output of the pyinstaller/pyi-makespec process. - + This class starts a QProcess and displays a dialog that shows the output of the packager command process. """ + def __init__(self, cmdname, parent=None): """ Constructor - + @param cmdname name of the packager @type str @param parent reference to the parent widget @@ -39,19 +40,17 @@ """ super().__init__(parent) self.setupUi(self) - - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setDefault(True) - + + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) + self.__process = None - self.__cmdname = cmdname # used for several outputs - + self.__cmdname = cmdname # used for several outputs + def start(self, args, parms, project, script): """ Public slot to start the packager command. - + @param args command line arguments for packager program @type list of str @param parms parameters got from the config dialog @@ -65,64 +64,61 @@ @rtype bool """ self.__project = project - + if not os.path.isabs(script): # assume relative paths are relative to the project directory script = os.path.join(self.__project.getProjectPath(), script) dname = os.path.dirname(script) self.__script = os.path.basename(script) - + self.contents.clear() - + args.append(self.__script) - + self.__process = QProcess() self.__process.setWorkingDirectory(dname) - + self.__process.readyReadStandardOutput.connect(self.__readStdout) self.__process.readyReadStandardError.connect(self.__readStderr) self.__process.finished.connect(self.__finishedProcess) - - self.setWindowTitle(self.tr('{0} - {1}').format( - self.__cmdname, script)) - self.contents.insertPlainText("{0} {1}\n\n".format( - ' '.join(args), os.path.join(dname, self.__script))) + + self.setWindowTitle(self.tr("{0} - {1}").format(self.__cmdname, script)) + self.contents.insertPlainText( + "{0} {1}\n\n".format(" ".join(args), os.path.join(dname, self.__script)) + ) self.contents.ensureCursorVisible() - + program = args.pop(0) self.__process.start(program, args) procStarted = self.__process.waitForStarted() if not procStarted: EricMessageBox.critical( self, - self.tr('Process Generation Error'), + self.tr("Process Generation Error"), self.tr( - 'The process {0} could not be started. ' - 'Ensure, that it is in the search path.' - ).format(program)) + "The process {0} could not be started. " + "Ensure, that it is in the search path." + ).format(program), + ) return procStarted - + @pyqtSlot(QAbstractButton) def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. - + @param button button that was clicked @type QAbstractButton """ - if button == self.buttonBox.button( - QDialogButtonBox.StandardButton.Close - ): + if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): self.accept() - elif button == self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel - ): + elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): self.__finish() - + def __finish(self): """ Private slot called when the process was canceled by the user. - + It is called when the process finished or the user pressed the cancel button. """ @@ -132,74 +128,76 @@ QTimer.singleShot(2000, self.__process.kill) self.__process.waitForFinished(3000) self.__process = None - + self.contents.insertPlainText( - self.tr('\n{0} aborted.\n').format(self.__cmdname)) - + self.tr("\n{0} aborted.\n").format(self.__cmdname) + ) + self.__enableButtons() - + def __finishedProcess(self): """ Private slot called when the process finished. - + It is called when the process finished or the user pressed the cancel button. """ if self.__process.exitStatus() == QProcess.ExitStatus.NormalExit: # add the spec file to the project - self.__project.addToOthers( - os.path.splitext(self.__script)[0] + ".spec") - + self.__project.addToOthers(os.path.splitext(self.__script)[0] + ".spec") + self.__process = None self.contents.insertPlainText( - self.tr('\n{0} finished.\n').format(self.__cmdname)) - + self.tr("\n{0} finished.\n").format(self.__cmdname) + ) + self.__enableButtons() - + def __enableButtons(self): """ Private slot called when all processes finished. - + It is called when the process finished or the user pressed the cancel button. """ - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setEnabled(True) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Cancel).setEnabled(False) - self.buttonBox.button( - QDialogButtonBox.StandardButton.Close).setDefault(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) + self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) + self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) self.contents.ensureCursorVisible() def __readStdout(self): """ Private slot to handle the readyReadStandardOutput signal. - + It reads the output of the process, formats it and inserts it into the contents pane. """ self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput) - + while self.__process.canReadLine(): - s = str(self.__process.readAllStandardOutput(), - Preferences.getSystem("IOEncoding"), - 'replace') + s = str( + self.__process.readAllStandardOutput(), + Preferences.getSystem("IOEncoding"), + "replace", + ) self.contents.insertPlainText(s) self.contents.ensureCursorVisible() - + def __readStderr(self): """ Private slot to handle the readyReadStandardError signal. - + It reads the error output of the process and inserts it into the error pane. """ self.__process.setReadChannel(QProcess.ProcessChannel.StandardError) - + while self.__process.canReadLine(): - s = str(self.__process.readAllStandardError(), - Preferences.getSystem("IOEncoding"), - 'replace') + s = str( + self.__process.readAllStandardError(), + Preferences.getSystem("IOEncoding"), + "replace", + ) self.contents.insertPlainText(s) self.contents.ensureCursorVisible()