From 0866581b2c1e3b2d580b6cce3c937f27a256f6b7 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 5 Jun 2024 14:45:28 +0000 Subject: [PATCH] daemon error-handling: fix traceback.format_exception() on old python The new API for traceback.format_exception was only added in python 3.10 (https://github.com/python/cpython/commit/91e93794d5dd1aa91fbe142099c2955e0c4c1660). --- electrum/daemon.py | 4 ++-- electrum/util.py | 8 ++++++++ tests/qt_util.py | 4 +++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/electrum/daemon.py b/electrum/daemon.py index e6d446705..ad7a81430 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -46,7 +46,7 @@ from .network import Network from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare, InvalidPassword) from .invoices import PR_PAID, PR_EXPIRED from .util import log_exceptions, ignore_exceptions, randrange, OldTaskGroup, UserFacingException, JsonRPCError -from .util import EventListener, event_listener +from .util import EventListener, event_listener, traceback_format_exception from .wallet import Wallet, Abstract_Wallet from .storage import WalletStorage from .wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished @@ -264,7 +264,7 @@ class AuthenticatedServer(Logger): 'message': "internal error while executing RPC", 'data': { "exception": repr(e), - "traceback": "".join(traceback.format_exception(e)), + "traceback": "".join(traceback_format_exception(e)), }, } return web.json_response(response) diff --git a/electrum/util.py b/electrum/util.py index 40aff7dfb..1f44e2ee5 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -2064,6 +2064,14 @@ class nullcontext: pass +def traceback_format_exception(exc: BaseException) -> Sequence[str]: + """Compatibility wrapper for stdlib traceback.format_exception using python 3.10+ API.""" + if sys.version_info[:3] >= (3, 10): + return traceback.format_exception(exc) + else: + return traceback.format_exception(type(exc), value=exc, tb=exc.__traceback__) + + class classproperty(property): """~read-only class-level @property from https://stackoverflow.com/a/13624858 by denis-ryzhkov diff --git a/tests/qt_util.py b/tests/qt_util.py index cad939ed6..2863425ce 100644 --- a/tests/qt_util.py +++ b/tests/qt_util.py @@ -6,6 +6,8 @@ from unittest import SkipTest from PyQt6.QtCore import QCoreApplication, QMetaObject, Qt, pyqtSlot, QObject +from electrum.util import traceback_format_exception + class TestQCoreApplication(QCoreApplication): @pyqtSlot() @@ -76,7 +78,7 @@ def qt_test(func): if not res: self._e = Exception('testcase timed out') if self._e: - print("".join(traceback.format_exception(self._e))) + print("".join(traceback_format_exception(self._e))) # deallocate stored exception from qt thread otherwise we SEGV garbage collector # instead, re-create using the exception message, special casing AssertionError and SkipTest e = None