URI: 
       thww: fix some threading issues in wizard - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 371f55a0f922cf57196ae3d8d7c2fabc7a9f0f08
   DIR parent 81fc3fcce2413bae55fc3e80a43744f7743745aa
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Wed,  1 Apr 2020 21:05:19 +0200
       
       hww: fix some threading issues in wizard
       
       fixes #3377
       related: #6064  (passphrase dialog not rendered correctly)
       
       Diffstat:
         M electrum/base_wizard.py             |       8 ++++++++
         M electrum/gui/qt/installwizard.py    |      20 ++++++++++++++++++++
         M electrum/plugins/digitalbitbox/dig… |       3 ++-
         M electrum/plugins/hw_wallet/plugin.… |       2 ++
         M electrum/plugins/keepkey/keepkey.py |       3 ++-
         M electrum/plugins/ledger/ledger.py   |       3 ++-
         M electrum/plugins/safe_t/safe_t.py   |       3 ++-
         M electrum/plugins/trezor/trezor.py   |       3 ++-
       
       8 files changed, 40 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
       t@@ -158,6 +158,13 @@ class BaseWizard(Logger):
                        exc = e
                self.waiting_dialog(do_upgrade, _('Upgrading wallet format...'), on_finished=on_finished)
        
       +    def run_task_without_blocking_gui(self, task, *, msg: str = None) -> Any:
       +        """Perform a task in a thread without blocking the GUI.
       +        Returns the result of 'task', or raises the same exception.
       +        This method blocks until 'task' is finished.
       +        """
       +        raise NotImplementedError()
       +
            def load_2fa(self):
                self.data['wallet_type'] = '2fa'
                self.data['use_trustedcoin'] = True
       t@@ -421,6 +428,7 @@ class BaseWizard(Logger):
            def on_hw_derivation(self, name, device_info: 'DeviceInfo', derivation, xtype):
                from .keystore import hardware_keystore
                devmgr = self.plugins.device_manager
       +        assert isinstance(self.plugin, HW_PluginBase)
                try:
                    xpub = self.plugin.get_xpub(device_info.device.id_, derivation, xtype, self)
                    client = devmgr.client_by_id(device_info.device.id_)
   DIR diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py
       t@@ -529,6 +529,26 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                if on_finished:
                    on_finished()
        
       +    def run_task_without_blocking_gui(self, task, *, msg=None):
       +        assert self.gui_thread == threading.current_thread(), 'must be called from GUI thread'
       +        if msg is None:
       +            msg = _("Please wait...")
       +
       +        exc = None  # type: Optional[Exception]
       +        res = None
       +        def task_wrapper():
       +            nonlocal exc
       +            nonlocal res
       +            try:
       +                task()
       +            except Exception as e:
       +                exc = e
       +        self.waiting_dialog(task_wrapper, msg=msg)
       +        if exc is None:
       +            return res
       +        else:
       +            raise exc
       +
            @wizard_dialog
            def choice_dialog(self, title, message, choices, run_next):
                c_values = [x[0] for x in choices]
   DIR diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py
       t@@ -707,7 +707,8 @@ class DigitalBitboxPlugin(HW_PluginBase):
                client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
                if purpose == HWD_SETUP_NEW_WALLET:
                    client.setupRunning = True
       -        client.get_xpub("m/44'/0'", 'standard')
       +        wizard.run_task_without_blocking_gui(
       +            task=lambda: client.get_xpub("m/44'/0'", 'standard'))
        
        
            def is_mobile_paired(self):
   DIR diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py
       t@@ -78,6 +78,8 @@ class HW_PluginBase(BasePlugin):
                """Called when creating a new wallet or when using the device to decrypt
                an existing wallet. Select the device to use.  If the device is
                uninitialized, go through the initialization process.
       +
       +        Runs in GUI thread.
                """
                raise NotImplementedError()
        
   DIR diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py
       t@@ -279,7 +279,8 @@ class KeepKeyPlugin(HW_PluginBase):
                client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
                if not device_info.initialized:
                    self.initialize_device(device_id, wizard, client.handler)
       -        client.get_xpub('m', 'standard')
       +        wizard.run_task_without_blocking_gui(
       +            task=lambda: client.get_xpub("m", 'standard'))
                client.used()
        
            def get_xpub(self, device_id, derivation, xtype, wizard):
   DIR diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py
       t@@ -591,7 +591,8 @@ class LedgerPlugin(HW_PluginBase):
            def setup_device(self, device_info, wizard, purpose):
                device_id = device_info.device.id_
                client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
       -        client.get_xpub("m/44'/0'", 'standard') # TODO replace by direct derivation once Nano S > 1.1
       +        wizard.run_task_without_blocking_gui(
       +            task=lambda: client.get_xpub("m/44'/0'", 'standard'))  # TODO replace by direct derivation once Nano S > 1.1
        
            def get_xpub(self, device_id, derivation, xtype, wizard):
                if xtype not in self.SUPPORTED_XTYPES:
   DIR diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py
       t@@ -253,7 +253,8 @@ class SafeTPlugin(HW_PluginBase):
                client = self.scan_and_create_client_for_device(device_id=device_id, wizard=wizard)
                if not device_info.initialized:
                    self.initialize_device(device_id, wizard, client.handler)
       -        client.get_xpub('m', 'standard')
       +        wizard.run_task_without_blocking_gui(
       +            task=lambda: client.get_xpub("m", 'standard'))
                client.used()
        
            def get_xpub(self, device_id, derivation, xtype, wizard):
   DIR diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py
       t@@ -280,7 +280,8 @@ class TrezorPlugin(HW_PluginBase):
                if not device_info.initialized:
                    self.initialize_device(device_id, wizard, client.handler)
                is_creating_wallet = purpose == HWD_SETUP_NEW_WALLET
       -        client.get_xpub('m', 'standard', creating=is_creating_wallet)
       +        wizard.run_task_without_blocking_gui(
       +            task=lambda: client.get_xpub('m', 'standard', creating=is_creating_wallet))
                client.used()
        
            def get_xpub(self, device_id, derivation, xtype, wizard):