# Buggy code
def selectWallet(self, testnet_seed=None):
    if jm_single().config.get("BLOCKCHAIN", "blockchain_source") != "regtest":
        # guaranteed to exist as load_program_config was called on startup:
        wallets_path = os.path.join(jm_single().datadir, "wallets")
        firstarg = QFileDialog.getOpenFileName(
            self,
            "Choose Wallet File",
            wallets_path,
            options=QFileDialog.DontUseNativeDialog,
        )
        # TODO validate the file looks vaguely like a wallet file
        log.debug("Looking for wallet in: " + str(firstarg))
        if not firstarg or not firstarg[0]:
            return
        decrypted = False
        while not decrypted:
            text, ok = QInputDialog.getText(
                self, "Decrypt wallet", "Enter your password:", echo=QLineEdit.Password
            )
            if not ok:
                return
            pwd = str(text).strip()
            try:
                decrypted = self.loadWalletFromBlockchain(firstarg[0], pwd)
            except Exception as e:
                JMQtMessageBox(self, str(e), mbtype="warn", title="Error")
                return
    else:
        if not testnet_seed:
            testnet_seed, ok = QInputDialog.getText(
                self, "Load Testnet wallet", "Enter a testnet seed:", QLineEdit.Normal
            )
            if not ok:
                return
        firstarg = str(testnet_seed)
        pwd = None
        # ignore return value as there is no decryption failure possible
        self.loadWalletFromBlockchain(firstarg, pwd)


# Traceback (jmclient.storage.StorageError)
2020-08-20 13:51:53,349 [DEBUG]  >>privmsg on darkscience: nick=JXXX cmd=pubkey msg=8XXX
2020-08-20 13:52:02,337 [DEBUG]  mix depths that have enough = {0: XXX}
2020-08-20 13:52:02,338 [INFO]  filling offer, mixdepth=0, amount=2XXX
2020-08-20 13:52:02,893 [INFO]  sending output to address=3XXX
Unhandled Error
Traceback (most recent call last):
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1041, in _commandReceived
deferred = self.dispatchCommand(box)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1099, in dispatchCommand
return maybeDeferred(responder, box)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
result = f(*args, **kw)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1186, in doit
return maybeDeferred(aCallable, **kw).addCallback(
--- <exception caught here> ---
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/protocols/amp.py", line 1169, in checkKnownErrors
key = error.trap(*command.allErrors)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
self.raiseException()
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
raise self.value.with_traceback(self.tb)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred
result = f(*args, **kw)
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/client_protocol.py", line 242, in on_JM_AUTH_RECEIVED
commitment, revelation, amount, kphex)
File "/home/nv01/joinmarket-clientserver/jmbase/jmbase/support.py", line 280, in func_wrapper
return func(inst, *newargs, **kwargs)
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/maker.py", line 105, in on_auth_received
self.wallet_service.save_wallet()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet_service.py", line 769, in save_wallet
self.wallet.save()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 1531, in save
super().save()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 1838, in save
super().save()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 385, in save
self._utxos.save()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/wallet.py", line 182, in save
self.storage.save()
File "/home/nv01/joinmarket-clientserver/jmclient/jmclient/storage.py", line 134, in save
raise StorageError("Read-only storage cannot be saved.")
jmclient.storage.StorageError: Read-only storage cannot be saved.

Amp server or network failure unhandled by client application.  Dropping connection!  To avoid, add errbacks to ALL remote commands!
Traceback (most recent call last):
--- <exception caught here> ---
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/internet/defer.py", line 654, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "/home/nv01/joinmarket-clientserver/jmdaemon/jmdaemon/daemon_protocol.py", line 114, in defaultErrback
ConnectionDone, ConnectionLost)
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 460, in trap
self.raiseException()
File "/home/nv01/joinmarket-clientserver/jmvenv/lib/python3.7/site-packages/twisted/python/failure.py", line 488, in raiseException
raise self.value.with_traceback(self.tb)
twisted.protocols.amp.UnknownRemoteError: Code<UNKNOWN>: Unknown Error

2020-08-20 13:52:45,357 [DEBUG]  Found a new channel, setting to: JXXX,('nXXX.onion', 6667)
2020-08-20 13:52:45,434 [DEBUG]  Nick: JXXX has left.
2020-08-20 13:53:43,052 [DEBUG]  Dynamic switch nick: JXXX
2020-08-20 13:55:25,035 [DEBUG]  JXXX has dusty minsize, capping at 2730
2020-08-20 13:55:25,155 [DEBUG]  JXXX has dusty minsize, capping at 2730
(...)

# Fixed code
def selectWallet(self, testnet_seed=None):
    if jm_single().config.get("BLOCKCHAIN", "blockchain_source") != "regtest":
        # guaranteed to exist as load_program_config was called on startup:
        wallets_path = os.path.join(jm_single().datadir, "wallets")
        firstarg = QFileDialog.getOpenFileName(
            self,
            "Choose Wallet File",
            wallets_path,
            options=QFileDialog.DontUseNativeDialog,
        )
        # TODO validate the file looks vaguely like a wallet file
        log.debug("Looking for wallet in: " + str(firstarg))
        if not firstarg or not firstarg[0]:
            return
        decrypted = False
        while not decrypted:
            text, ok = QInputDialog.getText(
                self, "Decrypt wallet", "Enter your password:", echo=QLineEdit.Password
            )
            if not ok:
                return
            pwd = str(text).strip()
            try:
                decrypted = self.loadWalletFromBlockchain(firstarg[0], pwd)
            except Exception as e:
                JMQtMessageBox(self, str(e), mbtype="warn", title="Error")
                return
            if decrypted == "error":
                # special case, not a failure to decrypt the file but
                # a failure of wallet loading, give up:
                self.close()
    else:
        if not testnet_seed:
            testnet_seed, ok = QInputDialog.getText(
                self, "Load Testnet wallet", "Enter a testnet seed:", QLineEdit.Normal
            )
            if not ok:
                return
        firstarg = str(testnet_seed)
        pwd = None
        # ignore return value as there is no decryption failure possible
        self.loadWalletFromBlockchain(firstarg, pwd)