Browse Source

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
to an ~arbitrary main window (preventing gc)
master
SomberNight 5 years ago
parent
commit
2105c6c4e6
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 2
      electrum/base_crash_reporter.py
  2. 43
      electrum/gui/qt/exception_window.py
  3. 7
      electrum/gui/qt/main_window.py

2
electrum/base_crash_reporter.py

@ -132,7 +132,7 @@ class BaseCrashReporter(Logger):
def get_user_description(self): def get_user_description(self):
raise NotImplementedError raise NotImplementedError
def get_wallet_type(self): def get_wallet_type(self) -> str:
raise NotImplementedError raise NotImplementedError

43
electrum/gui/qt/exception_window.py

@ -23,6 +23,7 @@
# SOFTWARE. # SOFTWARE.
import sys import sys
import html import html
from typing import TYPE_CHECKING, Optional, Set
from PyQt5.QtCore import QObject from PyQt5.QtCore import QObject
import PyQt5.QtCore as QtCore import PyQt5.QtCore as QtCore
@ -33,16 +34,22 @@ from electrum.i18n import _
from electrum.base_crash_reporter import BaseCrashReporter from electrum.base_crash_reporter import BaseCrashReporter
from electrum.logging import Logger from electrum.logging import Logger
from electrum import constants from electrum import constants
from electrum.network import Network
from .util import MessageBoxMixin, read_QIcon, WaitingDialog 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): class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
_active_window = None _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) BaseCrashReporter.__init__(self, exctype, value, tb)
self.main_window = main_window self.network = Network.get_instance()
self.config = config
QWidget.__init__(self) QWidget.__init__(self)
self.setWindowTitle('Electrum - ' + _('An Error Occurred')) self.setWindowTitle('Electrum - ' + _('An Error Occurred'))
@ -115,8 +122,8 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
f' <a href="{constants.GIT_REPO_ISSUES_URL}">on GitHub</a>.'), f' <a href="{constants.GIT_REPO_ISSUES_URL}">on GitHub</a>.'),
rich_text=True) rich_text=True)
proxy = self.main_window.network.proxy proxy = self.network.proxy
task = lambda: BaseCrashReporter.send_report(self, self.main_window.network.asyncio_loop, proxy) task = lambda: BaseCrashReporter.send_report(self, self.network.asyncio_loop, proxy)
msg = _('Sending crash report...') msg = _('Sending crash report...')
WaitingDialog(self, msg, task, on_success, on_failure) WaitingDialog(self, msg, task, on_success, on_failure)
@ -125,7 +132,7 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
self.close() self.close()
def show_never(self): def show_never(self):
self.main_window.config.set_key(BaseCrashReporter.config_key, False) self.config.set_key(BaseCrashReporter.config_key, False)
self.close() self.close()
def closeEvent(self, event): def closeEvent(self, event):
@ -136,7 +143,8 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger):
return self.description_textfield.toPlainText() return self.description_textfield.toPlainText()
def get_wallet_type(self): 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: def _get_traceback_str(self) -> str:
# The msg_box that shows the report uses rich_text=True, so # The msg_box that shows the report uses rich_text=True, so
@ -154,15 +162,26 @@ def _show_window(*args):
class Exception_Hook(QObject, Logger): class Exception_Hook(QObject, Logger):
_report_exception = QtCore.pyqtSignal(object, object, object, object) _report_exception = QtCore.pyqtSignal(object, object, object, object)
def __init__(self, main_window, *args, **kwargs): _INSTANCE = None # type: Optional[Exception_Hook] # singleton
QObject.__init__(self, *args, **kwargs)
def __init__(self, *, config: 'SimpleConfig'):
QObject.__init__(self)
Logger.__init__(self) Logger.__init__(self)
if not main_window.config.get(BaseCrashReporter.config_key, default=True): assert self._INSTANCE is None, "Exception_Hook is supposed to be a singleton"
return self.config = config
self.main_window = main_window self.wallet_types_seen = set() # type: Set[str]
sys.excepthook = self.handler sys.excepthook = self.handler
self._report_exception.connect(_show_window) 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): def handler(self, *exc_info):
self.logger.error('exception caught by crash reporter', exc_info=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)

7
electrum/gui/qt/main_window.py

@ -167,12 +167,12 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self.gui_object = gui_object self.gui_object = gui_object
self.config = config = gui_object.config # type: SimpleConfig self.config = config = gui_object.config # type: SimpleConfig
self.gui_thread = gui_object.gui_thread self.gui_thread = gui_object.gui_thread
assert wallet, "no wallet"
self.wallet = wallet
self.setup_exception_hook() self.setup_exception_hook()
self.network = gui_object.daemon.network # type: Network self.network = gui_object.daemon.network # type: Network
assert wallet, "no wallet"
self.wallet = wallet
self.fx = gui_object.daemon.fx # type: FxThread self.fx = gui_object.daemon.fx # type: FxThread
self.contacts = wallet.contacts self.contacts = wallet.contacts
self.tray = gui_object.tray self.tray = gui_object.tray
@ -304,7 +304,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
self._update_check_thread.start() self._update_check_thread.start()
def setup_exception_hook(self): def setup_exception_hook(self):
Exception_Hook(self) Exception_Hook.maybe_setup(config=self.config,
wallet=self.wallet)
def on_fx_history(self): def on_fx_history(self):
self.history_model.refresh('fx_history') self.history_model.refresh('fx_history')

Loading…
Cancel
Save