URI: 
       tMerge pull request #4770 from SomberNight/kill_aiosafe - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit e573c6d385a26c68a6da3d0e744a078f8750a18a
   DIR parent ab441a507abc160803bbb60e1b5d165f0de6289f
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Fri, 12 Oct 2018 18:53:29 +0200
       
       Merge pull request #4770 from SomberNight/kill_aiosafe
       
       rm aiosafe decorator. instead: log_exceptions and ignore_exceptions
       Diffstat:
         M electrum/address_synchronizer.py    |       2 +-
         M electrum/exchange_rate.py           |       6 +++---
         M electrum/interface.py               |       8 +++-----
         M electrum/network.py                 |       7 ++++---
         M electrum/plugins/labels/labels.py   |       8 +++++---
         M electrum/util.py                    |      43 ++++++++++++++++++-------------
       
       6 files changed, 41 insertions(+), 33 deletions(-)
       ---
   DIR diff --git a/electrum/address_synchronizer.py b/electrum/address_synchronizer.py
       t@@ -28,7 +28,7 @@ from collections import defaultdict
        
        from . import bitcoin
        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 .synchronizer import Synchronizer
        from .verifier import SPV
   DIR diff --git a/electrum/exchange_rate.py b/electrum/exchange_rate.py
       t@@ -14,7 +14,7 @@ from typing import Sequence
        
        from .bitcoin import COIN
        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 .network import Network
        
       t@@ -58,7 +58,7 @@ class ExchangeBase(PrintError):
            def name(self):
                return self.__class__.__name__
        
       -    @aiosafe
       +    @log_exceptions
            async def update_safe(self, ccy):
                try:
                    self.print_error("getting fx quotes for", ccy)
       t@@ -89,7 +89,7 @@ class ExchangeBase(PrintError):
                    self.on_history()
                return h
        
       -    @aiosafe
       +    @log_exceptions
            async def get_historical_rates_safe(self, ccy, cache_dir):
                try:
                    self.print_error("requesting fx history for", ccy)
   DIR diff --git a/electrum/interface.py b/electrum/interface.py
       t@@ -34,7 +34,7 @@ from collections import defaultdict
        import aiorpcx
        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 x509
        from . import pem
       t@@ -146,9 +146,6 @@ class Interface(PrintError):
                self.tip_header = None
                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(
                    self.network.main_taskgroup.spawn(self.run()), self.network.asyncio_loop)
                self.group = SilentTaskGroup()
       t@@ -249,7 +246,8 @@ class Interface(PrintError):
                        self.got_disconnected.set_result(1)
                return wrapper_func
        
       -    @aiosafe
       +    @ignore_exceptions  # do not kill main_taskgroup
       +    @log_exceptions
            @handle_disconnect
            async def run(self):
                try:
   DIR diff --git a/electrum/network.py b/electrum/network.py
       t@@ -40,7 +40,7 @@ import dns.resolver
        from aiorpcx import TaskGroup
        
        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 . import constants
        from . import blockchain
       t@@ -478,7 +478,7 @@ class Network(PrintError):
                    addr = host
                return socket._getaddrinfo(addr, *args, **kwargs)
        
       -    @aiosafe
       +    @log_exceptions
            async def set_parameters(self, net_params: NetworkParameters):
                proxy = net_params.proxy
                proxy_str = serialize_proxy(proxy)
       t@@ -619,7 +619,8 @@ class Network(PrintError):
                    await self._close_interface(interface)
                    self.trigger_callback('network_updated')
        
       -    @aiosafe
       +    @ignore_exceptions  # do not kill main_taskgroup
       +    @log_exceptions
            async def _run_new_interface(self, server):
                interface = Interface(self, server, self.config.path, self.proxy)
                timeout = 10 if not self.proxy else 20
   DIR diff --git a/electrum/plugins/labels/labels.py b/electrum/plugins/labels/labels.py
       t@@ -9,7 +9,7 @@ import base64
        from electrum.plugin import BasePlugin, hook
        from electrum.crypto import aes_encrypt_with_iv, aes_decrypt_with_iv
        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):
        
       t@@ -58,7 +58,8 @@ class LabelsPlugin(BasePlugin):
                # Caller will write the wallet
                self.set_nonce(wallet, nonce + 1)
        
       -    @aiosafe
       +    @ignore_exceptions
       +    @log_exceptions
            async def do_post_safe(self, *args):
                await self.do_post(*args)
        
       t@@ -129,7 +130,8 @@ class LabelsPlugin(BasePlugin):
                self.set_nonce(wallet, response["nonce"] + 1)
                self.on_pulled(wallet)
        
       -    @aiosafe
       +    @ignore_exceptions
       +    @log_exceptions
            async def pull_safe_thread(self, wallet, force):
                await self.pull_thread(wallet, force)
        
   DIR diff --git a/electrum/util.py b/electrum/util.py
       t@@ -846,29 +846,36 @@ def make_dir(path, allow_symlink=True):
                os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
        
        
       -class AIOSafeSilentException(Exception): pass
       -
       -
       -def aiosafe(f):
       -    # save exception in object.
       -    # f must be a method of a PrintError instance.
       -    # aiosafe calls should not be nested
       -    async def f2(*args, **kwargs):
       -        self = args[0]
       +def log_exceptions(func):
       +    """Decorator to log AND re-raise exceptions."""
       +    assert asyncio.iscoroutinefunction(func), 'func needs to be a coroutine'
       +    async def wrapper(*args, **kwargs):
       +        self = args[0] if len(args) > 0 else None
                try:
       -            return await f(*args, **kwargs)
       -        except AIOSafeSilentException as e:
       -            self.exception = e
       +            return await func(*args, **kwargs)
                except asyncio.CancelledError as e:
       -            self.exception = e
       +            raise
                except BaseException as e:
       -            self.exception = e
       -            self.print_error("Exception in", f.__name__, ":", e.__class__.__name__, str(e))
       +            print_ = self.print_error if hasattr(self, 'print_error') else print_error
       +            print_("Exception in", func.__name__, ":", e.__class__.__name__, repr(e))
                    try:
                        traceback.print_exc(file=sys.stderr)
                    except BaseException as e2:
       -                self.print_error("aiosafe:traceback.print_exc raised: {}... original exc: {}".format(e2, e))
       -    return f2
       +                print_error("traceback.print_exc raised: {}...".format(e2))
       +            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),
                                                     ("conf", int),
       t@@ -941,7 +948,7 @@ class NetworkJobOnDefaultServer(PrintError):
            async def stop(self):
                await self.group.cancel_remaining()
        
       -    @aiosafe
       +    @log_exceptions
            async def _restart(self, *args):
                interface = self.network.interface
                if interface is None: