URI: 
       thw wallets: generalise 'minimum_library' for those that provide a version number - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 91c369e39288328f24fedc70e36eda67f5ad6dd3
   DIR parent 9279f30363d0e01ec0ee501eddd6966cf9a37d7e
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 23 Aug 2018 18:31:14 +0200
       
       hw wallets: generalise 'minimum_library' for those that provide a version number
       
       Diffstat:
         M electrum/base_wizard.py             |       3 ++-
         M electrum/plugin.py                  |       3 ++-
         M electrum/plugins/coldcard/coldcard… |      17 +++++++++++++----
         M electrum/plugins/hw_wallet/plugin.… |      36 ++++++++++++++++++++++++++++++-
         M electrum/plugins/hw_wallet/qt.py    |       6 +-----
         M electrum/plugins/safe_t/safe_t.py   |      28 +++++++++-------------------
         M electrum/plugins/trezor/trezor.py   |      28 +++++++++-------------------
       
       7 files changed, 71 insertions(+), 50 deletions(-)
       ---
   DIR diff --git a/electrum/base_wizard.py b/electrum/base_wizard.py
       t@@ -240,7 +240,8 @@ class BaseWizard(object):
                            u = devmgr.unpaired_device_infos(None, plugin, devices=scanned_devices)
                        except BaseException as e:
                            devmgr.print_error('error getting device infos for {}: {}'.format(name, e))
       -                    debug_msg += '  {}:\n    {}\n'.format(plugin.name, e)
       +                    indented_error_msg = '    '.join([''] + str(e).splitlines(keepends=True))
       +                    debug_msg += '  {}:\n{}\n'.format(plugin.name, indented_error_msg)
                            continue
                        devices += list(map(lambda x: (name, x), u))
                if not debug_msg:
   DIR diff --git a/electrum/plugin.py b/electrum/plugin.py
       t@@ -457,7 +457,8 @@ class DeviceMgr(ThreadJob, PrintError):
                '''Returns a list of DeviceInfo objects: one for each connected,
                unpaired device accepted by the plugin.'''
                if not plugin.libraries_available:
       -            raise Exception('Missing libraries for {}'.format(plugin.name))
       +            message = plugin.get_library_not_available_message()
       +            raise Exception(message)
                if devices is None:
                    devices = self.scan_devices()
                devices = [dev for dev in devices if not self.xpub_by_id(dev.id_)]
   DIR diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py
       t@@ -585,8 +585,8 @@ class Coldcard_KeyStore(Hardware_KeyStore):
        
        
        class ColdcardPlugin(HW_PluginBase):
       -    libraries_available = requirements_ok
            keystore_class = Coldcard_KeyStore
       +    minimum_library = (0, 7, 2)
            client = None
        
            DEVICE_IDS = [
       t@@ -600,10 +600,19 @@ class ColdcardPlugin(HW_PluginBase):
            def __init__(self, parent, config, name):
                HW_PluginBase.__init__(self, parent, config, name)
        
       -        if self.libraries_available:
       -            self.device_manager().register_devices(self.DEVICE_IDS)
       +        self.libraries_available = self.check_libraries_available() and requirements_ok
       +        if not self.libraries_available:
       +            return
       +
       +        self.device_manager().register_devices(self.DEVICE_IDS)
       +        self.device_manager().register_enumerate_func(self.detect_simulator)
        
       -            self.device_manager().register_enumerate_func(self.detect_simulator)
       +    def get_library_version(self):
       +        import ckcc
       +        try:
       +            return ckcc.__version__
       +        except AttributeError:
       +            return 'unknown'
        
            def detect_simulator(self):
                # if there is a simulator running on this machine,
   DIR diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py
       t@@ -27,7 +27,7 @@
        from electrum.plugin import BasePlugin, hook
        from electrum.i18n import _
        from electrum.bitcoin import is_address, TYPE_SCRIPT
       -from electrum.util import bfh
       +from electrum.util import bfh, versiontuple
        from electrum.transaction import opcodes, TxOutput
        
        
       t@@ -38,6 +38,8 @@ class HW_PluginBase(BasePlugin):
            #     libraries_available, libraries_URL, minimum_firmware,
            #     wallet_class, ckd_public, types, HidTransport
        
       +    minimum_library = (0, )
       +
            def __init__(self, parent, config, name):
                BasePlugin.__init__(self, parent, config, name)
                self.device = self.keystore_class.device
       t@@ -78,6 +80,38 @@ class HW_PluginBase(BasePlugin):
                    return False
                return True
        
       +    def get_library_version(self) -> str:
       +        """Returns the version of the 3rd party python library
       +        for the hw wallet. For example '0.9.0'
       +
       +        Returns 'unknown' if library is found but cannot determine version.
       +        Raises 'ImportError' if library is not found.
       +        """
       +        raise NotImplementedError()
       +
       +    def check_libraries_available(self) -> bool:
       +        try:
       +            library_version = self.get_library_version()
       +        except ImportError:
       +            return False
       +        if library_version == 'unknown' or \
       +                versiontuple(library_version) < self.minimum_library:
       +            self.libraries_available_message = (
       +                    _("Library version for '{}' is too old.").format(self.name)
       +                    + '\nInstalled: {}, Needed: {}'
       +                    .format(library_version, self.minimum_library))
       +            self.print_stderr(self.libraries_available_message)
       +            return False
       +        return True
       +
       +    def get_library_not_available_message(self) -> str:
       +        if hasattr(self, 'libraries_available_message'):
       +            message = self.libraries_available_message
       +        else:
       +            message = _("Missing libraries for {}.").format(self.name)
       +        message += '\n' + _("Make sure you install it with python3")
       +        return message
       +
        
        def is_any_tx_output_on_change_branch(tx):
            if not hasattr(tx, 'output_info'):
   DIR diff --git a/electrum/plugins/hw_wallet/qt.py b/electrum/plugins/hw_wallet/qt.py
       t@@ -189,11 +189,7 @@ class QtPluginBase(object):
                    if not isinstance(keystore, self.keystore_class):
                        continue
                    if not self.libraries_available:
       -                if hasattr(self, 'libraries_available_message'):
       -                    message = self.libraries_available_message + '\n'
       -                else:
       -                    message = _("Cannot find python library for") + " '%s'.\n" % self.name
       -                message += _("Make sure you install it with python3")
       +                message = keystore.plugin.get_library_not_available_message()
                        window.show_error(message)
                        return
                    tooltip = self.device + '\n' + (keystore.label or 'unnamed')
   DIR diff --git a/electrum/plugins/safe_t/safe_t.py b/electrum/plugins/safe_t/safe_t.py
       t@@ -82,25 +82,8 @@ class SafeTPlugin(HW_PluginBase):
            def __init__(self, parent, config, name):
                HW_PluginBase.__init__(self, parent, config, name)
        
       -        try:
       -            # Minimal test if python-safet is installed
       -            import safetlib
       -            try:
       -                library_version = safetlib.__version__
       -            except AttributeError:
       -                # python-safet only introduced __version__ in 0.1.0
       -                library_version = 'unknown'
       -            if library_version == 'unknown' or \
       -                    versiontuple(library_version) < self.minimum_library:
       -                self.libraries_available_message = (
       -                        _("Library version for '{}' is too old.").format(name)
       -                        + '\nInstalled: {}, Needed: {}'
       -                        .format(library_version, self.minimum_library))
       -                self.print_stderr(self.libraries_available_message)
       -                raise ImportError()
       -            self.libraries_available = True
       -        except ImportError:
       -            self.libraries_available = False
       +        self.libraries_available = self.check_libraries_available()
       +        if not self.libraries_available:
                    return
        
                from . import client
       t@@ -113,6 +96,13 @@ class SafeTPlugin(HW_PluginBase):
                self.transport_handler = transport.SafeTTransport()
                self.device_manager().register_enumerate_func(self.enumerate)
        
       +    def get_library_version(self):
       +        import safetlib
       +        try:
       +            return safetlib.__version__
       +        except AttributeError:
       +            return 'unknown'
       +
            def enumerate(self):
                devices = self.transport_handler.enumerate_devices()
                return [Device(d.get_path(), -1, d.get_path(), 'Safe-T mini', 0) for d in devices]
   DIR diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py
       t@@ -83,25 +83,8 @@ class TrezorPlugin(HW_PluginBase):
            def __init__(self, parent, config, name):
                HW_PluginBase.__init__(self, parent, config, name)
        
       -        try:
       -            # Minimal test if python-trezor is installed
       -            import trezorlib
       -            try:
       -                library_version = trezorlib.__version__
       -            except AttributeError:
       -                # python-trezor only introduced __version__ in 0.9.0
       -                library_version = 'unknown'
       -            if library_version == 'unknown' or \
       -                    versiontuple(library_version) < self.minimum_library:
       -                self.libraries_available_message = (
       -                        _("Library version for '{}' is too old.").format(name)
       -                        + '\nInstalled: {}, Needed: {}'
       -                        .format(library_version, self.minimum_library))
       -                self.print_stderr(self.libraries_available_message)
       -                raise ImportError()
       -            self.libraries_available = True
       -        except ImportError:
       -            self.libraries_available = False
       +        self.libraries_available = self.check_libraries_available()
       +        if not self.libraries_available:
                    return
        
                from . import client
       t@@ -114,6 +97,13 @@ class TrezorPlugin(HW_PluginBase):
                self.transport_handler = transport.TrezorTransport()
                self.device_manager().register_enumerate_func(self.enumerate)
        
       +    def get_library_version(self):
       +        import trezorlib
       +        try:
       +            return trezorlib.__version__
       +        except AttributeError:
       +            return 'unknown'
       +
            def enumerate(self):
                devices = self.transport_handler.enumerate_devices()
                return [Device(d.get_path(), -1, d.get_path(), 'TREZOR', 0) for d in devices]