--- a/src/eric7/eric7.py Sat Oct 01 20:06:27 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,432 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -eric Python IDE. - -This is the main Python script that performs the necessary initialization -of the IDE and starts the Qt event loop. -""" - -import contextlib -import io -import logging -import multiprocessing -import os -import sys -import traceback -import time - -originalPathString = os.getenv("PATH") - -# generate list of arguments to be remembered for a restart -restartArgsList = [ - "--no-splash", - "--plugin", - "--debug", - "--config", - "--settings", - "--disable-crash", - "--disable-plugin", -] -restartArgs = [arg for arg in sys.argv[1:] if arg.split("=", 1)[0] in restartArgsList] - -sys.path.insert(1, os.path.dirname(__file__)) - -try: - from PyQt6.QtCore import qWarning, QLibraryInfo, QTimer, QCoreApplication -except ImportError: - try: - from tkinter import messagebox - except ImportError: - sys.exit(100) - messagebox.showerror( - "eric7 Error", - "PyQt could not be imported. Please make sure" - " it is installed and accessible.", - ) - sys.exit(100) - -try: - from PyQt6 import QtWebEngineWidgets # __IGNORE_WARNING__ __IGNORE_EXCEPTION__ - from PyQt6.QtWebEngineCore import QWebEngineUrlScheme - - WEBENGINE_AVAILABLE = True -except ImportError: - WEBENGINE_AVAILABLE = False - -# some global variables needed to start the application -args = None -mainWindow = None -splash = None -inMainLoop = None -app = None - -if "--debug" in sys.argv: - del sys.argv[sys.argv.index("--debug")] - logging.basicConfig(level=logging.DEBUG) - -for arg in sys.argv[:]: - if arg.startswith("--config="): - import Globals - - configDir = arg.replace("--config=", "") - Globals.setConfigDir(configDir) - sys.argv.remove(arg) - elif arg.startswith("--settings="): - from PyQt6.QtCore import QSettings - - settingsDir = os.path.expanduser(arg.replace("--settings=", "")) - if not os.path.isdir(settingsDir): - os.makedirs(settingsDir) - QSettings.setPath( - QSettings.Format.IniFormat, QSettings.Scope.UserScope, settingsDir - ) - sys.argv.remove(arg) - -# make Third-Party package available as a packages repository -sys.path.insert(2, os.path.join(os.path.dirname(__file__), "ThirdParty", "Jasy")) -sys.path.insert(2, os.path.join(os.path.dirname(__file__), "DebugClients", "Python")) - -from EricWidgets.EricApplication import EricApplication - - -def handleSingleApplication(ddindex): - """ - Global function to handle the single application mode. - - @param ddindex index of a '--' option in the options list - """ - from EricWidgets.EricSingleApplication import EricSingleApplicationClient - - client = EricSingleApplicationClient() - res = client.connect() - if res > 0: - if "--no-splash" in sys.argv and sys.argv.index("--no-splash") < ddindex: - sys.argv.remove("--no-splash") - ddindex -= 1 - if "--no-open" in sys.argv and sys.argv.index("--no-open") < ddindex: - sys.argv.remove("--no-open") - ddindex -= 1 - if "--no-crash" in sys.argv and sys.argv.index("--no-crash") < ddindex: - sys.argv.remove("--no-crash") - if ( - "--disable-crash" in sys.argv - and sys.argv.index("--disable-crash") < ddindex - ): - sys.argv.remove("--disable-crash") - ddindex -= 1 - if "--debug" in sys.argv and sys.argv.index("--debug") < ddindex: - sys.argv.remove("--debug") - ddindex -= 1 - for arg in sys.argv: - if arg.startswith("--config=") and sys.argv.index(arg) < ddindex: - sys.argv.remove(arg) - ddindex -= 1 - break - for arg in sys.argv: - if arg.startswith("--plugin=") and sys.argv.index(arg) < ddindex: - sys.argv.remove(arg) - ddindex -= 1 - break - for arg in sys.argv[:]: - if arg.startswith("--disable-plugin=") and sys.argv.index(arg) < ddindex: - sys.argv.remove(arg) - ddindex -= 1 - - if len(sys.argv) > 1: - client.processArgs(sys.argv[1:]) - sys.exit(0) - elif res < 0: - print("eric7: {0}".format(client.errstr())) - # __IGNORE_WARNING_M801__ - sys.exit(res) - - -def excepthook(excType, excValue, tracebackobj): - """ - Global function to catch unhandled exceptions. - - @param excType exception type - @param excValue exception value - @param tracebackobj traceback object - """ - from UI.Info import BugAddress - import Utilities - import Globals - - # Workaround for a strange issue with QScintilla - if str(excValue) == "unable to convert a QVariant back to a Python object": - return - - separator = "-" * 80 - logFile = os.path.join(Globals.getConfigDir(), "eric7_error.log") - notice = ( - """An unhandled exception occurred. Please report the problem\n""" - """using the error reporting dialog or via email to <{0}>.\n""" - """A log has been written to "{1}".\n\nError information:\n""".format( - BugAddress, logFile - ) - ) - timeString = time.strftime("%Y-%m-%d, %H:%M:%S") - - versionInfo = "\n{0}\n{1}".format(separator, Utilities.generateVersionInfo()) - pluginVersionInfo = Utilities.generatePluginsVersionInfo() - if pluginVersionInfo: - versionInfo += "\n{0}\n{1}".format(separator, pluginVersionInfo) - distroInfo = Utilities.generateDistroInfo() - if distroInfo: - versionInfo += "\n{0}\n{1}".format(separator, distroInfo) - - if isinstance(excType, str): - tbinfo = tracebackobj - else: - tbinfofile = io.StringIO() - traceback.print_tb(tracebackobj, None, tbinfofile) - tbinfofile.seek(0) - tbinfo = tbinfofile.read() - errmsg = "{0}: \n{1}".format(str(excType), str(excValue)) - sections = ["", separator, timeString, separator, errmsg, separator, tbinfo] - msg = "\n".join(sections) - with contextlib.suppress(OSError), open(logFile, "w", encoding="utf-8") as f: - f.write(msg) - f.write(versionInfo) - - if inMainLoop is None: - warning = notice + msg + versionInfo - print(warning) # __IGNORE_WARNING_M801__ - else: - warning = notice + msg + versionInfo - # Escape &<> otherwise it's not visible in the error dialog - warning = ( - warning.replace("&", "&").replace(">", ">").replace("<", "<") - ) - qWarning(warning) - - -def uiStartUp(): - """ - Global function to finalize the start up of the main UI. - - Note: It is activated by a zero timeout single-shot timer. - """ - global args, mainWindow, splash - - if splash: - splash.finish(mainWindow) - del splash - - mainWindow.checkForErrorLog() - mainWindow.processArgs(args) - mainWindow.processInstallInfoFile() - mainWindow.checkProjectsWorkspace() - mainWindow.checkConfigurationStatus() - mainWindow.performVersionCheck() - mainWindow.checkPluginUpdatesAvailable() - mainWindow.autoConnectIrc() - - -def main(): - """ - Main entry point into the application. - """ - from Globals import AppInfo - import Globals - - global app, args, mainWindow, splash, restartArgs, inMainLoop - - sys.excepthook = excepthook - multiprocessing.set_start_method("spawn") - - from PyQt6.QtGui import QGuiApplication - - QGuiApplication.setDesktopFileName("eric7.desktop") - - options = [ - ( - "--config=configDir", - "use the given directory as the one containing the config files", - ), - ("--debug", "activate debugging output to the console"), - ("--no-splash", "don't show the splash screen"), - ("--no-open", "don't open anything at startup except that given in command"), - ("--no-crash", "don't check for a crash session file on startup"), - ("--disable-crash", "disable the support for crash sessions"), - ( - "--disable-plugin=<plug-in name>", - "disable the given plug-in (may be repeated)", - ), - ("--plugin=plugin-file", "load the given plugin file (plugin development)"), - ( - "--settings=settingsDir", - "use the given directory to store the settings files", - ), - ("--small-screen", "adjust the interface for screens smaller than FHD"), - ("--start-file", "load the most recently opened file"), - ("--start-multi", "load the most recently opened multi-project"), - ("--start-project", "load the most recently opened project"), - ("--start-session", "load the global session file"), - ("--", "indicate that there are options for the program to be debugged"), - ("", "(everything after that is considered arguments for this program)"), - ] - appinfo = AppInfo.makeAppInfo( - sys.argv, - "Eric7", - "[project | files... [--] [debug-options]]", - "A Python IDE", - options, - ) - - if "__PYVENV_LAUNCHER__" in os.environ: - del os.environ["__PYVENV_LAUNCHER__"] - - # make sure our executable directory (i.e. that of the used Python - # interpreter) is included in the executable search path - pathList = os.environ["PATH"].split(os.pathsep) - exeDir = os.path.dirname(sys.executable) - if exeDir not in pathList: - pathList.insert(0, exeDir) - os.environ["PATH"] = os.pathsep.join(pathList) - - from Toolbox import Startup - - # set the library paths for plugins - Startup.setLibraryPaths() - - if WEBENGINE_AVAILABLE: - scheme = QWebEngineUrlScheme(b"qthelp") - scheme.setSyntax(QWebEngineUrlScheme.Syntax.Path) - scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme) - QWebEngineUrlScheme.registerScheme(scheme) - - app = EricApplication(sys.argv) - ddindex = Startup.handleArgs(sys.argv, appinfo) - - logging.debug("Importing Preferences") - import Preferences - - if Preferences.getUI("SingleApplicationMode"): - handleSingleApplication(ddindex) - - # set the application style sheet - app.setStyleSheetFile(Preferences.getUI("StyleSheet")) - - # set the search path for icons - Startup.initializeResourceSearchPath(app) - - # generate and show a splash window, if not suppressed - from UI.SplashScreen import SplashScreen, NoneSplashScreen - - if "--no-splash" in sys.argv and sys.argv.index("--no-splash") < ddindex: - sys.argv.remove("--no-splash") - ddindex -= 1 - splash = NoneSplashScreen() - elif not Preferences.getUI("ShowSplash"): - splash = NoneSplashScreen() - else: - splash = SplashScreen() - QCoreApplication.processEvents() - - # modify the executable search path for the PyQt5 installer - if Globals.isWindowsPlatform(): - pyqtDataDir = Globals.getPyQt6ModulesDirectory() - if os.path.exists(os.path.join(pyqtDataDir, "bin")): - path = os.path.join(pyqtDataDir, "bin") - else: - path = pyqtDataDir - os.environ["PATH"] = path + os.pathsep + os.environ["PATH"] - - pluginFile = None - noopen = False - nocrash = False - disablecrash = False - disabledPlugins = [] - if "--no-open" in sys.argv and sys.argv.index("--no-open") < ddindex: - sys.argv.remove("--no-open") - ddindex -= 1 - noopen = True - if "--no-crash" in sys.argv and sys.argv.index("--no-crash") < ddindex: - sys.argv.remove("--no-crash") - ddindex -= 1 - nocrash = True - if "--disable-crash" in sys.argv and sys.argv.index("--disable-crash") < ddindex: - sys.argv.remove("--disable-crash") - ddindex -= 1 - disablecrash = True - for arg in sys.argv[:]: - if arg.startswith("--disable-plugin=") and sys.argv.index(arg) < ddindex: - # extract the plug-in name - pluginName = arg.replace("--disable-plugin=", "") - sys.argv.remove(arg) - ddindex -= 1 - disabledPlugins.append(pluginName) - for arg in sys.argv: - if arg.startswith("--plugin=") and sys.argv.index(arg) < ddindex: - # extract the plugin development option - pluginFile = arg.replace("--plugin=", "").replace('"', "") - sys.argv.remove(arg) - ddindex -= 1 - pluginFile = os.path.expanduser(pluginFile) - pluginFile = os.path.abspath(pluginFile) - break - - # is there a set of filenames or options on the command line, - # if so, pass them to the UI - if len(sys.argv) > 1: - args = sys.argv[1:] - - # get the Qt translations directory - qtTransDir = Preferences.getQtTranslationsDir() - if not qtTransDir: - qtTransDir = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath) - - # Load translation files and install them - loc = Startup.loadTranslators(qtTransDir, app, ("qscintilla",)) - - # Initialize SSL stuff - from EricNetwork.EricSslUtilities import initSSL - - initSSL() - - splash.showMessage(QCoreApplication.translate("eric7", "Starting...")) - # We can only import these after creating the EricApplication because they - # make Qt calls that need the EricApplication to exist. - from UI.UserInterface import UserInterface - - splash.showMessage(QCoreApplication.translate("eric7", "Generating Main Window...")) - mainWindow = UserInterface( - app, - loc, - splash, - pluginFile, - disabledPlugins, - noopen, - nocrash, - disablecrash, - restartArgs, - originalPathString, - ) - app.lastWindowClosed.connect(app.quit) - mainWindow.show() - - QTimer.singleShot(0, uiStartUp) - - # generate a graphical error handler - from EricWidgets import EricErrorMessage - - eMsg = EricErrorMessage.qtHandler() - eMsg.setMinimumSize(600, 400) - - # start the event loop - inMainLoop = True - res = app.exec() - logging.debug("Shutting down, result %d", res) - logging.shutdown() - sys.exit(res) - - -if __name__ == "__main__": - main()