Browse Source

Merge pull request #4770 from SomberNight/kill_aiosafe

rm aiosafe decorator. instead: log_exceptions and ignore_exceptions
3.3.3.1
ThomasV 6 years ago
committed by GitHub
parent
commit
e573c6d385
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      electrum/address_synchronizer.py
  2. 6
      electrum/exchange_rate.py
  3. 8
      electrum/interface.py
  4. 7
      electrum/network.py
  5. 8
      electrum/plugins/labels/labels.py
  6. 43
      electrum/util.py

2
electrum/address_synchronizer.py

@ -28,7 +28,7 @@ from collections import defaultdict
from . import bitcoin from . import bitcoin
from .bitcoin import COINBASE_MATURITY, TYPE_ADDRESS, TYPE_PUBKEY from .bitcoin import COINBASE_MATURITY, TYPE_ADDRESS, TYPE_PUBKEY
from .util import PrintError, profiler, bfh, VerifiedTxInfo, TxMinedStatus, aiosafe, SilentTaskGroup from .util import PrintError, profiler, bfh, VerifiedTxInfo, TxMinedStatus
from .transaction import Transaction, TxOutput from .transaction import Transaction, TxOutput
from .synchronizer import Synchronizer from .synchronizer import Synchronizer
from .verifier import SPV from .verifier import SPV

6
electrum/exchange_rate.py

@ -14,7 +14,7 @@ from typing import Sequence
from .bitcoin import COIN from .bitcoin import COIN
from .i18n import _ from .i18n import _
from .util import PrintError, ThreadJob, make_dir, aiosafe from .util import PrintError, ThreadJob, make_dir, log_exceptions
from .util import make_aiohttp_session from .util import make_aiohttp_session
from .network import Network from .network import Network
@ -58,7 +58,7 @@ class ExchangeBase(PrintError):
def name(self): def name(self):
return self.__class__.__name__ return self.__class__.__name__
@aiosafe @log_exceptions
async def update_safe(self, ccy): async def update_safe(self, ccy):
try: try:
self.print_error("getting fx quotes for", ccy) self.print_error("getting fx quotes for", ccy)
@ -89,7 +89,7 @@ class ExchangeBase(PrintError):
self.on_history() self.on_history()
return h return h
@aiosafe @log_exceptions
async def get_historical_rates_safe(self, ccy, cache_dir): async def get_historical_rates_safe(self, ccy, cache_dir):
try: try:
self.print_error("requesting fx history for", ccy) self.print_error("requesting fx history for", ccy)

8
electrum/interface.py

@ -34,7 +34,7 @@ from collections import defaultdict
import aiorpcx import aiorpcx
from aiorpcx import ClientSession, Notification from aiorpcx import ClientSession, Notification
from .util import PrintError, aiosafe, bfh, AIOSafeSilentException, SilentTaskGroup from .util import PrintError, ignore_exceptions, log_exceptions, bfh, SilentTaskGroup
from . import util from . import util
from . import x509 from . import x509
from . import pem from . import pem
@ -146,9 +146,6 @@ class Interface(PrintError):
self.tip_header = None self.tip_header = None
self.tip = 0 self.tip = 0
# note that an interface dying MUST NOT kill the whole network,
# hence exceptions raised by "run" need to be caught not to kill
# main_taskgroup! the aiosafe decorator does this.
asyncio.run_coroutine_threadsafe( asyncio.run_coroutine_threadsafe(
self.network.main_taskgroup.spawn(self.run()), self.network.asyncio_loop) self.network.main_taskgroup.spawn(self.run()), self.network.asyncio_loop)
self.group = SilentTaskGroup() self.group = SilentTaskGroup()
@ -249,7 +246,8 @@ class Interface(PrintError):
self.got_disconnected.set_result(1) self.got_disconnected.set_result(1)
return wrapper_func return wrapper_func
@aiosafe @ignore_exceptions # do not kill main_taskgroup
@log_exceptions
@handle_disconnect @handle_disconnect
async def run(self): async def run(self):
try: try:

7
electrum/network.py

@ -40,7 +40,7 @@ import dns.resolver
from aiorpcx import TaskGroup from aiorpcx import TaskGroup
from . import util from . import util
from .util import PrintError, print_error, aiosafe, bfh, SilentTaskGroup from .util import PrintError, print_error, log_exceptions, ignore_exceptions, bfh, SilentTaskGroup
from .bitcoin import COIN from .bitcoin import COIN
from . import constants from . import constants
from . import blockchain from . import blockchain
@ -478,7 +478,7 @@ class Network(PrintError):
addr = host addr = host
return socket._getaddrinfo(addr, *args, **kwargs) return socket._getaddrinfo(addr, *args, **kwargs)
@aiosafe @log_exceptions
async def set_parameters(self, net_params: NetworkParameters): async def set_parameters(self, net_params: NetworkParameters):
proxy = net_params.proxy proxy = net_params.proxy
proxy_str = serialize_proxy(proxy) proxy_str = serialize_proxy(proxy)
@ -619,7 +619,8 @@ class Network(PrintError):
await self._close_interface(interface) await self._close_interface(interface)
self.trigger_callback('network_updated') self.trigger_callback('network_updated')
@aiosafe @ignore_exceptions # do not kill main_taskgroup
@log_exceptions
async def _run_new_interface(self, server): async def _run_new_interface(self, server):
interface = Interface(self, server, self.config.path, self.proxy) interface = Interface(self, server, self.config.path, self.proxy)
timeout = 10 if not self.proxy else 20 timeout = 10 if not self.proxy else 20

8
electrum/plugins/labels/labels.py

@ -9,7 +9,7 @@ import base64
from electrum.plugin import BasePlugin, hook from electrum.plugin import BasePlugin, hook
from electrum.crypto import aes_encrypt_with_iv, aes_decrypt_with_iv from electrum.crypto import aes_encrypt_with_iv, aes_decrypt_with_iv
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import aiosafe, make_aiohttp_session from electrum.util import log_exceptions, ignore_exceptions, make_aiohttp_session
class LabelsPlugin(BasePlugin): class LabelsPlugin(BasePlugin):
@ -58,7 +58,8 @@ class LabelsPlugin(BasePlugin):
# Caller will write the wallet # Caller will write the wallet
self.set_nonce(wallet, nonce + 1) self.set_nonce(wallet, nonce + 1)
@aiosafe @ignore_exceptions
@log_exceptions
async def do_post_safe(self, *args): async def do_post_safe(self, *args):
await self.do_post(*args) await self.do_post(*args)
@ -129,7 +130,8 @@ class LabelsPlugin(BasePlugin):
self.set_nonce(wallet, response["nonce"] + 1) self.set_nonce(wallet, response["nonce"] + 1)
self.on_pulled(wallet) self.on_pulled(wallet)
@aiosafe @ignore_exceptions
@log_exceptions
async def pull_safe_thread(self, wallet, force): async def pull_safe_thread(self, wallet, force):
await self.pull_thread(wallet, force) await self.pull_thread(wallet, force)

43
electrum/util.py

@ -846,29 +846,36 @@ def make_dir(path, allow_symlink=True):
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
class AIOSafeSilentException(Exception): pass def log_exceptions(func):
"""Decorator to log AND re-raise exceptions."""
assert asyncio.iscoroutinefunction(func), 'func needs to be a coroutine'
def aiosafe(f): async def wrapper(*args, **kwargs):
# save exception in object. self = args[0] if len(args) > 0 else None
# f must be a method of a PrintError instance.
# aiosafe calls should not be nested
async def f2(*args, **kwargs):
self = args[0]
try: try:
return await f(*args, **kwargs) return await func(*args, **kwargs)
except AIOSafeSilentException as e:
self.exception = e
except asyncio.CancelledError as e: except asyncio.CancelledError as e:
self.exception = e raise
except BaseException as e: except BaseException as e:
self.exception = e print_ = self.print_error if hasattr(self, 'print_error') else print_error
self.print_error("Exception in", f.__name__, ":", e.__class__.__name__, str(e)) print_("Exception in", func.__name__, ":", e.__class__.__name__, repr(e))
try: try:
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
except BaseException as e2: except BaseException as e2:
self.print_error("aiosafe:traceback.print_exc raised: {}... original exc: {}".format(e2, e)) print_error("traceback.print_exc raised: {}...".format(e2))
return f2 raise
return wrapper
def ignore_exceptions(func):
"""Decorator to silently swallow all exceptions."""
assert asyncio.iscoroutinefunction(func), 'func needs to be a coroutine'
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except BaseException as e:
pass
return wrapper
TxMinedStatus = NamedTuple("TxMinedStatus", [("height", int), TxMinedStatus = NamedTuple("TxMinedStatus", [("height", int),
("conf", int), ("conf", int),
@ -941,7 +948,7 @@ class NetworkJobOnDefaultServer(PrintError):
async def stop(self): async def stop(self):
await self.group.cancel_remaining() await self.group.cancel_remaining()
@aiosafe @log_exceptions
async def _restart(self, *args): async def _restart(self, *args):
interface = self.network.interface interface = self.network.interface
if interface is None: if interface is None:

Loading…
Cancel
Save