From 19cd408f9804c36a169537d273053e55e203f6a9 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Thu, 23 Jan 2025 12:58:28 +0100 Subject: [PATCH] organize import, whitespace --- electrum/commands.py | 10 +++++- electrum/daemon.py | 29 ++++++++-------- electrum/gui/qt/__init__.py | 5 ++- electrum/gui/qt/address_dialog.py | 2 +- electrum/gui/qt/address_list.py | 2 +- electrum/gui/qt/amountedit.py | 3 +- electrum/gui/qt/balance_dialog.py | 11 +++---- electrum/gui/qt/bip39_recovery_dialog.py | 4 +-- electrum/gui/qt/channel_details.py | 3 ++ electrum/gui/qt/channels_list.py | 22 ++++++++----- electrum/gui/qt/completion_text_edit.py | 1 + electrum/gui/qt/confirm_tx_dialog.py | 12 +++---- electrum/gui/qt/console.py | 10 +++--- electrum/gui/qt/custom_model.py | 3 +- electrum/gui/qt/exception_window.py | 1 + electrum/gui/qt/fee_slider.py | 1 + electrum/gui/qt/history_list.py | 23 ++++++------- electrum/gui/qt/invoice_list.py | 7 ++-- electrum/gui/qt/lightning_tx_dialog.py | 6 ++-- electrum/gui/qt/locktimeedit.py | 2 +- electrum/gui/qt/main_window.py | 27 ++++++--------- electrum/gui/qt/my_treeview.py | 42 ++++++++---------------- electrum/gui/qt/network_dialog.py | 9 ++--- electrum/gui/qt/new_channel_dialog.py | 7 +--- electrum/gui/qt/password_dialog.py | 7 ++-- electrum/gui/qt/paytoedit.py | 4 +-- electrum/gui/qt/plugins_dialog.py | 8 ++--- electrum/gui/qt/qrcodewidget.py | 6 +--- electrum/gui/qt/rbf_dialog.py | 11 +++---- electrum/gui/qt/rebalance_dialog.py | 1 - electrum/gui/qt/receive_tab.py | 7 ++-- electrum/gui/qt/request_list.py | 8 ++--- electrum/gui/qt/seed_dialog.py | 2 +- electrum/gui/qt/settings_dialog.py | 37 ++++++++++++++++----- electrum/gui/qt/transaction_dialog.py | 21 ++++++------ electrum/gui/qt/update_checker.py | 3 +- electrum/gui/qt/utxo_dialog.py | 2 +- electrum/gui/qt/utxo_list.py | 4 +-- electrum/transaction.py | 2 -- electrum/x509.py | 1 + 40 files changed, 180 insertions(+), 186 deletions(-) diff --git a/electrum/commands.py b/electrum/commands.py index c4f3c75ec..2d6442e32 100644 --- a/electrum/commands.py +++ b/electrum/commands.py @@ -88,10 +88,12 @@ class NotSynchronizedException(UserFacingException): def satoshis_or_max(amount): return satoshis(amount) if not parse_max_spend(amount) else amount + def satoshis(amount): # satoshi conversion must not be performed by the parser return int(COIN*to_decimal(amount)) if amount is not None else None + def format_satoshis(x): return str(to_decimal(x)/COIN) if x is not None else None @@ -1448,6 +1450,7 @@ def eval_bool(x: str) -> bool: except Exception: return bool(x) + param_descriptions = { 'privkey': 'Private key. Type \'?\' to get a prompt.', 'destination': 'Bitcoin address, contact or alias', @@ -1548,7 +1551,6 @@ arg_types = { } config_variables = { - 'addrequest': { 'ssl_privkey': 'Path to your SSL private key, needed to sign the request.', 'ssl_chain': 'Chain of SSL certificates, needed for signed requests. Put your certificate at the top and the root CA at the end', @@ -1559,6 +1561,7 @@ config_variables = { } } + def set_default_subparser(self, name, args=None): """see http://stackoverflow.com/questions/5176691/argparse-how-to-specify-a-default-subcommand""" subparser_found = False @@ -1580,6 +1583,7 @@ def set_default_subparser(self, name, args=None): else: args.insert(0, name) + argparse.ArgumentParser.set_default_subparser = set_default_subparser @@ -1608,6 +1612,7 @@ def subparser_call(self, parser, namespace, values, option_string=None): vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, []) getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) + argparse._SubParsersAction.__call__ = subparser_call @@ -1630,6 +1635,7 @@ def add_network_options(parser): parser.add_argument("--skipmerklecheck", action="store_true", dest=SimpleConfig.NETWORK_SKIPMERKLECHECK.key(), default=None, help="Tolerate invalid merkle proofs from server") + def add_global_options(parser): group = parser.add_argument_group('global options') group.add_argument("-v", dest="verbosity", help="Set verbosity (log levels)", default='') @@ -1645,10 +1651,12 @@ def add_global_options(parser): group.add_argument("--rpcuser", dest=SimpleConfig.RPC_USERNAME.key(), default=argparse.SUPPRESS, help="RPC user") group.add_argument("--rpcpassword", dest=SimpleConfig.RPC_PASSWORD.key(), default=argparse.SUPPRESS, help="RPC password") + def add_wallet_option(parser): parser.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path") parser.add_argument("--forgetconfig", action="store_true", dest=SimpleConfig.CONFIG_FORGET_CHANGES.key(), default=False, help="Forget config on exit") + def get_parser(): # create main parser parser = argparse.ArgumentParser( diff --git a/electrum/daemon.py b/electrum/daemon.py index f399d01fe..b98592d9f 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -30,26 +30,24 @@ import time import traceback import sys import threading -from typing import Dict, Optional, Tuple, Iterable, Callable, Union, Sequence, Mapping, TYPE_CHECKING +from typing import Dict, Optional, Tuple, Callable, Union, Sequence, Mapping, TYPE_CHECKING from base64 import b64decode, b64encode -from collections import defaultdict import json import socket -from enum import IntEnum import aiohttp from aiohttp import web, client_exceptions -from aiorpcx import timeout_after, TaskTimeout, ignore_after +from aiorpcx import ignore_after from . import util from .network import Network -from .util import (json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare, InvalidPassword) -from .invoices import PR_PAID, PR_EXPIRED -from .util import log_exceptions, ignore_exceptions, randrange, OldTaskGroup, UserFacingException, JsonRPCError -from .util import EventListener, event_listener +from .util import ( + json_decode, to_bytes, to_string, profiler, standardize_path, constant_time_compare, InvalidPassword, + log_exceptions, randrange, OldTaskGroup, UserFacingException, JsonRPCError +) from .wallet import Wallet, Abstract_Wallet from .storage import WalletStorage -from .wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished +from .wallet_db import WalletDB, WalletUnfinished from .commands import known_commands, Commands from .simple_config import SimpleConfig from .exchange_rate import FxThread @@ -67,9 +65,11 @@ _logger = get_logger(__name__) class DaemonNotRunning(Exception): pass + def get_rpcsock_defaultpath(config: SimpleConfig): return os.path.join(config.path, 'daemon_rpc_socket') + def get_rpcsock_default_type(config: SimpleConfig): if config.RPC_PORT: return 'tcp' @@ -80,9 +80,11 @@ def get_rpcsock_default_type(config: SimpleConfig): return 'unix' return 'tcp' + def get_lockfile(config: SimpleConfig): return os.path.join(config.path, 'daemon') + def remove_lockfile(lockfile): os.unlink(lockfile) @@ -107,7 +109,6 @@ def get_file_descriptor(config: SimpleConfig): remove_lockfile(lockfile) - def request(config: SimpleConfig, endpoint, args=(), timeout: Union[float, int] = 60): lockfile = get_lockfile(config) while True: @@ -130,6 +131,7 @@ def request(config: SimpleConfig, endpoint, args=(), timeout: Union[float, int] server_url = 'http://%s:%d' % (host, port) auth = aiohttp.BasicAuth(login=rpc_user, password=rpc_password) loop = util.get_asyncio_loop() + async def request_coroutine( *, socktype=socktype, path=path, auth=auth, server_url=server_url, endpoint=endpoint, ): @@ -142,6 +144,7 @@ def request(config: SimpleConfig, endpoint, args=(), timeout: Union[float, int] async with aiohttp.ClientSession(auth=auth, connector=connector) as session: c = util.JsonRPCClient(session, server_url) return await c.request(endpoint, *args) + try: fut = asyncio.run_coroutine_threadsafe(request_coroutine(), loop) return fut.result(timeout=timeout) @@ -185,12 +188,15 @@ def get_rpc_credentials(config: SimpleConfig) -> Tuple[str, str]: class AuthenticationError(Exception): pass + class AuthenticationInvalidOrMissing(AuthenticationError): pass + class AuthenticationCredentialsInvalid(AuthenticationError): pass + class AuthenticatedServer(Logger): def __init__(self, rpc_user, rpc_password): @@ -362,9 +368,6 @@ class CommandsServer(AuthenticatedServer): return result - - - class Daemon(Logger): network: Optional[Network] = None diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py index 1e3468215..53cd67f16 100644 --- a/electrum/gui/qt/__init__.py +++ b/electrum/gui/qt/__init__.py @@ -63,13 +63,12 @@ if sys.platform == "linux" and os.environ.get("APPIMAGE"): from electrum.i18n import _, set_language from electrum.plugin import run_hook from electrum.util import (UserCancelled, profiler, send_exception_to_crash_reporter, - WalletFileException, BitcoinException, get_new_wallet_name, InvalidPassword) + WalletFileException, get_new_wallet_name, InvalidPassword) from electrum.wallet import Wallet, Abstract_Wallet -from electrum.wallet_db import WalletDB, WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished +from electrum.wallet_db import WalletRequiresSplit, WalletRequiresUpgrade, WalletUnfinished from electrum.logging import Logger from electrum.gui import BaseElectrumGui from electrum.simple_config import SimpleConfig -from electrum.storage import WalletStorage from electrum.wizard import WizardViewState from electrum.keystore import load_keystore from electrum.bip32 import is_xprv diff --git a/electrum/gui/qt/address_dialog.py b/electrum/gui/qt/address_dialog.py index 06a22ead2..e06c65132 100644 --- a/electrum/gui/qt/address_dialog.py +++ b/electrum/gui/qt/address_dialog.py @@ -29,7 +29,7 @@ from PyQt6.QtWidgets import QVBoxLayout, QLabel from electrum.i18n import _ -from .util import WindowModalDialog, ButtonsLineEdit, ShowQRLineEdit, ColorScheme, Buttons, CloseButton +from .util import WindowModalDialog, ButtonsLineEdit, ShowQRLineEdit, Buttons, CloseButton from .history_list import HistoryList, HistoryModel from .qrtextedit import ShowQRTextEdit diff --git a/electrum/gui/qt/address_list.py b/electrum/gui/qt/address_list.py index 64a679314..b14abc185 100644 --- a/electrum/gui/qt/address_list.py +++ b/electrum/gui/qt/address_list.py @@ -29,7 +29,7 @@ from typing import TYPE_CHECKING from PyQt6.QtCore import Qt, QPersistentModelIndex, QModelIndex from PyQt6.QtGui import QStandardItemModel, QStandardItem, QFont -from PyQt6.QtWidgets import QAbstractItemView, QComboBox, QLabel, QMenu +from PyQt6.QtWidgets import QAbstractItemView, QComboBox, QMenu from electrum.i18n import _ from electrum.util import block_explorer_URL, profiler diff --git a/electrum/gui/qt/amountedit.py b/electrum/gui/qt/amountedit.py index b738ddd80..7f12707b1 100644 --- a/electrum/gui/qt/amountedit.py +++ b/electrum/gui/qt/amountedit.py @@ -4,7 +4,7 @@ from decimal import Decimal from typing import Union from PyQt6.QtCore import pyqtSignal, Qt, QSize -from PyQt6.QtGui import QPalette, QPainter +from PyQt6.QtGui import QPainter from PyQt6.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame, QSizePolicy) from .util import char_width_in_lineedit, ColorScheme @@ -27,6 +27,7 @@ class FreezableLineEdit(QLineEdit): def isFrozen(self): return self.isReadOnly() + class SizedFreezableLineEdit(FreezableLineEdit): def __init__(self, *, width: int, parent=None): diff --git a/electrum/gui/qt/balance_dialog.py b/electrum/gui/qt/balance_dialog.py index a1d15aaf0..504e0a250 100644 --- a/electrum/gui/qt/balance_dialog.py +++ b/electrum/gui/qt/balance_dialog.py @@ -25,12 +25,9 @@ from typing import TYPE_CHECKING -from PyQt6.QtWidgets import (QVBoxLayout, QCheckBox, QHBoxLayout, QLineEdit, - QLabel, QCompleter, QDialog, QStyledItemDelegate, - QScrollArea, QWidget, QPushButton, QGridLayout, QToolButton) -from PyQt6.QtCore import QRect, QEventLoop, Qt, pyqtSignal -from PyQt6.QtGui import QPalette, QPen, QPainter, QPixmap - +from PyQt6.QtWidgets import QVBoxLayout, QLabel, QWidget, QGridLayout, QToolButton +from PyQt6.QtCore import QRect, Qt +from PyQt6.QtGui import QPen, QPainter from electrum.i18n import _ @@ -52,6 +49,7 @@ COLOR_FROZEN = ColorScheme.BLUE.as_color(True) COLOR_LIGHTNING = Qt.GlobalColor.yellow COLOR_FROZEN_LIGHTNING = Qt.GlobalColor.cyan + class PieChartObject: def paintEvent(self, event): @@ -78,6 +76,7 @@ class PieChartObject: alpha += delta qp.end() + class PieChartWidget(QWidget, PieChartObject): def __init__(self, size, l): diff --git a/electrum/gui/qt/bip39_recovery_dialog.py b/electrum/gui/qt/bip39_recovery_dialog.py index d291d851b..7a25f2ebc 100644 --- a/electrum/gui/qt/bip39_recovery_dialog.py +++ b/electrum/gui/qt/bip39_recovery_dialog.py @@ -6,7 +6,7 @@ import asyncio import concurrent.futures from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import QWidget, QVBoxLayout, QGridLayout, QLabel, QListWidget, QListWidgetItem +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QListWidget, QListWidgetItem from electrum.i18n import _ from electrum.network import Network @@ -14,7 +14,7 @@ from electrum.bip39_recovery import account_discovery from electrum.logging import get_logger from electrum.util import get_asyncio_loop, UserFacingException -from .util import WindowModalDialog, MessageBoxMixin, TaskThread, Buttons, CancelButton, OkButton +from .util import WindowModalDialog, TaskThread, Buttons, CancelButton, OkButton _logger = get_logger(__name__) diff --git a/electrum/gui/qt/channel_details.py b/electrum/gui/qt/channel_details.py index 3385b1a2f..adb428ffb 100644 --- a/electrum/gui/qt/channel_details.py +++ b/electrum/gui/qt/channel_details.py @@ -20,16 +20,19 @@ from .util import QtEventListener, qt_event_listener, VLine if TYPE_CHECKING: from .main_window import ElectrumWindow + class HTLCItem(QtGui.QStandardItem): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setEditable(False) + class SelectableLabel(QtWidgets.QLabel): def __init__(self, text=''): super().__init__(text) self.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) + class LinkedLabel(QtWidgets.QLabel): def __init__(self, text, on_clicked): super().__init__(text) diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py index 1be6edd5b..5f6a22390 100644 --- a/electrum/gui/qt/channels_list.py +++ b/electrum/gui/qt/channels_list.py @@ -6,22 +6,17 @@ from abc import abstractmethod, ABC from PyQt6 import QtCore, QtGui from PyQt6.QtCore import Qt, QRect, QSize -from PyQt6.QtWidgets import (QMenu, QHBoxLayout, QLabel, QVBoxLayout, QGridLayout, QLineEdit, - QPushButton, QAbstractItemView, QComboBox, QCheckBox, - QToolTip) +from PyQt6.QtWidgets import QMenu, QLabel, QVBoxLayout, QGridLayout, QAbstractItemView, QCheckBox, QToolTip from PyQt6.QtGui import QFont, QStandardItem, QBrush, QPainter, QIcon, QHelpEvent -from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates from electrum.i18n import _ -from electrum.lnchannel import AbstractChannel, PeerState, ChannelBackup, Channel, ChannelState, ChanCloseOption +from electrum.lnchannel import AbstractChannel, ChannelBackup, Channel, ChanCloseOption from electrum.wallet import Abstract_Wallet -from electrum.lnutil import LOCAL, REMOTE, format_short_channel_id +from electrum.lnutil import LOCAL, REMOTE from electrum.lnworker import LNWallet from electrum.gui import messages -from .util import (WindowModalDialog, Buttons, OkButton, CancelButton, - EnterButton, WaitingDialog, MONOSPACE_FONT, ColorScheme) -from .amountedit import BTCAmountEdit, FreezableLineEdit +from .util import WindowModalDialog, Buttons, OkButton, EnterButton, WaitingDialog, MONOSPACE_FONT, ColorScheme from .util import read_QIcon, font_height from .my_treeview import MyTreeView @@ -132,15 +127,19 @@ class ChannelsList(MyTreeView): return coro = self.lnworker.close_channel(channel_id) on_success = self.on_channel_closed + def task(): return self.network.run_from_another_thread(coro) + WaitingDialog(self, _('Please wait...'), task, on_success, self.on_failure) def force_close(self, channel_id): self.save_backup = True backup_cb = QCheckBox('Create a backup now', checked=True) + def on_checked(_x): self.save_backup = backup_cb.isChecked() + backup_cb.stateChanged.connect(on_checked) chan = self.lnworker.channels[channel_id] to_self_delay = chan.config[REMOTE].to_self_delay @@ -155,9 +154,11 @@ class ChannelsList(MyTreeView): if self.save_backup: if not self.main_window.backup_wallet(): return + def task(): coro = self.lnworker.force_close_channel(channel_id) return self.network.run_from_another_thread(coro) + WaitingDialog(self, _('Please wait...'), task, self.on_channel_closed, self.on_failure) def remove_channel(self, channel_id): @@ -185,11 +186,14 @@ class ChannelsList(MyTreeView): msg += '\n\n' + messages.MSG_REQUEST_FORCE_CLOSE if not self.main_window.question(msg): return + def task(): coro = self.lnworker.request_force_close(channel_id) return self.network.run_from_another_thread(coro) + def on_done(b): self.main_window.show_message(_('Request scheduled')) + WaitingDialog(self, _('Please wait...'), task, on_done, self.on_failure) def set_frozen(self, chan, *, for_sending, value): diff --git a/electrum/gui/qt/completion_text_edit.py b/electrum/gui/qt/completion_text_edit.py index 230c5f18f..74ab058cf 100644 --- a/electrum/gui/qt/completion_text_edit.py +++ b/electrum/gui/qt/completion_text_edit.py @@ -116,6 +116,7 @@ class CompletionTextEdit(ButtonsTextEdit): return True return False + if __name__ == "__main__": app = QApplication([]) completer = QCompleter(["alabama", "arkansas", "avocado", "breakfast", "sausage"]) diff --git a/electrum/gui/qt/confirm_tx_dialog.py b/electrum/gui/qt/confirm_tx_dialog.py index fdd2c35b5..6811a3bd2 100644 --- a/electrum/gui/qt/confirm_tx_dialog.py +++ b/electrum/gui/qt/confirm_tx_dialog.py @@ -30,7 +30,7 @@ from typing import TYPE_CHECKING, Optional, Union, Callable from PyQt6.QtCore import Qt from PyQt6.QtGui import QIcon -from PyQt6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QGridLayout, QPushButton, QLineEdit, QToolButton, QMenu +from PyQt6.QtWidgets import QHBoxLayout, QVBoxLayout, QLabel, QGridLayout, QPushButton, QToolButton, QMenu from electrum.i18n import _ from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates @@ -42,9 +42,7 @@ from electrum.simple_config import SimpleConfig from electrum.bitcoin import DummyAddress from .util import (WindowModalDialog, ColorScheme, HelpLabel, Buttons, CancelButton, - PasswordLineEdit, WWLabel, read_QIcon) - -from .fee_slider import FeeSlider, FeeComboBox + WWLabel, read_QIcon) if TYPE_CHECKING: from electrum.simple_config import ConfigVarWithConfig @@ -113,7 +111,6 @@ class TxEditor(WindowModalDialog): self.main_window.gui_object.timer.timeout.connect(self.timer_actions) - def timer_actions(self): if self.needs_update: self.update() @@ -379,18 +376,21 @@ class TxEditor(WindowModalDialog): def create_top_bar(self, text): self.pref_menu = QMenu() self.pref_menu.setToolTipsVisible(True) + def add_pref_action(b, action, text, tooltip): m = self.pref_menu.addAction(text, action) m.setCheckable(True) m.setChecked(b) m.setToolTip(tooltip) return m + def add_cv_action(configvar: 'ConfigVarWithConfig', action: Callable[[], None]): b = configvar.get() short_desc = configvar.get_short_desc() assert short_desc is not None, f"short_desc missing for {configvar}" tooltip = configvar.get_long_desc() or "" return add_pref_action(b, action, short_desc, tooltip) + add_cv_action(self.config.cv.GUI_QT_TX_EDITOR_SHOW_IO, self.toggle_io_visibility) add_cv_action(self.config.cv.GUI_QT_TX_EDITOR_SHOW_FEE_DETAILS, self.toggle_fee_details) add_cv_action(self.config.cv.GUI_QT_TX_EDITOR_SHOW_LOCKTIME, self.toggle_locktime) @@ -607,7 +607,7 @@ class TxEditor(WindowModalDialog): class ConfirmTxDialog(TxEditor): - help_text = ''#_('Set the mining fee of your transaction') + help_text = '' #_('Set the mining fee of your transaction') def __init__(self, *, window: 'ElectrumWindow', make_tx, output_value: Union[int, str], allow_preview=True): diff --git a/electrum/gui/qt/console.py b/electrum/gui/qt/console.py index 0cd87b9b3..775b1bfd1 100644 --- a/electrum/gui/qt/console.py +++ b/electrum/gui/qt/console.py @@ -6,10 +6,8 @@ import os import re import traceback -from PyQt6 import QtCore +from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6.QtCore import Qt -from PyQt6 import QtGui -from PyQt6 import QtWidgets from electrum import util from electrum.i18n import _ @@ -230,7 +228,7 @@ class Console(QtWidgets.QPlainTextEdit): def exec_command(self, command): tmp_stdout = sys.stdout - class stdoutProxy(): + class StdoutProxy: def __init__(self, write_func): self.write_func = write_func self.skip = False @@ -245,12 +243,12 @@ class Console(QtWidgets.QPlainTextEdit): QtCore.QCoreApplication.processEvents() self.skip = not self.skip - if type(self.namespace.get(command)) == type(lambda:None): + if type(self.namespace.get(command)) == type(lambda: None): self.appendPlainText("'{}' is a function. Type '{}()' to use it in the Python console." .format(command, command)) return - sys.stdout = stdoutProxy(self.appendPlainText) + sys.stdout = StdoutProxy(self.appendPlainText) try: try: # eval is generally considered bad practice. use it wisely! diff --git a/electrum/gui/qt/custom_model.py b/electrum/gui/qt/custom_model.py index 46e665a5f..099e041b3 100644 --- a/electrum/gui/qt/custom_model.py +++ b/electrum/gui/qt/custom_model.py @@ -1,7 +1,7 @@ # loosely based on # http://trevorius.com/scrapbook/uncategorized/pyqt-custom-abstractitemmodel/ -from PyQt6 import QtCore, QtWidgets +from PyQt6 import QtCore class CustomNode: @@ -39,7 +39,6 @@ class CustomNode: self._children.append(child) - class CustomModel(QtCore.QAbstractItemModel): def __init__(self, parent, columncount): diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py index 090498335..e730d9f9c 100644 --- a/electrum/gui/qt/exception_window.py +++ b/electrum/gui/qt/exception_window.py @@ -112,6 +112,7 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger): msg=text, rich_text=True) self.close() + def on_failure(exc_info): e = exc_info[1] self.logger.error('There was a problem with the automatic reporting', exc_info=exc_info) diff --git a/electrum/gui/qt/fee_slider.py b/electrum/gui/qt/fee_slider.py index 4fb2aa8e0..eabedb9be 100644 --- a/electrum/gui/qt/fee_slider.py +++ b/electrum/gui/qt/fee_slider.py @@ -6,6 +6,7 @@ from PyQt6.QtWidgets import QSlider, QToolTip, QComboBox from electrum.i18n import _ + class FeeComboBox(QComboBox): def __init__(self, fee_slider): diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py index 2fd78a8cc..0fb7b6c59 100644 --- a/electrum/gui/qt/history_list.py +++ b/electrum/gui/qt/history_list.py @@ -24,7 +24,6 @@ # SOFTWARE. import os -import sys import time import datetime from datetime import date @@ -34,18 +33,17 @@ import enum from decimal import Decimal from PyQt6.QtGui import QFont, QBrush, QColor -from PyQt6.QtCore import (Qt, QPersistentModelIndex, QModelIndex, QAbstractItemModel, +from PyQt6.QtCore import (Qt, QPersistentModelIndex, QModelIndex, QSortFilterProxyModel, QVariant, QItemSelectionModel, QDate, QPoint) -from PyQt6.QtWidgets import (QMenu, QHeaderView, QLabel, QMessageBox, - QPushButton, QComboBox, QVBoxLayout, QCalendarWidget, +from PyQt6.QtWidgets import (QMenu, QHeaderView, QLabel, QPushButton, QComboBox, QVBoxLayout, QCalendarWidget, QGridLayout) from electrum.gui import messages -from electrum.address_synchronizer import TX_HEIGHT_LOCAL, TX_HEIGHT_FUTURE +from electrum.address_synchronizer import TX_HEIGHT_LOCAL from electrum.i18n import _ from electrum.util import (block_explorer_URL, profiler, TxMinedInfo, OrderedDictWithIndex, timestamp_to_datetime, - Satoshis, Fiat, format_time) + Satoshis, format_time) from electrum.logging import get_logger, Logger from electrum.simple_config import SimpleConfig @@ -95,6 +93,7 @@ class HistorySortModel(QSortFilterProxyModel): except Exception: return False + def get_item_key(tx_item): return tx_item.get('txid') or tx_item['payment_hash'] @@ -350,6 +349,7 @@ class HistoryModel(CustomModel, Logger): def set_visibility_of_columns(self): def set_visible(col: int, b: bool): self.view.showColumn(col) if b else self.view.hideColumn(col) + # txid set_visible(HistoryColumns.TXID, False) set_visible(HistoryColumns.SHORT_ID, False) @@ -406,9 +406,9 @@ class HistoryModel(CustomModel, Logger): fiat_acq_title = 'n/a fiat acquisition price' fiat_cg_title = 'n/a fiat capital gains' if self.should_show_fiat(): - fiat_title = '%s '%fx.ccy + _('Value') - fiat_acq_title = '%s '%fx.ccy + _('Acquisition price') - fiat_cg_title = '%s '%fx.ccy + _('Capital Gains') + fiat_title = '%s ' % fx.ccy + _('Value') + fiat_acq_title = '%s ' % fx.ccy + _('Acquisition price') + fiat_cg_title = '%s ' % fx.ccy + _('Capital Gains') return { HistoryColumns.STATUS: _('Date'), HistoryColumns.DESCRIPTION: _('Description'), @@ -578,8 +578,10 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): d.setMinimumSize(600, 150) d.date = None vbox = QVBoxLayout() + def on_date(date): d.date = date + cal = QCalendarWidget() cal.setGridVisible(True) cal.clicked[QDate].connect(on_date) @@ -795,8 +797,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): if num_child_txs > 0: question = (_("Are you sure you want to remove this transaction and {} child transactions?") .format(num_child_txs)) - if not self.main_window.question(msg=question, - title=_("Please confirm")): + if not self.main_window.question(msg=question, title=_("Please confirm")): return self.wallet.adb.remove_transaction(tx_hash) self.wallet.save_db() diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py index 569ac1be9..1acc866c6 100644 --- a/electrum/gui/qt/invoice_list.py +++ b/electrum/gui/qt/invoice_list.py @@ -26,14 +26,14 @@ import enum from typing import Sequence, TYPE_CHECKING -from PyQt6.QtCore import Qt, QItemSelectionModel +from PyQt6.QtCore import Qt from PyQt6.QtGui import QStandardItemModel, QStandardItem from PyQt6.QtWidgets import QAbstractItemView from PyQt6.QtWidgets import QMenu, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QHeaderView from electrum.i18n import _ from electrum.util import format_time -from electrum.invoices import Invoice, PR_UNPAID, PR_PAID, PR_INFLIGHT, PR_FAILED +from electrum.invoices import PR_UNPAID, PR_INFLIGHT, PR_FAILED from electrum.lnutil import HtlcLog from .util import read_QIcon, pr_icons @@ -43,7 +43,6 @@ from .util import WindowModalDialog from .my_treeview import MyTreeView, MySortModel if TYPE_CHECKING: - from .main_window import ElectrumWindow from .send_tab import SendTab @@ -157,7 +156,7 @@ class InvoiceList(MyTreeView): def create_menu(self, position): wallet = self.wallet items = self.selected_in_column(0) - if len(items)>1: + if len(items) > 1: keys = [item.data(ROLE_REQUEST_ID) for item in items] invoices = [wallet.get_invoice(key) for key in keys] can_batch_pay = all([not i.is_lightning() and wallet.get_invoice_status(i) == PR_UNPAID for i in invoices]) diff --git a/electrum/gui/qt/lightning_tx_dialog.py b/electrum/gui/qt/lightning_tx_dialog.py index 323494f1f..8c61a69e6 100644 --- a/electrum/gui/qt/lightning_tx_dialog.py +++ b/electrum/gui/qt/lightning_tx_dialog.py @@ -27,14 +27,12 @@ from typing import TYPE_CHECKING from decimal import Decimal import datetime -from PyQt6.QtGui import QFont -from PyQt6.QtWidgets import QVBoxLayout, QLabel, QGridLayout +from PyQt6.QtWidgets import QVBoxLayout, QLabel from electrum.i18n import _ from electrum.lnworker import PaymentDirection -from electrum.invoices import Invoice -from .util import WindowModalDialog, ShowQRLineEdit, ColorScheme, Buttons, CloseButton, font_height, ButtonsLineEdit +from .util import WindowModalDialog, ShowQRLineEdit, Buttons, CloseButton, font_height, ButtonsLineEdit from .qrtextedit import ShowQRTextEdit if TYPE_CHECKING: diff --git a/electrum/gui/qt/locktimeedit.py b/electrum/gui/qt/locktimeedit.py index 9d72dfbd8..f30a524c4 100644 --- a/electrum/gui/qt/locktimeedit.py +++ b/electrum/gui/qt/locktimeedit.py @@ -7,7 +7,7 @@ from datetime import datetime from typing import Optional, Any from PyQt6.QtCore import Qt, QDateTime, pyqtSignal -from PyQt6.QtGui import QPalette, QPainter +from PyQt6.QtGui import QPainter from PyQt6.QtWidgets import (QWidget, QLineEdit, QStyle, QStyleOptionFrame, QComboBox, QHBoxLayout, QDateTimeEdit) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index aea6eaaa9..a766e5d21 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -39,12 +39,9 @@ import concurrent.futures from PyQt6.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont, QFontMetrics, QAction, QShortcut from PyQt6.QtCore import Qt, QRect, QStringListModel, QSize, pyqtSignal -from PyQt6.QtWidgets import (QMessageBox, QSystemTrayIcon, QTabWidget, - QMenuBar, QFileDialog, QCheckBox, QLabel, - QVBoxLayout, QGridLayout, QLineEdit, - QHBoxLayout, QPushButton, QScrollArea, QTextEdit, - QMainWindow, QInputDialog, - QWidget, QSizePolicy, QStatusBar, QToolTip, +from PyQt6.QtWidgets import (QMessageBox, QTabWidget, QMenuBar, QFileDialog, QCheckBox, QLabel, + QVBoxLayout, QGridLayout, QLineEdit, QHBoxLayout, QPushButton, QScrollArea, QTextEdit, + QMainWindow, QInputDialog, QWidget, QSizePolicy, QStatusBar, QToolTip, QMenu, QToolButton) import electrum_ecc as ecc @@ -54,7 +51,7 @@ from electrum.gui import messages from electrum import (keystore, constants, util, bitcoin, commands, paymentrequest, lnutil) from electrum.bitcoin import COIN, is_address, DummyAddress -from electrum.plugin import run_hook, BasePlugin +from electrum.plugin import run_hook from electrum.i18n import _ from electrum.util import (format_time, UserCancelled, profiler, bfh, InvalidPassword, UserFacingException, get_new_wallet_name, send_exception_to_crash_reporter, @@ -68,13 +65,12 @@ from electrum.wallet import (Multisig_Wallet, Abstract_Wallet, sweep_preparations, InternalAddressCorruption, CannotCPFP) from electrum.version import ELECTRUM_VERSION -from electrum.network import Network, UntrustedServerReturnedError, NetworkException +from electrum.network import Network, UntrustedServerReturnedError from electrum.exchange_rate import FxThread from electrum.simple_config import SimpleConfig from electrum.logging import Logger from electrum.lntransport import extract_nodeid, ConnStringFormatError from electrum.lnaddr import lndecode -from electrum.submarine_swaps import SwapServerError from .rate_limiter import rate_limited from .exception_window import Exception_Hook @@ -86,14 +82,11 @@ from .fee_slider import FeeSlider, FeeComboBox from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialog, WindowModalDialog, HelpLabel, Buttons, OkButton, InfoButton, WWLabel, TaskThread, CancelButton, - CloseButton, HelpButton, MessageBoxMixin, EnterButton, - import_meta_gui, export_meta_gui, + CloseButton, MessageBoxMixin, EnterButton, import_meta_gui, export_meta_gui, filename_field, address_field, char_width_in_lineedit, webopen, TRANSACTION_FILE_EXTENSION_FILTER_ANY, MONOSPACE_FONT, - getOpenFileName, getSaveFileName, font_height) -from .util import ButtonsLineEdit, ShowQRLineEdit -from .util import QtEventListener, qt_event_listener, event_listener -from .util import scan_qr_from_screenshot + getOpenFileName, getSaveFileName, ShowQRLineEdit, QtEventListener, qt_event_listener, + event_listener, scan_qr_from_screenshot) from .wizard.wallet import WIF_HELP_TEXT from .history_list import HistoryList, HistoryModel from .update_checker import UpdateCheck, UpdateCheckThread @@ -102,10 +95,10 @@ from .confirm_tx_dialog import ConfirmTxDialog from .rbf_dialog import BumpFeeDialog, DSCancelDialog from .qrreader import scan_qrcode from .swap_dialog import SwapDialog, InvalidSwapParameters -from .balance_dialog import BalanceToolButton, COLOR_FROZEN, COLOR_UNMATURED, COLOR_UNCONFIRMED, COLOR_CONFIRMED, COLOR_LIGHTNING, COLOR_FROZEN_LIGHTNING +from .balance_dialog import (BalanceToolButton, COLOR_FROZEN, COLOR_UNMATURED, COLOR_UNCONFIRMED, COLOR_CONFIRMED, + COLOR_LIGHTNING, COLOR_FROZEN_LIGHTNING) if TYPE_CHECKING: - from electrum.simple_config import ConfigVarWithConfig from . import ElectrumGui diff --git a/electrum/gui/qt/my_treeview.py b/electrum/gui/qt/my_treeview.py index 0e998beae..791033778 100644 --- a/electrum/gui/qt/my_treeview.py +++ b/electrum/gui/qt/my_treeview.py @@ -23,36 +23,18 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import asyncio -import contextlib import enum -import os.path -import time -import sys -import platform -import queue -import traceback -import os -import webbrowser from decimal import Decimal -from functools import partial, lru_cache, wraps -from typing import (NamedTuple, Callable, Optional, TYPE_CHECKING, Union, List, Dict, Any, - Sequence, Iterable, Tuple, Type) +from typing import (Optional, TYPE_CHECKING, Union, List, Dict, Any, + Sequence, Iterable, Type) -from PyQt6 import QtWidgets, QtCore -from PyQt6.QtGui import (QFont, QColor, QCursor, QPixmap, QStandardItem, QImage, QStandardItemModel, - QPalette, QIcon, QFontMetrics, QShowEvent, QPainter, QHelpEvent, QMouseEvent, QAction) -from PyQt6.QtCore import (Qt, QPersistentModelIndex, QModelIndex, pyqtSignal, - QCoreApplication, QItemSelectionModel, QThread, - QSortFilterProxyModel, QSize, QLocale, QAbstractItemModel, - QEvent, QRect, QPoint, QObject) -from PyQt6.QtWidgets import (QPushButton, QLabel, QMessageBox, QHBoxLayout, - QAbstractItemView, QVBoxLayout, QLineEdit, - QStyle, QDialog, QGroupBox, QButtonGroup, QRadioButton, - QFileDialog, QWidget, QToolButton, QTreeView, QPlainTextEdit, - QHeaderView, QApplication, QToolTip, QTreeWidget, QStyledItemDelegate, - QMenu, QStyleOptionViewItem, QLayout, QLayoutItem, QAbstractButton, - QGraphicsEffect, QGraphicsScene, QGraphicsPixmapItem, QSizePolicy) +from PyQt6.QtGui import (QStandardItem, QStandardItemModel, + QShowEvent, QPainter, QHelpEvent, QMouseEvent, QAction) +from PyQt6.QtCore import (Qt, QPersistentModelIndex, QModelIndex, QItemSelectionModel, + QSortFilterProxyModel, QSize, QAbstractItemModel, QEvent, QPoint) +from PyQt6.QtWidgets import (QLabel, QHBoxLayout, QAbstractItemView, QLineEdit, + QWidget, QToolButton, QTreeView, QHeaderView, QStyledItemDelegate, + QMenu, QStyleOptionViewItem) from electrum.i18n import _, languages from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, resource_path @@ -126,7 +108,6 @@ def create_toolbar_with_menu(config: 'SimpleConfig', title): return toolbar, menu - class MySortModel(QSortFilterProxyModel): def __init__(self, parent, *, sort_role): super().__init__(parent) @@ -147,16 +128,19 @@ class MySortModel(QSortFilterProxyModel): except Exception: return v1 < v2 + class ElectrumItemDelegate(QStyledItemDelegate): def __init__(self, tv: 'MyTreeView'): super().__init__(tv) self.tv = tv self.opened = None + def on_closeEditor(editor: QLineEdit, hint): self.opened = None self.tv.is_editor_open = False if self.tv._pending_update: self.tv.update() + def on_commitData(editor: QLineEdit): new_text = editor.text() idx = QModelIndex(self.opened) @@ -164,6 +148,7 @@ class ElectrumItemDelegate(QStyledItemDelegate): edit_key = self.tv.get_edit_key_from_coordinate(row, col) assert edit_key is not None, (idx.row(), idx.column()) self.tv.on_edited(idx, edit_key=edit_key, text=new_text) + self.closeEditor.connect(on_closeEditor) self.commitData.connect(on_commitData) @@ -200,6 +185,7 @@ class ElectrumItemDelegate(QStyledItemDelegate): default_size = super().sizeHint(option, idx) return custom_data.sizeHint(default_size) + class MyTreeView(QTreeView): ROLE_CLIPBOARD_DATA = Qt.ItemDataRole.UserRole + 100 diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py index a7609c0f6..8bc3c032c 100644 --- a/electrum/gui/qt/network_dialog.py +++ b/electrum/gui/qt/network_dialog.py @@ -23,10 +23,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import socket -import time from enum import IntEnum -from typing import Tuple, TYPE_CHECKING import threading from PyQt6.QtCore import Qt, pyqtSignal, QThread @@ -36,7 +33,7 @@ from PyQt6.QtWidgets import (QTreeWidget, QTreeWidgetItem, QMenu, QGridLayout, Q from PyQt6.QtGui import QIntValidator from electrum.i18n import _ -from electrum import constants, blockchain, util +from electrum import blockchain from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL from electrum.network import Network from electrum.logging import get_logger @@ -123,17 +120,21 @@ class NodesListWidget(QTreeWidget): def do_set_server(): self.setServer.emit(str(server)) menu.addAction(read_QIcon("chevron-right.png"), _("Use as server"), do_set_server) + def set_bookmark(*, add: bool): self.network.set_server_bookmark(server, add=add) self.update() + if self.network.is_server_bookmarked(server): menu.addAction(read_QIcon("bookmark_remove.png"), _("Remove from bookmarks"), lambda: set_bookmark(add=False)) else: menu.addAction(read_QIcon("bookmark_add.png"), _("Bookmark this server"), lambda: set_bookmark(add=True)) elif item_type == self.ItemType.CHAIN: chain_id = item.data(0, self.CHAIN_ID_ROLE) + def do_follow_chain(): self.followChain.emit(chain_id) + menu.addAction(_("Follow this branch"), do_follow_chain) else: return diff --git a/electrum/gui/qt/new_channel_dialog.py b/electrum/gui/qt/new_channel_dialog.py index a6688d4b7..9622fc755 100644 --- a/electrum/gui/qt/new_channel_dialog.py +++ b/electrum/gui/qt/new_channel_dialog.py @@ -4,16 +4,12 @@ from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComb import electrum_ecc as ecc from electrum.i18n import _ -from electrum.transaction import PartialTxOutput, PartialTransaction from electrum.lnutil import MIN_FUNDING_SAT from electrum.lnworker import hardcoded_trampoline_nodes from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates -from electrum.gui import messages -from . import util from .util import (WindowModalDialog, Buttons, OkButton, CancelButton, - EnterButton, ColorScheme, WWLabel, read_QIcon, IconLabel, - char_width_in_lineedit) + EnterButton, WWLabel, char_width_in_lineedit) from .amountedit import BTCAmountEdit from .my_treeview import create_toolbar_with_menu @@ -21,7 +17,6 @@ if TYPE_CHECKING: from .main_window import ElectrumWindow - class NewChannelDialog(WindowModalDialog): def __init__(self, window: 'ElectrumWindow', amount_sat: Optional[int] = None, min_amount_sat: Optional[int] = None): diff --git a/electrum/gui/qt/password_dialog.py b/electrum/gui/qt/password_dialog.py index 449962c2c..845436343 100644 --- a/electrum/gui/qt/password_dialog.py +++ b/electrum/gui/qt/password_dialog.py @@ -25,17 +25,15 @@ import re import math -from functools import partial from PyQt6.QtCore import Qt from PyQt6.QtGui import QPixmap -from PyQt6.QtWidgets import QLineEdit, QLabel, QGridLayout, QVBoxLayout, QCheckBox +from PyQt6.QtWidgets import QLabel, QGridLayout, QVBoxLayout from electrum.i18n import _ from electrum.plugin import run_hook -from .util import (icon_path, WindowModalDialog, OkButton, CancelButton, Buttons, - PasswordLineEdit) +from .util import icon_path, WindowModalDialog, OkButton, CancelButton, Buttons, PasswordLineEdit def check_password_strength(password): @@ -60,6 +58,7 @@ PW_NEW, PW_CHANGE, PW_PASSPHRASE = range(0, 3) MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\ + _("Leave this field empty if you want to disable encryption.") + class PasswordLayout(object): titles = [_("Enter Password"), _("Change Password"), _("Enter Passphrase")] diff --git a/electrum/gui/qt/paytoedit.py b/electrum/gui/qt/paytoedit.py index a6db8ffba..4de20d8c9 100644 --- a/electrum/gui/qt/paytoedit.py +++ b/electrum/gui/qt/paytoedit.py @@ -27,9 +27,9 @@ from functools import partial from typing import Optional, TYPE_CHECKING from PyQt6.QtCore import Qt, QTimer, QSize -from PyQt6.QtCore import QObject, pyqtSignal +from PyQt6.QtCore import pyqtSignal from PyQt6.QtGui import QFontMetrics, QFont -from PyQt6.QtWidgets import QApplication, QTextEdit, QWidget, QLineEdit, QStackedLayout, QSizePolicy +from PyQt6.QtWidgets import QTextEdit, QWidget, QLineEdit, QStackedLayout from electrum.payment_identifier import PaymentIdentifier from electrum.logging import Logger diff --git a/electrum/gui/qt/plugins_dialog.py b/electrum/gui/qt/plugins_dialog.py index 1179e9e49..ba703aaa0 100644 --- a/electrum/gui/qt/plugins_dialog.py +++ b/electrum/gui/qt/plugins_dialog.py @@ -1,14 +1,12 @@ from typing import TYPE_CHECKING, Optional from functools import partial -from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout, QScrollArea, QCheckBox, QFormLayout +from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QWidget, QScrollArea, QCheckBox, QFormLayout from electrum.i18n import _ -from electrum.gui import messages -from electrum.plugin import run_hook, BasePlugin +from electrum.plugin import run_hook -from . import util -from .util import WindowModalDialog, Buttons, CloseButton, HelpButton, WWLabel, insert_spaces +from .util import WindowModalDialog, Buttons, CloseButton, WWLabel, insert_spaces if TYPE_CHECKING: diff --git a/electrum/gui/qt/qrcodewidget.py b/electrum/gui/qt/qrcodewidget.py index 10321f26f..33e1d8d56 100644 --- a/electrum/gui/qt/qrcodewidget.py +++ b/electrum/gui/qt/qrcodewidget.py @@ -6,10 +6,7 @@ import qrcode.exceptions from PyQt6.QtGui import QColor, QPen import PyQt6.QtGui as QtGui from PyQt6.QtCore import Qt, QRect -from PyQt6.QtWidgets import ( - QApplication, QVBoxLayout, QTextEdit, QHBoxLayout, QPushButton, QWidget, - QFileDialog, -) +from PyQt6.QtWidgets import QApplication, QVBoxLayout, QHBoxLayout, QPushButton, QWidget from electrum.i18n import _ from electrum.simple_config import SimpleConfig @@ -54,7 +51,6 @@ class QRCodeWidget(QWidget): self.update() - def paintEvent(self, e): if not self.data: return diff --git a/electrum/gui/qt/rbf_dialog.py b/electrum/gui/qt/rbf_dialog.py index 5295d7661..7eb96e16e 100644 --- a/electrum/gui/qt/rbf_dialog.py +++ b/electrum/gui/qt/rbf_dialog.py @@ -5,13 +5,9 @@ from typing import TYPE_CHECKING from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import (QCheckBox, QLabel, QVBoxLayout, QGridLayout, QWidget, - QPushButton, QHBoxLayout, QComboBox) +from PyQt6.QtWidgets import QLabel, QGridLayout, QHBoxLayout, QComboBox -from .amountedit import FeerateEdit -from .fee_slider import FeeSlider, FeeComboBox -from .util import (ColorScheme, WindowModalDialog, Buttons, - OkButton, WWLabel, CancelButton) +from .util import ColorScheme from electrum.i18n import _ from electrum.transaction import PartialTransaction @@ -23,6 +19,7 @@ if TYPE_CHECKING: from .confirm_tx_dialog import TxEditor, TxSizeLabel, HelpLabel + class _BaseRBFDialog(TxEditor): def __init__( @@ -96,9 +93,11 @@ class _BaseRBFDialog(TxEditor): if self.is_preview: self.main_window.show_transaction(self.tx) return + def sign_done(success): if success: self.main_window.broadcast_or_show(self.tx) + self.main_window.sign_tx( self.tx, callback=sign_done, diff --git a/electrum/gui/qt/rebalance_dialog.py b/electrum/gui/qt/rebalance_dialog.py index eaf88fde2..8906dcd8e 100644 --- a/electrum/gui/qt/rebalance_dialog.py +++ b/electrum/gui/qt/rebalance_dialog.py @@ -1,6 +1,5 @@ from typing import TYPE_CHECKING -from PyQt6.QtCore import pyqtSignal from PyQt6.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton from electrum.i18n import _ diff --git a/electrum/gui/qt/receive_tab.py b/electrum/gui/qt/receive_tab.py index 8dc198c0b..07b2aa8f1 100644 --- a/electrum/gui/qt/receive_tab.py +++ b/electrum/gui/qt/receive_tab.py @@ -6,10 +6,9 @@ from typing import Optional, TYPE_CHECKING from PyQt6.QtGui import QFont, QCursor, QMouseEvent from PyQt6.QtCore import Qt, QSize -from PyQt6.QtWidgets import (QComboBox, QLabel, QVBoxLayout, QGridLayout, QLineEdit, QTextEdit, +from PyQt6.QtWidgets import (QLabel, QVBoxLayout, QGridLayout, QTextEdit, QHBoxLayout, QPushButton, QWidget, QSizePolicy, QFrame) -from electrum.bitcoin import is_address from electrum.i18n import _ from electrum.util import InvoiceError from electrum.invoices import pr_expiration_values @@ -17,11 +16,9 @@ from electrum.logging import Logger from .amountedit import AmountEdit, BTCAmountEdit, SizedFreezableLineEdit from .qrcodewidget import QRCodeWidget -from .util import read_QIcon, ColorScheme, HelpLabel, WWLabel, MessageBoxMixin, MONOSPACE_FONT -from .util import ButtonsTextEdit, get_iconname_qrcode +from .util import read_QIcon, WWLabel, MessageBoxMixin, MONOSPACE_FONT, get_iconname_qrcode if TYPE_CHECKING: - from . import ElectrumGui from .main_window import ElectrumWindow diff --git a/electrum/gui/qt/request_list.py b/electrum/gui/qt/request_list.py index 52c2290d2..75cb23a86 100644 --- a/electrum/gui/qt/request_list.py +++ b/electrum/gui/qt/request_list.py @@ -33,13 +33,11 @@ from PyQt6.QtCore import Qt, QItemSelectionModel, QModelIndex from electrum.i18n import _ from electrum.util import format_time from electrum.plugin import run_hook -from electrum.invoices import Invoice -from .util import pr_icons, read_QIcon, webopen +from .util import pr_icons, read_QIcon from .my_treeview import MyTreeView, MySortModel if TYPE_CHECKING: - from .main_window import ElectrumWindow from .receive_tab import ReceiveTab @@ -180,8 +178,8 @@ class RequestList(MyTreeView): def create_menu(self, position): items = self.selected_in_column(0) - if len(items)>1: - keys = [item.data(ROLE_KEY) for item in items] + if len(items) > 1: + keys = [item.data(ROLE_KEY) for item in items] menu = QMenu(self) menu.addAction(_("Delete requests"), lambda: self.delete_requests(keys)) menu.exec(self.viewport().mapToGlobal(position)) diff --git a/electrum/gui/qt/seed_dialog.py b/electrum/gui/qt/seed_dialog.py index e7d9a8ea7..632f5bb32 100644 --- a/electrum/gui/qt/seed_dialog.py +++ b/electrum/gui/qt/seed_dialog.py @@ -29,7 +29,7 @@ from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QPixmap from PyQt6.QtWidgets import (QVBoxLayout, QCheckBox, QHBoxLayout, QLineEdit, QLabel, QCompleter, QDialog, QStyledItemDelegate, - QScrollArea, QWidget, QPushButton) + QWidget, QPushButton) from electrum.i18n import _ from electrum.mnemonic import Mnemonic, calc_seed_type, is_any_2fa_seed_type diff --git a/electrum/gui/qt/settings_dialog.py b/electrum/gui/qt/settings_dialog.py index 84cabe20b..fbade2e87 100644 --- a/electrum/gui/qt/settings_dialog.py +++ b/electrum/gui/qt/settings_dialog.py @@ -24,22 +24,19 @@ # SOFTWARE. import ast -from typing import Optional, TYPE_CHECKING +from typing import TYPE_CHECKING from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import (QComboBox, QTabWidget, QDialog, - QSpinBox, QFileDialog, QCheckBox, QLabel, - QVBoxLayout, QGridLayout, QLineEdit, - QPushButton, QWidget, QHBoxLayout, QSlider) +from PyQt6.QtWidgets import (QComboBox, QTabWidget, QDialog, QSpinBox, QCheckBox, QLabel, + QVBoxLayout, QGridLayout, QLineEdit, QWidget, QHBoxLayout, QSlider) from electrum.i18n import _, languages -from electrum import util, paymentrequest +from electrum import util from electrum.util import base_units_list, event_listener from electrum.gui import messages -from .util import (ColorScheme, WindowModalDialog, HelpLabel, Buttons, - CloseButton, QtEventListener) +from .util import ColorScheme, HelpLabel, Buttons, CloseButton, QtEventListener if TYPE_CHECKING: @@ -88,6 +85,7 @@ class SettingsDialog(QDialog, QtEventListener): lang_combo.setCurrentIndex(index) if not self.config.cv.LOCALIZATION_LANGUAGE.is_modifiable(): for w in [lang_combo, lang_label]: w.setEnabled(False) + def on_lang(x): lang_request = list(languages.keys())[lang_combo.currentIndex()] if lang_request != self.config.LOCALIZATION_LANGUAGE: @@ -102,6 +100,7 @@ class SettingsDialog(QDialog, QtEventListener): nz.setValue(self.config.num_zeros) if not self.config.cv.BTC_AMOUNTS_FORCE_NZEROS_AFTER_DECIMAL_POINT.is_modifiable(): for w in [nz, nz_label]: w.setEnabled(False) + def on_nz(): value = nz.value() if self.config.num_zeros != value: @@ -114,6 +113,7 @@ class SettingsDialog(QDialog, QtEventListener): # lightning trampoline_cb = checkbox_from_configvar(self.config.cv.LIGHTNING_USE_GOSSIP) trampoline_cb.setChecked(not self.config.LIGHTNING_USE_GOSSIP) + def on_trampoline_checked(_x): use_trampoline = trampoline_cb.isChecked() if not use_trampoline: @@ -139,12 +139,14 @@ class SettingsDialog(QDialog, QtEventListener): legacy_add_trampoline_cb = checkbox_from_configvar(self.config.cv.LIGHTNING_LEGACY_ADD_TRAMPOLINE) legacy_add_trampoline_cb.setChecked(self.config.LIGHTNING_LEGACY_ADD_TRAMPOLINE) legacy_add_trampoline_cb.setEnabled(trampoline_cb.isChecked()) + def on_legacy_add_trampoline_checked(_x): self.config.LIGHTNING_LEGACY_ADD_TRAMPOLINE = legacy_add_trampoline_cb.isChecked() legacy_add_trampoline_cb.stateChanged.connect(on_legacy_add_trampoline_checked) remote_wt_cb = checkbox_from_configvar(self.config.cv.WATCHTOWER_CLIENT_ENABLED) remote_wt_cb.setChecked(self.config.WATCHTOWER_CLIENT_ENABLED) + def on_remote_wt_checked(_x): self.config.WATCHTOWER_CLIENT_ENABLED = remote_wt_cb.isChecked() self.watchtower_url_e.setEnabled(remote_wt_cb.isChecked()) @@ -152,6 +154,7 @@ class SettingsDialog(QDialog, QtEventListener): watchtower_url = self.config.WATCHTOWER_CLIENT_URL self.watchtower_url_e = QLineEdit(watchtower_url) self.watchtower_url_e.setEnabled(self.config.WATCHTOWER_CLIENT_ENABLED) + def on_wt_url(): url = self.watchtower_url_e.text() or None self.config.WATCHTOWER_CLIENT_URL = url @@ -159,16 +162,20 @@ class SettingsDialog(QDialog, QtEventListener): lnfee_hlabel = HelpLabel.from_configvar(self.config.cv.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS) lnfee_map = [500, 1_000, 3_000, 5_000, 10_000, 20_000, 30_000, 50_000] + def lnfee_update_vlabel(fee_val: int): lnfee_vlabel.setText(_("{}% of payment").format(f"{fee_val / 10 ** 4:.2f}")) + def lnfee_slider_moved(): pos = lnfee_slider.sliderPosition() fee_val = lnfee_map[pos] lnfee_update_vlabel(fee_val) + def lnfee_slider_released(): pos = lnfee_slider.sliderPosition() fee_val = lnfee_map[pos] self.config.LIGHTNING_PAYMENT_FEE_MAX_MILLIONTHS = fee_val + lnfee_slider = QSlider(Qt.Orientation.Horizontal) lnfee_slider.setRange(0, len(lnfee_map)-1) lnfee_slider.setTracking(True) @@ -197,18 +204,21 @@ class SettingsDialog(QDialog, QtEventListener): nostr_relays_label = HelpLabel.from_configvar(self.config.cv.NOSTR_RELAYS) nostr_relays = self.config.NOSTR_RELAYS self.nostr_relays_e = QLineEdit(nostr_relays) + def on_nostr_edit(): self.config.NOSTR_RELAYS = str(self.nostr_relays_e.text()) self.nostr_relays_e.editingFinished.connect(on_nostr_edit) msat_cb = checkbox_from_configvar(self.config.cv.BTC_AMOUNTS_PREC_POST_SAT) msat_cb.setChecked(self.config.BTC_AMOUNTS_PREC_POST_SAT > 0) + def on_msat_checked(_x): prec = 3 if msat_cb.isChecked() else 0 if self.config.amt_precision_post_satoshi != prec: self.config.amt_precision_post_satoshi = prec self.config.BTC_AMOUNTS_PREC_POST_SAT = prec self.app.refresh_tabs_signal.emit() + msat_cb.stateChanged.connect(on_msat_checked) # units @@ -220,6 +230,7 @@ class SettingsDialog(QDialog, QtEventListener): unit_combo = QComboBox() unit_combo.addItems(units) unit_combo.setCurrentIndex(units.index(self.config.get_base_unit())) + def on_unit(x, nz): unit_result = units[unit_combo.currentIndex()] if self.config.get_base_unit() == unit_result: @@ -233,6 +244,7 @@ class SettingsDialog(QDialog, QtEventListener): thousandsep_cb = checkbox_from_configvar(self.config.cv.BTC_AMOUNTS_ADD_THOUSANDS_SEP) thousandsep_cb.setChecked(self.config.BTC_AMOUNTS_ADD_THOUSANDS_SEP) + def on_set_thousandsep(_x): checked = thousandsep_cb.isChecked() if self.config.amt_add_thousands_sep != checked: @@ -250,6 +262,7 @@ class SettingsDialog(QDialog, QtEventListener): qr_combo.addItem(cam_desc, cam_path) index = qr_combo.findData(self.config.VIDEO_DEVICE_PATH) qr_combo.setCurrentIndex(index) + def on_video_device(x): self.config.VIDEO_DEVICE_PATH = qr_combo.itemData(x) qr_combo.currentIndexChanged.connect(on_video_device) @@ -260,6 +273,7 @@ class SettingsDialog(QDialog, QtEventListener): index = colortheme_combo.findData(self.config.GUI_QT_COLOR_THEME) colortheme_combo.setCurrentIndex(index) colortheme_label = QLabel(self.config.cv.GUI_QT_COLOR_THEME.get_short_desc() + ':') + def on_colortheme(x): self.config.GUI_QT_COLOR_THEME = colortheme_combo.itemData(x) self.need_restart = True @@ -267,12 +281,14 @@ class SettingsDialog(QDialog, QtEventListener): updatecheck_cb = checkbox_from_configvar(self.config.cv.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS) updatecheck_cb.setChecked(self.config.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS) + def on_set_updatecheck(_x): self.config.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS = updatecheck_cb.isChecked() updatecheck_cb.stateChanged.connect(on_set_updatecheck) filelogging_cb = checkbox_from_configvar(self.config.cv.WRITE_LOGS_TO_DISK) filelogging_cb.setChecked(self.config.WRITE_LOGS_TO_DISK) + def on_set_filelogging(_x): self.config.WRITE_LOGS_TO_DISK = filelogging_cb.isChecked() self.need_restart = True @@ -289,9 +305,11 @@ class SettingsDialog(QDialog, QtEventListener): block_ex_combo.addItems(block_explorers) block_ex_combo.setCurrentIndex( block_ex_combo.findText(util.block_explorer(self.config) or BLOCK_EX_CUSTOM_ITEM)) + def showhide_block_ex_custom_e(): block_ex_custom_e.setVisible(block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM) showhide_block_ex_custom_e() + def on_be_combo(x): if block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM: on_be_edit() @@ -300,7 +318,9 @@ class SettingsDialog(QDialog, QtEventListener): self.config.BLOCK_EXPLORER_CUSTOM = None self.config.BLOCK_EXPLORER = be_result showhide_block_ex_custom_e() + block_ex_combo.currentIndexChanged.connect(on_be_combo) + def on_be_edit(): val = block_ex_custom_e.text() try: @@ -308,6 +328,7 @@ class SettingsDialog(QDialog, QtEventListener): except Exception: pass self.config.BLOCK_EXPLORER_CUSTOM = val + block_ex_custom_e.editingFinished.connect(on_be_edit) block_ex_hbox = QHBoxLayout() block_ex_hbox.setContentsMargins(0, 0, 0, 0) diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py index 95edb51ac..c33e82be1 100644 --- a/electrum/gui/qt/transaction_dialog.py +++ b/electrum/gui/qt/transaction_dialog.py @@ -24,39 +24,33 @@ # SOFTWARE. import asyncio -import sys import concurrent.futures import copy import datetime -import traceback import time -from typing import TYPE_CHECKING, Callable, Optional, List, Union, Tuple, Mapping +from typing import TYPE_CHECKING, Optional, List, Union, Mapping from functools import partial from decimal import Decimal from PyQt6.QtCore import QSize, Qt, QUrl, QPoint, pyqtSignal from PyQt6.QtGui import QTextCharFormat, QBrush, QFont, QPixmap, QTextCursor, QAction -from PyQt6.QtWidgets import (QDialog, QLabel, QPushButton, QHBoxLayout, QVBoxLayout, QWidget, QGridLayout, - QTextEdit, QFrame, QToolButton, QMenu, QCheckBox, QTextBrowser, QToolTip, - QApplication, QSizePolicy) +from PyQt6.QtWidgets import (QDialog, QLabel, QPushButton, QHBoxLayout, QVBoxLayout, QWidget, + QToolButton, QMenu, QTextBrowser, + QSizePolicy) import qrcode from qrcode import exceptions -from electrum.simple_config import SimpleConfig -from electrum.util import quantize_feerate from electrum import bitcoin -from electrum.bitcoin import base_encode, NLOCKTIME_BLOCKHEIGHT_MAX, DummyAddress +from electrum.bitcoin import NLOCKTIME_BLOCKHEIGHT_MAX, DummyAddress from electrum.i18n import _ from electrum.plugin import run_hook -from electrum import simple_config from electrum.transaction import SerializationError, Transaction, PartialTransaction, TxOutpoint, TxinDataFetchProgress from electrum.logging import get_logger from electrum.util import ShortID, get_asyncio_loop, UI_UNIT_NAME_TXSIZE_VBYTES from electrum.network import Network from electrum.wallet import TxSighashRiskLevel, TxSighashDanger -from . import util from .util import (MessageBoxMixin, read_QIcon, Buttons, icon_path, MONOSPACE_FONT, ColorScheme, ButtonsLineEdit, ShowQRLineEdit, text_dialog, char_width_in_lineedit, TRANSACTION_FILE_EXTENSION_FILTER_SEPARATE, @@ -185,6 +179,7 @@ class TxInOutWidget(QWidget): lnk.setAnchor(True) lnk.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SingleUnderline) tf_used_recv, tf_used_change, tf_used_2fa, tf_used_swap = False, False, False, False + def addr_text_format(addr: str) -> QTextCharFormat: nonlocal tf_used_recv, tf_used_change, tf_used_2fa, tf_used_swap sm = self.wallet.lnworker.swap_manager if self.wallet.lnworker else None @@ -643,9 +638,11 @@ class TxDialog(QDialog, MessageBoxMixin): def _add_slip_19_ownership_proofs_to_tx(self): assert isinstance(self.tx, PartialTransaction) + def on_success(result): self._export_option_slip19.setEnabled(False) self.main_window.pop_top_level_window(self) + def on_failure(exc_info): self._export_option_slip19.setChecked(False) self.main_window.on_error(exc_info) @@ -1024,9 +1021,11 @@ class TxDialog(QDialog, MessageBoxMixin): if self._fetch_txin_data_fut is not None: return network = self.wallet.network + def progress_cb(prog: TxinDataFetchProgress): self._fetch_txin_data_progress = prog self.throttled_update_sig.emit() + async def wrapper(): try: await tx.add_info_from_network(network, progress_cb=progress_cb) diff --git a/electrum/gui/qt/update_checker.py b/electrum/gui/qt/update_checker.py index 7112f61d1..190666722 100644 --- a/electrum/gui/qt/update_checker.py +++ b/electrum/gui/qt/update_checker.py @@ -7,8 +7,7 @@ import base64 from typing import Optional from PyQt6.QtCore import Qt, QThread, pyqtSignal -from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QLabel, QProgressBar, - QHBoxLayout, QPushButton, QDialog) +from PyQt6.QtWidgets import QVBoxLayout, QLabel, QProgressBar, QHBoxLayout, QPushButton, QDialog from electrum import version from electrum import constants diff --git a/electrum/gui/qt/utxo_dialog.py b/electrum/gui/qt/utxo_dialog.py index 91443efc1..390a5e981 100644 --- a/electrum/gui/qt/utxo_dialog.py +++ b/electrum/gui/qt/utxo_dialog.py @@ -42,7 +42,6 @@ if TYPE_CHECKING: from .main_window import ElectrumWindow - class UTXODialog(WindowModalDialog): def __init__(self, window: 'ElectrumWindow', utxo: 'PartialTxInput'): @@ -102,6 +101,7 @@ class UTXODialog(WindowModalDialog): self.parents_list.clear() self.num_reuse = 0 + def print_ascii_tree(_txid, prefix, is_last, is_uncle): if _txid not in parents: return diff --git a/electrum/gui/qt/utxo_list.py b/electrum/gui/qt/utxo_list.py index d6f5434e2..ae2072168 100644 --- a/electrum/gui/qt/utxo_list.py +++ b/electrum/gui/qt/utxo_list.py @@ -29,7 +29,7 @@ import copy from PyQt6.QtCore import Qt from PyQt6.QtGui import QStandardItemModel, QStandardItem, QFont -from PyQt6.QtWidgets import QAbstractItemView, QMenu, QLabel, QHBoxLayout +from PyQt6.QtWidgets import QAbstractItemView, QMenu from electrum.i18n import _ from electrum.bitcoin import is_address @@ -37,7 +37,7 @@ from electrum.transaction import PartialTxInput, PartialTxOutput from electrum.lnutil import MIN_FUNDING_SAT from electrum.util import profiler -from .util import ColorScheme, MONOSPACE_FONT, EnterButton +from .util import ColorScheme, MONOSPACE_FONT from .my_treeview import MyTreeView, MySortModel from .new_channel_dialog import NewChannelDialog from ..messages import MSG_FREEZE_ADDRESS, MSG_FREEZE_COIN diff --git a/electrum/transaction.py b/electrum/transaction.py index cad9b2249..5712ffec2 100644 --- a/electrum/transaction.py +++ b/electrum/transaction.py @@ -808,8 +808,6 @@ def multisig_script(public_keys: Sequence[str], m: int) -> bytes: return construct_script([m, *public_keys, n, opcodes.OP_CHECKMULTISIG]) - - class Transaction: _cached_network_ser: Optional[str] diff --git a/electrum/x509.py b/electrum/x509.py index 424793e5c..07450bb2b 100644 --- a/electrum/x509.py +++ b/electrum/x509.py @@ -194,6 +194,7 @@ class ASN1_Node(bytes): except TypeError: return time.strptime(self.get_value_of_type(ii, 'GeneralizedTime').decode('ascii'), GENERALIZED_TIMESTAMP_FMT) + class X509(object): def __init__(self, b):