Browse Source

whitespace, imports, code style

master
Sander van Grieken 2 years ago
parent
commit
190c19d48c
  1. 7
      electrum/gui/qml/__init__.py
  2. 10
      electrum/gui/qml/auth.py
  3. 44
      electrum/gui/qml/qeaddresslistmodel.py
  4. 3
      electrum/gui/qml/qebip39recovery.py
  5. 3
      electrum/gui/qml/qebitcoin.py
  6. 50
      electrum/gui/qml/qechannellistmodel.py
  7. 26
      electrum/gui/qml/qechannelopener.py
  8. 11
      electrum/gui/qml/qeconfig.py
  9. 24
      electrum/gui/qml/qedaemon.py
  10. 1
      electrum/gui/qml/qefx.py
  11. 7
      electrum/gui/qml/qeinvoice.py
  12. 34
      electrum/gui/qml/qeinvoicelistmodel.py
  13. 2
      electrum/gui/qml/qelnpaymentdetails.py
  14. 12
      electrum/gui/qml/qenetwork.py
  15. 16
      electrum/gui/qml/qeqr.py
  16. 3
      electrum/gui/qml/qerequestdetails.py
  17. 45
      electrum/gui/qml/qeserverlistmodel.py
  18. 25
      electrum/gui/qml/qetransactionlistmodel.py
  19. 9
      electrum/gui/qml/qetxdetails.py
  20. 28
      electrum/gui/qml/qetxfinalizer.py
  21. 3
      electrum/gui/qml/qetypes.py
  22. 35
      electrum/gui/qml/qewallet.py
  23. 1
      electrum/gui/qml/qewalletdb.py
  24. 50
      electrum/gui/qml/qewizard.py
  25. 6
      electrum/gui/qml/util.py
  26. 4
      electrum/gui/qt/wizard/wizard.py

7
electrum/gui/qml/__init__.py

@ -2,7 +2,6 @@ import os
import signal
import sys
import threading
import traceback
from typing import TYPE_CHECKING
try:
@ -15,11 +14,10 @@ try:
except Exception:
sys.exit("Error: Could not import PyQt5.QtQml on Linux systems, you may try 'sudo apt-get install python3-pyqt5.qtquick'")
from PyQt5.QtCore import (Qt, QCoreApplication, QObject, QLocale, QTranslator, QTimer, pyqtSignal,
QT_VERSION_STR, PYQT_VERSION_STR)
from PyQt5.QtCore import (Qt, QCoreApplication, QLocale, QTranslator, QTimer, QT_VERSION_STR, PYQT_VERSION_STR)
from PyQt5.QtGui import QGuiApplication
from electrum.i18n import _, set_language, languages
from electrum.i18n import _
from electrum.plugin import run_hook
from electrum.util import profiler
from electrum.logging import Logger
@ -29,7 +27,6 @@ if TYPE_CHECKING:
from electrum.daemon import Daemon
from electrum.simple_config import SimpleConfig
from electrum.plugin import Plugins
from electrum.wallet import Abstract_Wallet
from .qeapp import ElectrumQmlApplication, Exception_Hook

10
electrum/gui/qml/auth.py

@ -1,9 +1,10 @@
from functools import wraps, partial
from PyQt5.QtCore import pyqtSignal, pyqtSlot, pyqtProperty
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from electrum.logging import get_logger
def auth_protect(func=None, reject=None, method='pin', message=''):
if func is None:
return partial(auth_protect, reject=reject, method=method, message=message)
@ -20,6 +21,7 @@ def auth_protect(func=None, reject=None, method='pin', message=''):
return wrapper
class AuthMixin:
_auth_logger = get_logger(__name__)
authRequired = pyqtSignal([str, str], arguments=['method', 'authMessage'])
@ -29,14 +31,14 @@ class AuthMixin:
self._auth_logger.debug('Proceeding with authed fn()')
try:
self._auth_logger.debug(str(getattr(self, '__auth_fcall')))
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
(func, args, kwargs, reject) = getattr(self, '__auth_fcall')
r = func(self, *args, **kwargs)
return r
except Exception as e:
self._auth_logger.error(f'Error executing wrapped fn(): {repr(e)}')
raise e
finally:
delattr(self,'__auth_fcall')
delattr(self, '__auth_fcall')
@pyqtSlot()
def authCancel(self):
@ -45,7 +47,7 @@ class AuthMixin:
return
try:
(func,args,kwargs,reject) = getattr(self, '__auth_fcall')
(func, args, kwargs, reject) = getattr(self, '__auth_fcall')
if reject is not None:
if hasattr(self, reject):
getattr(self, reject)()

44
electrum/gui/qml/qeaddresslistmodel.py

@ -1,7 +1,7 @@
import itertools
from typing import TYPE_CHECKING
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger
@ -17,27 +17,30 @@ class QEAddressListModel(QAbstractListModel):
_logger = get_logger(__name__)
# define listmodel rolemap
_ROLE_NAMES=('type','iaddr','address','label','balance','numtx', 'held')
_ROLE_NAMES=('type', 'iaddr', 'address', 'label', 'balance', 'numtx', 'held')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
def __init__(self, wallet: 'Abstract_Wallet', parent=None):
super().__init__(parent)
self.wallet = wallet
self.setDirty()
self._receive_addresses = []
self._change_addresses = []
self._dirty = True
self.initModel()
def rowCount(self, index):
return len(self.receive_addresses) + len(self.change_addresses)
return len(self._receive_addresses) + len(self._change_addresses)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
if index.row() > len(self.receive_addresses) - 1:
address = self.change_addresses[index.row() - len(self.receive_addresses)]
if index.row() > len(self._receive_addresses) - 1:
address = self._change_addresses[index.row() - len(self._receive_addresses)]
else:
address = self.receive_addresses[index.row()]
address = self._receive_addresses[index.row()]
role_index = role - Qt.UserRole
value = address[self._ROLE_NAMES[role_index]]
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
@ -48,18 +51,19 @@ class QEAddressListModel(QAbstractListModel):
def clear(self):
self.beginResetModel()
self.receive_addresses = []
self.change_addresses = []
self._receive_addresses = []
self._change_addresses = []
self.endResetModel()
def addr_to_model(self, address):
item = {}
item['address'] = address
item['numtx'] = self.wallet.adb.get_address_history_len(address)
item['label'] = self.wallet.get_label_for_address(address)
c, u, x = self.wallet.get_addr_balance(address)
item['balance'] = QEAmount(amount_sat=c + u + x)
item['held'] = self.wallet.is_frozen_address(address)
item = {
'address': address,
'numtx': self.wallet.adb.get_address_history_len(address),
'label': self.wallet.get_label_for_address(address),
'balance': QEAmount(amount_sat=c + u + x),
'held': self.wallet.is_frozen_address(address)
}
return item
@pyqtSlot()
@ -86,21 +90,21 @@ class QEAddressListModel(QAbstractListModel):
self.beginInsertRows(QModelIndex(), 0, n_addresses - 1)
if self.wallet.wallet_type != 'imported':
for i, address in enumerate(r_addresses):
insert_row('receive', self.receive_addresses, address, i)
insert_row('receive', self._receive_addresses, address, i)
for i, address in enumerate(c_addresses):
insert_row('change', self.change_addresses, address, i)
insert_row('change', self._change_addresses, address, i)
else:
for i, address in enumerate(r_addresses):
insert_row('imported', self.receive_addresses, address, i)
insert_row('imported', self._receive_addresses, address, i)
self.endInsertRows()
self._dirty = False
@pyqtSlot(str)
def updateAddress(self, address):
for i, a in enumerate(itertools.chain(self.receive_addresses, self.change_addresses)):
for i, a in enumerate(itertools.chain(self._receive_addresses, self._change_addresses)):
if a['address'] == address:
self.do_update(i,a)
self.do_update(i, a)
return
def do_update(self, modelindex, modelitem):

3
electrum/gui/qml/qebip39recovery.py

@ -26,7 +26,6 @@ class QEBip39RecoveryListModel(QAbstractListModel):
recoveryFailed = pyqtSignal()
stateChanged = pyqtSignal()
# userinfoChanged = pyqtSignal()
# define listmodel rolemap
_ROLE_NAMES=('description', 'derivation_path', 'script_type')
@ -112,7 +111,7 @@ class QEBip39RecoveryListModel(QAbstractListModel):
if isinstance(e, concurrent.futures.CancelledError):
self.state = QEBip39RecoveryListModel.State.Cancelled
return
self._logger.error(f"recovery error", exc_info=exc_info)
self._logger.error(f'recovery error', exc_info=exc_info)
self.state = QEBip39RecoveryListModel.State.Failed
self._thread.stop()

3
electrum/gui/qml/qebitcoin.py

@ -5,7 +5,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum import mnemonic
from electrum import keystore
from electrum.i18n import _
from electrum.bip32 import is_bip32_derivation, normalize_bip32_derivation, xpub_type
from electrum.bip32 import is_bip32_derivation, xpub_type
from electrum.logging import get_logger
from electrum.slip39 import decode_mnemonic, Slip39Error
from electrum.util import get_asyncio_loop
@ -13,7 +13,6 @@ from electrum.transaction import tx_from_any
from electrum.mnemonic import Mnemonic, is_any_2fa_seed_type
from electrum.old_mnemonic import wordlist as old_wordlist
from .qetypes import QEAmount
class QEBitcoin(QObject):
_logger = get_logger(__name__)

50
electrum/gui/qml/qechannellistmodel.py

@ -29,6 +29,11 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
def __init__(self, wallet, parent=None):
super().__init__(parent)
self.wallet = wallet
self._channels = []
self._fm_backups = None
self._fm_nobackups = None
self.initModel()
# To avoid leaking references to "self" that prevent the
@ -52,19 +57,19 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
self.unregister_callbacks()
def rowCount(self, index):
return len(self.channels)
return len(self._channels)
# also expose rowCount as a property
countChanged = pyqtSignal()
@pyqtProperty(int, notify=countChanged)
def count(self):
return len(self.channels)
return len(self._channels)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
tx = self.channels[index.row()]
tx = self._channels[index.row()]
role_index = role - Qt.UserRole
value = tx[self._ROLE_NAMES[role_index]]
if isinstance(value, (bool, list, int, str, QEAmount)) or value is None:
@ -75,21 +80,22 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
def clear(self):
self.beginResetModel()
self.channels = []
self._channels = []
self.endResetModel()
def channel_to_model(self, lnc):
lnworker = self.wallet.lnworker
item = {}
item['cid'] = lnc.channel_id.hex()
item['node_id'] = lnc.node_id.hex()
item['node_alias'] = lnworker.get_node_alias(lnc.node_id) or ''
item['short_cid'] = lnc.short_id_for_GUI()
item['state'] = lnc.get_state_for_GUI()
item['state_code'] = int(lnc.get_state())
item['is_backup'] = lnc.is_backup()
item['is_trampoline'] = lnworker.is_trampoline_peer(lnc.node_id)
item['capacity'] = QEAmount(amount_sat=lnc.get_capacity())
item = {
'cid': lnc.channel_id.hex(),
'node_id': lnc.node_id.hex(),
'node_alias': lnworker.get_node_alias(lnc.node_id) or '',
'short_cid': lnc.short_id_for_GUI(),
'state': lnc.get_state_for_GUI(),
'state_code': int(lnc.get_state()),
'is_backup': lnc.is_backup(),
'is_trampoline': lnworker.is_trampoline_peer(lnc.node_id),
'capacity': QEAmount(amount_sat=lnc.get_capacity())
}
if lnc.is_backup():
item['can_send'] = QEAmount()
item['can_receive'] = QEAmount()
@ -111,7 +117,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
numOpenChannelsChanged = pyqtSignal()
@pyqtProperty(int, notify=numOpenChannelsChanged)
def numOpenChannels(self):
return sum([1 if x['state_code'] == ChannelState.OPEN else 0 for x in self.channels])
return sum([1 if x['state_code'] == ChannelState.OPEN else 0 for x in self._channels])
@pyqtSlot()
def initModel(self):
@ -134,20 +140,20 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
self.clear()
self.beginInsertRows(QModelIndex(), 0, len(channels) - 1)
self.channels = channels
self._channels = channels
self.endInsertRows()
self.countChanged.emit()
def on_channel_updated(self, channel):
for i, c in enumerate(self.channels):
for i, c in enumerate(self._channels):
if c['cid'] == channel.channel_id.hex():
self.do_update(i,channel)
self.do_update(i, channel)
break
def do_update(self, modelindex, channel):
self._logger.debug(f'updating our channel {channel.short_id_for_GUI()}')
modelitem = self.channels[modelindex]
modelitem = self._channels[modelindex]
modelitem.update(self.channel_to_model(channel))
mi = self.createIndex(modelindex, 0)
@ -163,7 +169,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
item = self.channel_to_model(channel)
self._logger.debug(item)
self.beginInsertRows(QModelIndex(), 0, 0)
self.channels.insert(0,item)
self._channels.insert(0, item)
self.endInsertRows()
self.countChanged.emit()
return
@ -171,11 +177,11 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
@pyqtSlot(str)
def removeChannel(self, cid):
self._logger.debug('remove channel with cid %s' % cid)
for i, channel in enumerate(self.channels):
for i, channel in enumerate(self._channels):
if cid == channel['cid']:
self._logger.debug(cid)
self.beginRemoveRows(QModelIndex(), i, i)
self.channels.remove(channel)
self._channels.remove(channel)
self.endRemoveRows()
self.countChanged.emit()
return

26
electrum/gui/qml/qechannelopener.py

@ -27,7 +27,8 @@ class QEChannelOpener(QObject, AuthMixin):
conflictingBackup = pyqtSignal([str], arguments=['message'])
channelOpening = pyqtSignal([str], arguments=['peer'])
channelOpenError = pyqtSignal([str], arguments=['message'])
channelOpenSuccess = pyqtSignal([str,bool,int,bool], arguments=['cid','has_onchain_backup','min_depth','tx_complete'])
channelOpenSuccess = pyqtSignal([str, bool, int, bool],
arguments=['cid', 'has_onchain_backup', 'min_depth', 'tx_complete'])
dataChanged = pyqtSignal() # generic notify signal
@ -41,6 +42,10 @@ class QEChannelOpener(QObject, AuthMixin):
self._opentx = None
self._txdetails = None
self._finalizer = None
self._node_pubkey = None
self._connect_str_resolved = None
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)
def wallet(self):
@ -124,7 +129,7 @@ class QEChannelOpener(QObject, AuthMixin):
self.validChanged.emit()
return
self._logger.debug('amount=%s' % str(self._amount))
self._logger.debug(f'amount={self._amount}')
if not self._amount or not (self._amount.satsInt > 0 or self._amount.isMax):
self._valid = False
self.validChanged.emit()
@ -136,9 +141,9 @@ class QEChannelOpener(QObject, AuthMixin):
@pyqtSlot(str, result=bool)
def validateConnectString(self, connect_str):
try:
node_id, rest = extract_nodeid(connect_str)
extract_nodeid(connect_str)
except ConnStringFormatError as e:
self._logger.debug(f"invalid connect_str. {e!r}")
self._logger.debug(f'invalid connect_str. {e!r}')
return False
return True
@ -199,13 +204,13 @@ class QEChannelOpener(QObject, AuthMixin):
chan.constraints.funding_txn_minimum_depth, funding_tx.is_complete())
# TODO: handle incomplete TX
#if not funding_tx.is_complete():
#self._txdetails = QETxDetails(self)
#self._txdetails.rawTx = funding_tx
#self._txdetails.wallet = self._wallet
#self.txDetailsChanged.emit()
# if not funding_tx.is_complete():
# self._txdetails = QETxDetails(self)
# self._txdetails.rawTx = funding_tx
# self._txdetails.wallet = self._wallet
# self.txDetailsChanged.emit()
except (CancelledError,TimeoutError):
except (CancelledError, TimeoutError):
error = _('Could not connect to channel peer')
except Exception as e:
error = str(e)
@ -216,7 +221,6 @@ class QEChannelOpener(QObject, AuthMixin):
self._logger.exception("Problem opening channel: %s", error)
self.channelOpenError.emit(error)
self._logger.debug('starting open thread')
self.channelOpening.emit(conn_str)
threading.Thread(target=open_thread, daemon=True).start()

11
electrum/gui/qml/qeconfig.py

@ -7,13 +7,14 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QRegularEx
from electrum.bitcoin import TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
from electrum.i18n import set_language, languages
from electrum.logging import get_logger
from electrum.util import DECIMAL_POINT_DEFAULT, base_unit_name_to_decimal_point
from electrum.invoices import PR_DEFAULT_EXPIRATION_WHEN_CREATING
from electrum.simple_config import SimpleConfig
from electrum.util import base_unit_name_to_decimal_point
from .qetypes import QEAmount
from .auth import AuthMixin, auth_protect
if TYPE_CHECKING:
from electrum.simple_config import SimpleConfig
class QEConfig(AuthMixin, QObject):
_logger = get_logger(__name__)
@ -251,7 +252,7 @@ class QEConfig(AuthMixin, QObject):
return self.config.BTC_AMOUNTS_DECIMAL_POINT
def max_precision(self):
return self.decimal_point() + 0 #self.extra_precision
return self.decimal_point() + 0 # self.extra_precision
@pyqtSlot(str, result=QEAmount)
def unitsToSats(self, unitAmount):
@ -275,4 +276,4 @@ class QEConfig(AuthMixin, QObject):
@pyqtSlot('quint64', result=float)
def satsToUnits(self, satoshis):
return satoshis / pow(10,self.config.decimal_point)
return satoshis / pow(10, self.config.decimal_point)

24
electrum/gui/qml/qedaemon.py

@ -28,23 +28,24 @@ class QEWalletListModel(QAbstractListModel):
_logger = get_logger(__name__)
# define listmodel rolemap
_ROLE_NAMES= ('name','path','active')
_ROLE_NAMES= ('name', 'path', 'active')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
def __init__(self, daemon, parent=None):
QAbstractListModel.__init__(self, parent)
self.daemon = daemon
self._wallets = []
self.reload()
def rowCount(self, index):
return len(self.wallets)
return len(self._wallets)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
(wallet_name, wallet_path) = self.wallets[index.row()]
(wallet_name, wallet_path) = self._wallets[index.row()]
role_index = role - Qt.UserRole
role_name = self._ROLE_NAMES[role_index]
if role_name == 'name':
@ -58,7 +59,7 @@ class QEWalletListModel(QAbstractListModel):
def reload(self):
self._logger.debug('enumerating available wallets')
self.beginResetModel()
self.wallets = []
self._wallets = []
self.endResetModel()
available = []
@ -72,18 +73,18 @@ class QEWalletListModel(QAbstractListModel):
self.add_wallet(wallet_path = path)
def add_wallet(self, wallet_path):
self.beginInsertRows(QModelIndex(), len(self.wallets), len(self.wallets))
self.beginInsertRows(QModelIndex(), len(self._wallets), len(self._wallets))
wallet_name = os.path.basename(wallet_path)
wallet_path = standardize_path(wallet_path)
item = (wallet_name, wallet_path)
self.wallets.append(item)
self._wallets.append(item)
self.endInsertRows()
def remove_wallet(self, path):
i = 0
wallets = []
remove = -1
for wallet_name, wallet_path in self.wallets:
for wallet_name, wallet_path in self._wallets:
if wallet_path == path:
remove = i
else:
@ -92,12 +93,12 @@ class QEWalletListModel(QAbstractListModel):
if remove >= 0:
self.beginRemoveRows(QModelIndex(), i, i)
self.wallets = wallets
self._wallets = wallets
self.endRemoveRows()
@pyqtSlot(str, result=bool)
def wallet_name_exists(self, name):
for wallet_name, wallet_path in self.wallets:
for wallet_name, wallet_path in self._wallets:
if name == wallet_name:
return True
return False
@ -105,7 +106,7 @@ class QEWalletListModel(QAbstractListModel):
@pyqtSlot(str)
def updateWallet(self, path):
i = 0
for wallet_name, wallet_path in self.wallets:
for wallet_name, wallet_path in self._wallets:
if wallet_path == path:
mi = self.createIndex(i, i)
self.dataChanged.emit(mi, mi, self._ROLE_KEYS)
@ -238,7 +239,7 @@ class QEDaemon(AuthMixin, QObject):
@pyqtSlot()
@pyqtSlot(str)
def _on_backend_wallet_loaded(self, password = None):
def _on_backend_wallet_loaded(self, password=None):
self._logger.debug('_on_backend_wallet_loaded')
wallet = self.daemon.get_wallet(self._path)
assert wallet is not None
@ -247,7 +248,6 @@ class QEDaemon(AuthMixin, QObject):
self._current_wallet.password = password if password else None
self.walletLoaded.emit(self._name, self._path)
@pyqtSlot(QEWallet)
@pyqtSlot(QEWallet, bool)
@pyqtSlot(QEWallet, bool, bool)

1
electrum/gui/qml/qefx.py

@ -11,6 +11,7 @@ from electrum.simple_config import SimpleConfig
from .qetypes import QEAmount
from .util import QtEventListener, event_listener
class QEFX(QObject, QtEventListener):
_logger = get_logger(__name__)

7
electrum/gui/qml/qeinvoice.py

@ -403,6 +403,7 @@ class QEInvoiceParser(QEInvoice):
self._recipient = ''
self._pi = None
self._lnurlData = None
self.clear()
@ -476,7 +477,7 @@ class QEInvoiceParser(QEInvoice):
self.setValidOnchainInvoice(invoice)
self.validationSuccess.emit()
else:
self.validationError.emit('unknown', f"invoice error:\n{pr.error}")
self.validationError.emit('unknown', f'invoice error:\n{pr.error}')
def validateRecipient(self, recipient):
if not recipient:
@ -485,7 +486,8 @@ class QEInvoiceParser(QEInvoice):
self._pi = PaymentIdentifier(self._wallet.wallet, recipient)
if not self._pi.is_valid() or self._pi.type not in [PaymentIdentifierType.SPK, PaymentIdentifierType.BIP21,
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11, PaymentIdentifierType.LNURLP]:
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11,
PaymentIdentifierType.LNURLP]:
self.validationError.emit('unknown', _('Unknown invoice'))
return
@ -552,6 +554,7 @@ class QEInvoiceParser(QEInvoice):
def resolve_pi(self):
assert self._pi.need_resolve()
def on_finished(pi):
if pi.is_error():
pass

34
electrum/gui/qml/qeinvoicelistmodel.py

@ -1,7 +1,7 @@
from abc import abstractmethod
from typing import TYPE_CHECKING, List, Dict, Any
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
from PyQt5.QtCore import pyqtSlot, QTimer
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger
@ -29,6 +29,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
def __init__(self, wallet: 'Abstract_Wallet', parent=None):
super().__init__(parent)
self.wallet = wallet
self._invoices = []
self._timer = QTimer(self)
self._timer.setSingleShot(True)
@ -41,13 +42,13 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
raise e
def rowCount(self, index):
return len(self.invoices)
return len(self._invoices)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
invoice = self.invoices[index.row()]
invoice = self._invoices[index.row()]
role_index = role - Qt.UserRole
value = invoice[self._ROLE_NAMES[role_index]]
@ -59,7 +60,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
def clear(self):
self.beginResetModel()
self.invoices = []
self._invoices = []
self.endResetModel()
@pyqtSlot()
@ -71,7 +72,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
self.clear()
self.beginInsertRows(QModelIndex(), 0, len(invoices) - 1)
self.invoices = invoices
self._invoices = invoices
self.endInsertRows()
self.set_status_timer()
@ -79,7 +80,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
def add_invoice(self, invoice: BaseInvoice):
# skip if already in list
key = invoice.get_id()
for x in self.invoices:
for x in self._invoices:
if x['key'] == key:
return
@ -87,7 +88,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
self._logger.debug(str(item))
self.beginInsertRows(QModelIndex(), 0, 0)
self.invoices.insert(0, item)
self._invoices.insert(0, item)
self.endInsertRows()
self.set_status_timer()
@ -97,29 +98,29 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
self.add_invoice(self.get_invoice_for_key(key))
def delete_invoice(self, key: str):
for i, invoice in enumerate(self.invoices):
for i, invoice in enumerate(self._invoices):
if invoice['key'] == key:
self.beginRemoveRows(QModelIndex(), i, i)
self.invoices.pop(i)
self._invoices.pop(i)
self.endRemoveRows()
break
self.set_status_timer()
def get_model_invoice(self, key: str):
for invoice in self.invoices:
for invoice in self._invoices:
if invoice['key'] == key:
return invoice
return None
@pyqtSlot(str, int)
def updateInvoice(self, key, status):
self._logger.debug('updating invoice for %s to %d' % (key,status))
for i, item in enumerate(self.invoices):
self._logger.debug(f'updating invoice for {key} to {status}')
for i, item in enumerate(self._invoices):
if item['key'] == key:
invoice = self.get_invoice_for_key(key)
item['status'] = status
item['status_str'] = invoice.get_status_str(status)
index = self.index(i,0)
index = self.index(i, 0)
self.dataChanged.emit(index, index, [self._ROLE_RMAP['status'], self._ROLE_RMAP['status_str']])
return
@ -137,7 +138,7 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
def set_status_timer(self):
nearest_interval = LN_EXPIRY_NEVER
for invoice in self.invoices:
for invoice in self._invoices:
if invoice['status'] != PR_EXPIRED:
if invoice['expiry'] > 0 and invoice['expiry'] != LN_EXPIRY_NEVER:
interval = status_update_timer_interval(invoice['timestamp'] + invoice['expiry'])
@ -150,11 +151,11 @@ class QEAbstractInvoiceListModel(QAbstractListModel):
@pyqtSlot()
def updateStatusStrings(self):
for i, item in enumerate(self.invoices):
for i, item in enumerate(self._invoices):
invoice = self.get_invoice_for_key(item['key'])
item['status'] = self.wallet.get_invoice_status(invoice)
item['status_str'] = invoice.get_status_str(item['status'])
index = self.index(i,0)
index = self.index(i, 0)
self.dataChanged.emit(index, index, [self._ROLE_RMAP['status'], self._ROLE_RMAP['status_str']])
self.set_status_timer()
@ -206,6 +207,7 @@ class QEInvoiceListModel(QEAbstractInvoiceListModel, QtEventListener):
def get_invoice_as_dict(self, invoice: Invoice):
return self.wallet.export_invoice(invoice)
class QERequestListModel(QEAbstractInvoiceListModel, QtEventListener):
def __init__(self, wallet, parent=None):
super().__init__(wallet, parent)

2
electrum/gui/qml/qelnpaymentdetails.py

@ -45,7 +45,7 @@ class QELnPaymentDetails(QObject):
@key.setter
def key(self, key: str):
if self._key != key:
self._logger.debug('key set -> %s' % key)
self._logger.debug(f'key set -> {key}')
self._key = key
self.keyChanged.emit()
self.update()

12
electrum/gui/qml/qenetwork.py

@ -1,6 +1,6 @@
from typing import TYPE_CHECKING
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject
from electrum.logging import get_logger
from electrum import constants
@ -178,7 +178,6 @@ class QENetwork(QObject, QtEventListener):
self._logger.debug(f'unknown channels {unknown}')
self._gossipUnknownChannels = unknown
self.gossipUpdated.emit()
#self.lightning_gossip_num_queries = unknown
def on_gossip_setting_changed(self):
if not self.network:
@ -205,7 +204,8 @@ class QENetwork(QObject, QtEventListener):
net_params = self.network.get_parameters()
try:
server = ServerAddr.from_str_with_inference(server)
if not server: raise Exception("failed to parse")
if not server:
raise Exception('failed to parse')
except Exception:
return
net_params = net_params._replace(server=server, auto_connect=self._qeconfig.autoConnect)
@ -215,7 +215,7 @@ class QENetwork(QObject, QtEventListener):
def serverWithStatus(self):
server = self._server
if not self.network.is_connected(): # connecting or disconnected
return f"{server} (connecting...)"
return f'{server} (connecting...)'
return server
@pyqtProperty(str, notify=statusChanged)
@ -244,7 +244,7 @@ class QENetwork(QObject, QtEventListener):
@pyqtProperty(str, notify=dataChanged)
def networkName(self):
return constants.net.__name__.replace('Bitcoin','')
return constants.net.__name__.replace('Bitcoin', '')
@pyqtProperty('QVariantMap', notify=proxyChanged)
def proxy(self):
@ -275,7 +275,7 @@ class QENetwork(QObject, QtEventListener):
'peers': self._gossipPeers,
'unknown_channels': self._gossipUnknownChannels,
'db_nodes': self._gossipDbNodes,
'db_channels': self._gossipDbChannels ,
'db_channels': self._gossipDbChannels,
'db_policies': self._gossipDbPolicies
}

16
electrum/gui/qml/qeqr.py

@ -16,6 +16,7 @@ from electrum.qrreader import get_qr_reader
from electrum.i18n import _
from electrum.util import profiler, get_asyncio_loop
class QEQRParser(QObject):
_logger = get_logger(__name__)
@ -28,6 +29,7 @@ class QEQRParser(QObject):
self._busy = False
self._image = None
self._data = None
self._text = text
self.qrreader = get_qr_reader()
@ -118,10 +120,12 @@ class QEQRParser(QObject):
result.append(QPoint(x+self.scan_pos_x, y+self.scan_pos_y))
return result
class QEQRImageProvider(QQuickImageProvider):
def __init__(self, max_size, parent=None):
super().__init__(QQuickImageProvider.Image)
self._max_size = max_size
self.qimg = None
_logger = get_logger(__name__)
@ -161,6 +165,7 @@ class QEQRImageProvider(QQuickImageProvider):
self.qimg.fill(QColor('gray'))
return self.qimg, self.qimg.size()
# helper for placing icon exactly where it should go on the QR code
# pyqt5 is unwilling to accept slots on QEQRImageProvider, so we need to define
# a separate class (sigh)
@ -187,6 +192,11 @@ class QEQRImageProviderHelper(QObject):
qr.box_size = math.floor(pixelsize/modules)
# calculate icon width in modules
icon_modules = int(modules / 5)
icon_modules += (icon_modules+1)%2 # force odd
return { 'modules': modules, 'box_size': qr.box_size, 'icon_modules': icon_modules, 'valid' : valid }
icon_modules += (icon_modules+1) % 2 # force odd
return {
'modules': modules,
'box_size': qr.box_size,
'icon_modules': icon_modules,
'valid': valid
}

3
electrum/gui/qml/qerequestdetails.py

@ -83,7 +83,6 @@ class QERequestDetails(QObject, QtEventListener):
self.keyChanged.emit()
self.initRequest()
statusChanged = pyqtSignal()
@pyqtProperty(int, notify=statusChanged)
def status(self):
return self._wallet.wallet.get_invoice_status(self._req)
@ -133,7 +132,6 @@ class QERequestDetails(QObject, QtEventListener):
def bip21(self):
return self._req.get_bip21_URI() if self._req else ''
def initRequest(self):
if self._wallet is None or self._key is None:
return
@ -160,7 +158,6 @@ class QERequestDetails(QObject, QtEventListener):
self._timer.setInterval(interval) # msec
self._timer.start()
@pyqtSlot()
def updateStatusString(self):
self.statusChanged.emit()

45
electrum/gui/qml/qeserverlistmodel.py

@ -1,8 +1,8 @@
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger
from electrum.util import Satoshis, format_time
from electrum.util import Satoshis
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL
from electrum import blockchain
@ -22,6 +22,7 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
super().__init__(parent)
self._chaintips = 0
self._servers = []
self.network = network
self.initModel()
@ -44,13 +45,13 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
self.initModel()
def rowCount(self, index):
return len(self.servers)
return len(self._servers)
def roleNames(self):
return self._ROLE_MAP
def data(self, index, role):
server = self.servers[index.row()]
server = self._servers[index.row()]
role_index = role - Qt.UserRole
value = server[self._ROLE_NAMES[role_index]]
@ -62,7 +63,7 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
def clear(self):
self.beginResetModel()
self.servers = []
self._servers = []
self.endResetModel()
chaintipsChanged = pyqtSignal()
@ -97,14 +98,15 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
self._logger.debug(f'chain {chain_id} has name={name}, max_forkpoint=@{b.get_max_forkpoint()}, height={b.height()}')
for i in interfaces:
server = {}
server['chain'] = name
server['chain_height'] = b.height()
server['is_primary'] = i == self.network.interface
server['is_connected'] = True
server['name'] = str(i.server)
server['address'] = i.server.to_friendly_name()
server['height'] = i.tip
server = {
'chain': name,
'chain_height': b.height(),
'is_primary': i == self.network.interface,
'is_connected': True,
'name': str(i.server),
'address': i.server.to_friendly_name(),
'height': i.tip
}
servers.append(server)
@ -120,17 +122,18 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
port = d.get(protocol)
if port:
s = ServerAddr(_host, port, protocol=protocol)
server = {}
server['chain'] = ''
server['chain_height'] = 0
server['height'] = 0
server['is_primary'] = False
server['is_connected'] = False
server['name'] = s.net_addr_str()
server = {
'chain': '',
'chain_height': 0,
'height': 0,
'is_primary': False,
'is_connected': False,
'name': s.net_addr_str()
}
server['address'] = server['name']
servers.append(server)
self.beginInsertRows(QModelIndex(), 0, len(servers) - 1)
self.servers = servers
self._servers = servers
self.endInsertRows()

25
electrum/gui/qml/qetransactionlistmodel.py

@ -1,7 +1,7 @@
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Dict, Any
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger
@ -19,9 +19,9 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
_logger = get_logger(__name__)
# define listmodel rolemap
_ROLE_NAMES=('txid','fee_sat','height','confirmations','timestamp','monotonic_timestamp',
'incoming','value','date','label','txpos_in_block','fee',
'inputs','outputs','section','type','lightning','payment_hash','key','complete')
_ROLE_NAMES=('txid', 'fee_sat', 'height', 'confirmations', 'timestamp', 'monotonic_timestamp',
'incoming', 'value', 'date', 'label', 'txpos_in_block', 'fee',
'inputs', 'outputs', 'section', 'type', 'lightning', 'payment_hash', 'key', 'complete')
_ROLE_KEYS = range(Qt.UserRole, Qt.UserRole + len(_ROLE_NAMES))
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES]))
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS))
@ -34,11 +34,13 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
self.onchain_domain = onchain_domain
self.include_lightning = include_lightning
self.tx_history = []
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
self.requestRefresh.connect(lambda: self.initModel())
self.setDirty()
self._dirty = True
self.initModel()
def on_destroy(self):
@ -159,19 +161,19 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
txts = datetime.fromtimestamp(timestamp)
today = datetime.today().replace(hour=0, minute=0, second=0, microsecond=0)
if (txts > today):
if txts > today:
return 'today'
elif (txts > today - timedelta(days=1)):
elif txts > today - timedelta(days=1):
return 'yesterday'
elif (txts > today - timedelta(days=7)):
elif txts > today - timedelta(days=7):
return 'lastweek'
elif (txts > today - timedelta(days=31)):
elif txts > today - timedelta(days=31):
return 'lastmonth'
else:
return 'older'
def format_date_by_section(self, section, date):
#TODO: l10n
# TODO: l10n
dfmt = {
'today': '%H:%M:%S',
'yesterday': '%H:%M:%S',
@ -194,7 +196,6 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
)
return tx_mined_info
# initial model data
@pyqtSlot()
@pyqtSlot(bool)
def initModel(self, force: bool = False):
@ -231,7 +232,7 @@ class QETransactionListModel(QAbstractListModel, QtEventListener):
tx['section'] = self.get_section_by_timestamp(info.timestamp)
tx['date'] = self.format_date_by_section(tx['section'], datetime.fromtimestamp(info.timestamp))
index = self.index(i,0)
roles = [self._ROLE_RMAP[x] for x in ['section','height','confirmations','timestamp','date']]
roles = [self._ROLE_RMAP[x] for x in ['section', 'height', 'confirmations', 'timestamp', 'date']]
self.dataChanged.emit(index, index, roles)
return

9
electrum/gui/qml/qetxdetails.py

@ -4,7 +4,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.i18n import _
from electrum.logging import get_logger
from electrum.util import format_time, AddTransactionException, TxMinedInfo
from electrum.util import format_time, TxMinedInfo
from electrum.transaction import tx_from_any, Transaction
from electrum.network import Network
@ -12,6 +12,7 @@ from .qewallet import QEWallet
from .qetypes import QEAmount
from .util import QtEventListener, event_listener
class QETxDetails(QObject, QtEventListener):
_logger = get_logger(__name__)
@ -68,13 +69,13 @@ class QETxDetails(QObject, QtEventListener):
@event_listener
def on_event_verified(self, wallet, txid, info):
if wallet == self._wallet.wallet and txid == self._txid:
self._logger.debug('verified event for our txid %s' % txid)
self._logger.debug(f'verified event for our txid {txid}')
self.update()
@event_listener
def on_event_new_transaction(self, wallet, tx):
if wallet == self._wallet.wallet and tx.txid() == self._txid:
self._logger.debug('new_transaction event for our txid %s' % self._txid)
self._logger.debug(f'new_transaction event for our txid {txid}')
self.update()
walletChanged = pyqtSignal()
@ -292,7 +293,7 @@ class QETxDetails(QObject, QtEventListener):
group_id = item.get('group_id')
if group_id:
full_history = self._wallet.wallet.get_full_history()
group_item = full_history['group:'+ group_id]
group_item = full_history['group:' + group_id]
self._lnamount.satsInt = int(group_item['ln_value'].value)
else:
self._lnamount.satsInt = int(item['amount_msat'] / 1000)

28
electrum/gui/qml/qetxfinalizer.py

@ -291,7 +291,7 @@ class QETxFinalizer(TxFeeSlider):
@profiler
def make_tx(self, amount):
self._logger.debug('make_tx amount = %s' % str(amount))
self._logger.debug(f'make_tx amount={amount}')
if self.f_make_tx:
tx = self.f_make_tx(amount)
@ -299,7 +299,7 @@ class QETxFinalizer(TxFeeSlider):
# default impl
coins = self._wallet.wallet.get_spendable_coins(None)
outputs = [PartialTxOutput.from_address_and_value(self.address, amount)]
tx = self._wallet.wallet.make_unsigned_transaction(coins=coins,outputs=outputs, fee=None,rbf=self._rbf)
tx = self._wallet.wallet.make_unsigned_transaction(coins=coins, outputs=outputs, fee=None, rbf=self._rbf)
self._logger.debug('fee: %d, inputs: %d, outputs: %d' % (tx.get_fee(), len(tx.inputs()), len(tx.outputs())))
@ -312,7 +312,7 @@ class QETxFinalizer(TxFeeSlider):
try:
# make unsigned transaction
tx = self.make_tx(amount = '!' if self._amount.isMax else self._amount.satsInt)
tx = self.make_tx(amount='!' if self._amount.isMax else self._amount.satsInt)
except NotEnoughFunds:
self.warning = _("Not enough funds")
self._valid = False
@ -373,10 +373,7 @@ class QETxFinalizer(TxFeeSlider):
self.f_accept(self._tx)
return
self._wallet.sign(self._tx,
broadcast=True,
on_success=partial(self.on_signed_tx, False)
)
self._wallet.sign(self._tx, broadcast=True, on_success=partial(self.on_signed_tx, False))
@pyqtSlot()
def sign(self):
@ -384,10 +381,7 @@ class QETxFinalizer(TxFeeSlider):
self._logger.error('no valid tx')
return
self._wallet.sign(self._tx,
broadcast=False,
on_success=partial(self.on_signed_tx, True)
)
self._wallet.sign(self._tx, broadcast=False, on_success=partial(self.on_signed_tx, True))
def on_signed_tx(self, save: bool, tx: Transaction):
self._logger.debug('on_signed_tx')
@ -405,12 +399,13 @@ class QETxFinalizer(TxFeeSlider):
return [str(self._tx), txqr[0], txqr[1]]
# mixin for watching an existing TX based on its txid for verified event
# requires self._wallet to contain a QEWallet instance
# exposes txid qt property
# calls get_tx() once txid is set
# calls tx_verified and emits txMined signal once tx is verified
class TxMonMixin(QtEventListener):
""" mixin for watching an existing TX based on its txid for verified event.
requires self._wallet to contain a QEWallet instance.
exposes txid qt property.
calls get_tx() once txid is set.
calls tx_verified and emits txMined signal once tx is verified.
"""
txMined = pyqtSignal()
def __init__(self, parent=None):
@ -505,7 +500,6 @@ class QETxRbfFeeBumper(TxFeeSlider, TxMonMixin):
self.bumpMethodChanged.emit()
self.update()
def get_tx(self):
assert self._txid
self._orig_tx = self._wallet.wallet.db.get_transaction(self._txid)

3
electrum/gui/qml/qetypes.py

@ -11,10 +11,11 @@ from electrum.i18n import _
# should also capture millisats amounts and MAX/'!' indicators
# and (unformatted) string representations
class QEAmount(QObject):
_logger = get_logger(__name__)
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, from_invoice = None, parent=None):
def __init__(self, *, amount_sat: int = 0, amount_msat: int = 0, is_max: bool = False, from_invoice=None, parent=None):
super().__init__(parent)
self._amount_sat = int(amount_sat) if amount_sat is not None else None
self._amount_msat = int(amount_msat) if amount_msat is not None else None

35
electrum/gui/qml/qewallet.py

@ -2,18 +2,17 @@ import asyncio
import queue
import threading
import time
from typing import TYPE_CHECKING, Optional, Tuple, Callable
from typing import TYPE_CHECKING, Callable
from functools import partial
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, QMetaObject, Qt
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer
from electrum import bitcoin
from electrum.i18n import _
from electrum.invoices import InvoiceError, PR_DEFAULT_EXPIRATION_WHEN_CREATING, PR_PAID, PR_BROADCASTING, PR_BROADCAST
from electrum.invoices import InvoiceError, PR_PAID, PR_BROADCASTING, PR_BROADCAST
from electrum.logging import get_logger
from electrum.network import TxBroadcastError, BestEffortRequestFailed
from electrum.transaction import PartialTxOutput, PartialTransaction, Transaction
from electrum.util import parse_max_spend, InvalidPassword, event_listener, AddTransactionException, get_asyncio_loop
from electrum.transaction import PartialTransaction, Transaction
from electrum.util import InvalidPassword, event_listener, AddTransactionException, get_asyncio_loop
from electrum.plugin import run_hook
from electrum.wallet import Multisig_Wallet
from electrum.crypto import pw_decode_with_version_and_mac
@ -30,6 +29,7 @@ if TYPE_CHECKING:
from electrum.wallet import Abstract_Wallet
from .qeinvoice import QEInvoice
class QEWallet(AuthMixin, QObject, QtEventListener):
__instances = []
@ -53,12 +53,14 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
# shared signal for many static wallet properties
dataChanged = pyqtSignal()
balanceChanged = pyqtSignal()
requestStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
requestCreateSuccess = pyqtSignal([str], arguments=['key'])
requestCreateError = pyqtSignal([str], arguments=['error'])
invoiceStatusChanged = pyqtSignal([str,int], arguments=['key','status'])
invoiceCreateSuccess = pyqtSignal()
invoiceCreateError = pyqtSignal([str,str], arguments=['code','error'])
paymentAuthRejected = pyqtSignal()
paymentSucceeded = pyqtSignal([str], arguments=['key'])
paymentFailed = pyqtSignal([str,str], arguments=['key','reason'])
requestNewPassword = pyqtSignal()
@ -196,7 +198,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
if wallet == self.wallet:
self._logger.info(f'removed transaction {tx.txid()}')
self.addressModel.setDirty()
self.historyModel.initModel(True) #setDirty()
self.historyModel.initModel(True) # setDirty()?
self.balanceChanged.emit()
@qt_event_listener
@ -431,8 +433,6 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
return self.wallet.m == 1
return True
balanceChanged = pyqtSignal()
@pyqtProperty(QEAmount, notify=balanceChanged)
def frozenBalance(self):
c, u, x = self.wallet.get_frozen_balance()
@ -499,9 +499,11 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
success = self.do_sign(tx, broadcast)
if success:
if on_success: on_success(tx)
if on_success:
on_success(tx)
else:
if on_failure: on_failure()
if on_failure:
on_failure()
def do_sign(self, tx, broadcast):
try:
@ -534,14 +536,16 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
# this assumes a 2fa wallet, but there are no other tc_sign_wrapper hooks, so that's ok
def on_sign_complete(self, broadcast, cb: Callable[[Transaction], None] = None, tx: Transaction = None):
self.otpSuccess.emit()
if cb: cb(tx)
if cb:
cb(tx)
if broadcast:
self.broadcast(tx)
# this assumes a 2fa wallet, but there are no other tc_sign_wrapper hooks, so that's ok
def on_sign_failed(self, cb: Callable[[], None] = None, error: str = None):
self.otpFailed.emit('error', error)
if cb: cb()
if cb:
cb()
def request_otp(self, on_submit):
self._otp_on_submit = on_submit
@ -577,7 +581,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
threading.Thread(target=broadcast_thread, daemon=True).start()
#TODO: properly catch server side errors, e.g. bad-txns-inputs-missingorspent
# TODO: properly catch server side errors, e.g. bad-txns-inputs-missingorspent
def save_tx(self, tx: 'PartialTransaction'):
assert tx
@ -595,7 +599,6 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
self.saveTxError.emit(tx.txid(), 'error', str(e))
return False
paymentAuthRejected = pyqtSignal()
def ln_auth_rejected(self):
self.paymentAuthRejected.emit()
@ -724,7 +727,7 @@ class QEWallet(AuthMixin, QObject, QtEventListener):
xpub = self.wallet.get_fingerprint()
decrypted = pw_decode_with_version_and_mac(encrypted, xpub)
return True
except Exception as e:
except Exception:
return False
@pyqtSlot()

1
electrum/gui/qml/qewalletdb.py

@ -142,7 +142,6 @@ class QEWalletDB(QObject):
self.invalidPassword.emit()
else: # storage not encrypted; but it might still have a keystore pw
# FIXME hack... load both db and full wallet, just to tell if it has keystore pw.
# this also completely ignores db.requires_split(), db.get_action(), etc
try:
db = WalletDB(self._storage.read(), storage=self._storage, upgrade=True)
except WalletRequiresSplit as e:

50
electrum/gui/qml/qewizard.py

@ -13,9 +13,13 @@ if TYPE_CHECKING:
class QEAbstractWizard(QObject):
""" Concrete subclasses of QEAbstractWizard must also inherit from a concrete AbstractWizard subclass.
QEAbstractWizard forms the base for all QML GUI based wizards, while AbstractWizard defines
the base for non-gui wizard flow navigation functionality.
"""
_logger = get_logger(__name__)
def __init__(self, parent = None):
def __init__(self, parent=None):
QObject.__init__(self, parent)
@pyqtSlot(result=str)
@ -45,32 +49,33 @@ class QEAbstractWizard(QObject):
class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
createError = pyqtSignal([str], arguments=["error"])
createSuccess = pyqtSignal()
def __init__(self, daemon: 'QEDaemon', plugins: 'Plugins', parent = None):
def __init__(self, daemon: 'QEDaemon', plugins: 'Plugins', parent=None):
NewWalletWizard.__init__(self, daemon.daemon, plugins)
QEAbstractWizard.__init__(self, parent)
self._qedaemon = daemon
self._path = None
self._password = None
# attach view names and accept handlers
self.navmap_merge({
'wallet_name': { 'gui': 'WCWalletName' },
'wallet_type': { 'gui': 'WCWalletType' },
'keystore_type': { 'gui': 'WCKeystoreType' },
'create_seed': { 'gui': 'WCCreateSeed' },
'confirm_seed': { 'gui': 'WCConfirmSeed' },
'have_seed': { 'gui': 'WCHaveSeed' },
'script_and_derivation': { 'gui': 'WCScriptAndDerivation' },
'have_master_key': { 'gui': 'WCHaveMasterKey' },
'multisig': { 'gui': 'WCMultisig' },
'multisig_cosigner_keystore': { 'gui': 'WCCosignerKeystore' },
'multisig_cosigner_key': { 'gui': 'WCHaveMasterKey' },
'multisig_cosigner_seed': { 'gui': 'WCHaveSeed' },
'multisig_cosigner_script_and_derivation': { 'gui': 'WCScriptAndDerivation' },
'imported': { 'gui': 'WCImport' },
'wallet_password': { 'gui': 'WCWalletPassword' }
'wallet_name': {'gui': 'WCWalletName'},
'wallet_type': {'gui': 'WCWalletType'},
'keystore_type': {'gui': 'WCKeystoreType'},
'create_seed': {'gui': 'WCCreateSeed'},
'confirm_seed': {'gui': 'WCConfirmSeed'},
'have_seed': {'gui': 'WCHaveSeed'},
'script_and_derivation': {'gui': 'WCScriptAndDerivation'},
'have_master_key': {'gui': 'WCHaveMasterKey'},
'multisig': {'gui': 'WCMultisig'},
'multisig_cosigner_keystore': {'gui': 'WCCosignerKeystore'},
'multisig_cosigner_key': {'gui': 'WCHaveMasterKey'},
'multisig_cosigner_seed': {'gui': 'WCHaveSeed'},
'multisig_cosigner_script_and_derivation': {'gui': 'WCScriptAndDerivation'},
'imported': {'gui': 'WCImport'},
'wallet_password': {'gui': 'WCWalletPassword'}
})
pathChanged = pyqtSignal()
@ -127,15 +132,14 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard):
class QEServerConnectWizard(ServerConnectWizard, QEAbstractWizard):
def __init__(self, daemon: 'QEDaemon', parent=None):
ServerConnectWizard.__init__(self, daemon.daemon)
QEAbstractWizard.__init__(self, parent)
# attach view names
self.navmap_merge({
'autoconnect': { 'gui': 'WCAutoConnect' },
'proxy_ask': { 'gui': 'WCProxyAsk' },
'proxy_config': { 'gui': 'WCProxyConfig' },
'server_config': { 'gui': 'WCServerConfig' },
'autoconnect': {'gui': 'WCAutoConnect'},
'proxy_ask': {'gui': 'WCProxyAsk'},
'proxy_config': {'gui': 'WCProxyConfig'},
'server_config': {'gui': 'WCServerConfig'},
})

6
electrum/gui/qml/util.py

@ -31,6 +31,7 @@ class QtEventListener(EventListener):
# decorator for members of the QtEventListener class
def qt_event_listener(func):
func = event_listener(func)
@wraps(func)
def decorator(self, *args):
self.qt_callback_signal.emit( (func,) + args)
@ -56,10 +57,11 @@ def status_update_timer_interval(exp):
return interval
# TODO: copied from desktop client, this could be moved to a set of common code.
class TaskThread(QThread, Logger):
'''Thread that runs background tasks. Callbacks are guaranteed
to happen in the context of its parent.'''
"""Thread that runs background tasks. Callbacks are guaranteed
to happen in the context of its parent."""
class Task(NamedTuple):
task: Callable

4
electrum/gui/qt/wizard/wizard.py

@ -19,6 +19,10 @@ if TYPE_CHECKING:
class QEAbstractWizard(QDialog, MessageBoxMixin):
""" Concrete subclasses of QEAbstractWizard must also inherit from a concrete AbstractWizard subclass.
QEAbstractWizard forms the base for all QtWidgets GUI based wizards, while AbstractWizard defines
the base for non-gui wizard flow navigation functionality.
"""
_logger = get_logger(__name__)
requestNext = pyqtSignal()

Loading…
Cancel
Save