URI: 
       tqt exception window: turn Exception_Hook into singleton - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2105c6c4e6085f9c53eb58dfe8447f2b5b1abad7
   DIR parent 2b1a150c52cf2a3c9df9046bc5268d3eadf3b577
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Fri,  1 May 2020 06:33:38 +0200
       
       qt exception window: turn Exception_Hook into singleton
       
       related #4905
       related Electron-Cash/Electron-Cash@6a3d76b0ab7bf3fe58390100f5bf2ab8a3261d87
       
       conceptually did not really make sense that the Exception_Hook kept a reference
       tto an ~arbitrary main window (preventing gc)
       
       Diffstat:
         M electrum/base_crash_reporter.py     |       2 +-
         M electrum/gui/qt/exception_window.py |      43 ++++++++++++++++++++++---------
         M electrum/gui/qt/main_window.py      |       7 ++++---
       
       3 files changed, 36 insertions(+), 16 deletions(-)
       ---
   DIR diff --git a/electrum/base_crash_reporter.py b/electrum/base_crash_reporter.py
       t@@ -132,7 +132,7 @@ class BaseCrashReporter(Logger):
            def get_user_description(self):
                raise NotImplementedError
        
       -    def get_wallet_type(self):
       +    def get_wallet_type(self) -> str:
                raise NotImplementedError
        
        
   DIR diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py
       t@@ -23,6 +23,7 @@
        # SOFTWARE.
        import sys
        import html
       +from typing import TYPE_CHECKING, Optional, Set
        
        from PyQt5.QtCore import QObject
        import PyQt5.QtCore as QtCore
       t@@ -33,16 +34,22 @@ from electrum.i18n import _
        from electrum.base_crash_reporter import BaseCrashReporter
        from electrum.logging import Logger
        from electrum import constants
       +from electrum.network import Network
        
        from .util import MessageBoxMixin, read_QIcon, WaitingDialog
        
       +if TYPE_CHECKING:
       +    from electrum.simple_config import SimpleConfig
       +    from electrum.wallet import Abstract_Wallet
       +
        
        class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
            _active_window = None
        
       -    def __init__(self, main_window, exctype, value, tb):
       +    def __init__(self, config: 'SimpleConfig', exctype, value, tb):
                BaseCrashReporter.__init__(self, exctype, value, tb)
       -        self.main_window = main_window
       +        self.network = Network.get_instance()
       +        self.config = config
        
                QWidget.__init__(self)
                self.setWindowTitle('Electrum - ' + _('An Error Occurred'))
       t@@ -115,8 +122,8 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
                                            f' <a href="{constants.GIT_REPO_ISSUES_URL}">on GitHub</a>.'),
                                       rich_text=True)
        
       -        proxy = self.main_window.network.proxy
       -        task = lambda: BaseCrashReporter.send_report(self, self.main_window.network.asyncio_loop, proxy)
       +        proxy = self.network.proxy
       +        task = lambda: BaseCrashReporter.send_report(self, self.network.asyncio_loop, proxy)
                msg = _('Sending crash report...')
                WaitingDialog(self, msg, task, on_success, on_failure)
        
       t@@ -125,7 +132,7 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
                self.close()
        
            def show_never(self):
       -        self.main_window.config.set_key(BaseCrashReporter.config_key, False)
       +        self.config.set_key(BaseCrashReporter.config_key, False)
                self.close()
        
            def closeEvent(self, event):
       t@@ -136,7 +143,8 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
                return self.description_textfield.toPlainText()
        
            def get_wallet_type(self):
       -        return self.main_window.wallet.wallet_type
       +        wallet_types = Exception_Hook._INSTANCE.wallet_types_seen
       +        return ",".join(wallet_types)
        
            def _get_traceback_str(self) -> str:
                # The msg_box that shows the report uses rich_text=True, so
       t@@ -154,15 +162,26 @@ def _show_window(*args):
        class Exception_Hook(QObject, Logger):
            _report_exception = QtCore.pyqtSignal(object, object, object, object)
        
       -    def __init__(self, main_window, *args, **kwargs):
       -        QObject.__init__(self, *args, **kwargs)
       +    _INSTANCE = None  # type: Optional[Exception_Hook]  # singleton
       +
       +    def __init__(self, *, config: 'SimpleConfig'):
       +        QObject.__init__(self)
                Logger.__init__(self)
       -        if not main_window.config.get(BaseCrashReporter.config_key, default=True):
       -            return
       -        self.main_window = main_window
       +        assert self._INSTANCE is None, "Exception_Hook is supposed to be a singleton"
       +        self.config = config
       +        self.wallet_types_seen = set()  # type: Set[str]
       +
                sys.excepthook = self.handler
                self._report_exception.connect(_show_window)
        
       +    @classmethod
       +    def maybe_setup(cls, *, config: 'SimpleConfig', wallet: 'Abstract_Wallet') -> None:
       +        if not config.get(BaseCrashReporter.config_key, default=True):
       +            return
       +        if not cls._INSTANCE:
       +            cls._INSTANCE = Exception_Hook(config=config)
       +        cls._INSTANCE.wallet_types_seen.add(wallet.wallet_type)
       +
            def handler(self, *exc_info):
                self.logger.error('exception caught by crash reporter', exc_info=exc_info)
       -        self._report_exception.emit(self.main_window, *exc_info)
       +        self._report_exception.emit(self.config, *exc_info)
   DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
       t@@ -167,12 +167,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                self.gui_object = gui_object
                self.config = config = gui_object.config  # type: SimpleConfig
                self.gui_thread = gui_object.gui_thread
       +        assert wallet, "no wallet"
       +        self.wallet = wallet
        
                self.setup_exception_hook()
        
                self.network = gui_object.daemon.network  # type: Network
       -        assert wallet, "no wallet"
       -        self.wallet = wallet
                self.fx = gui_object.daemon.fx  # type: FxThread
                self.contacts = wallet.contacts
                self.tray = gui_object.tray
       t@@ -304,7 +304,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                    self._update_check_thread.start()
        
            def setup_exception_hook(self):
       -        Exception_Hook(self)
       +        Exception_Hook.maybe_setup(config=self.config,
       +                                   wallet=self.wallet)
        
            def on_fx_history(self):
                self.history_model.refresh('fx_history')