tconfig: enforce that SimpleConfig is singleton - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit b2920db8b8a10600e8851317118699b34ba926d8 DIR parent a43be6657defe92631872d401fa0a940b680a540 HTML Author: SomberNight <somber.night@protonmail.com> Date: Tue, 10 Sep 2019 18:01:10 +0200 config: enforce that SimpleConfig is singleton related: #5629 Diffstat: M electrum/__init__.py | 2 +- M electrum/gui/qt/qrcodewidget.py | 4 +++- M electrum/gui/qt/qrtextedit.py | 5 +++-- M electrum/lnchannel.py | 1 - M electrum/lnpeer.py | 1 - M electrum/network.py | 9 +++++---- M electrum/simple_config.py | 25 +++++++++++++------------ M electrum/tests/__init__.py | 4 ++++ M electrum/wallet.py | 7 ++++--- 9 files changed, 33 insertions(+), 25 deletions(-) --- DIR diff --git a/electrum/__init__.py b/electrum/__init__.py t@@ -5,7 +5,7 @@ from .storage import WalletStorage from .coinchooser import COIN_CHOOSERS from .network import Network, pick_random_server from .interface import Interface -from .simple_config import SimpleConfig, get_config, set_config +from .simple_config import SimpleConfig from . import bitcoin from . import transaction from . import daemon DIR diff --git a/electrum/gui/qt/qrcodewidget.py b/electrum/gui/qt/qrcodewidget.py t@@ -9,6 +9,8 @@ from PyQt5.QtWidgets import ( import electrum from electrum.i18n import _ +from electrum.simple_config import SimpleConfig + from .util import WindowModalDialog t@@ -105,7 +107,7 @@ class QRDialog(WindowModalDialog): hbox = QHBoxLayout() hbox.addStretch(1) - config = electrum.get_config() + config = SimpleConfig.get_instance() if config: filename = os.path.join(config.path, "qrcode.png") DIR diff --git a/electrum/gui/qt/qrtextedit.py b/electrum/gui/qt/qrtextedit.py t@@ -2,6 +2,7 @@ from PyQt5.QtWidgets import QFileDialog from electrum.i18n import _ from electrum.plugin import run_hook +from electrum.simple_config import SimpleConfig from .util import ButtonsTextEdit, MessageBoxMixin, ColorScheme t@@ -54,9 +55,9 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin): self.setText(data) def qr_input(self): - from electrum import qrscanner, get_config + from electrum import qrscanner try: - data = qrscanner.scan_barcode(get_config().get_video_device()) + data = qrscanner.scan_barcode(SimpleConfig.get_instance().get_video_device()) except BaseException as e: self.show_error(repr(e)) data = '' DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py t@@ -35,7 +35,6 @@ from .util import bfh, bh2u, PR_PAID, PR_FAILED from .bitcoin import TYPE_SCRIPT, TYPE_ADDRESS from .bitcoin import redeem_script_to_address from .crypto import sha256, sha256d -from .simple_config import get_config from .transaction import Transaction from .logging import Logger DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py t@@ -18,7 +18,6 @@ from datetime import datetime import aiorpcx -from .simple_config import get_config from .crypto import sha256, sha256d from . import bitcoin from . import ecc DIR diff --git a/electrum/network.py b/electrum/network.py t@@ -224,7 +224,7 @@ class UntrustedServerReturnedError(NetworkException): return f"<UntrustedServerReturnedError original_exception: {repr(self.original_exception)}>" -INSTANCE = None +_INSTANCE = None class Network(Logger): t@@ -235,8 +235,9 @@ class Network(Logger): LOGGING_SHORTCUT = 'n' def __init__(self, config: SimpleConfig): - global INSTANCE - INSTANCE = self + global _INSTANCE + assert _INSTANCE is None, "Network is a singleton!" + _INSTANCE = self Logger.__init__(self) t@@ -322,7 +323,7 @@ class Network(Logger): @staticmethod def get_instance() -> Optional["Network"]: - return INSTANCE + return _INSTANCE def with_recent_servers_lock(func): def func_wrapper(self, *args, **kwargs): DIR diff --git a/electrum/simple_config.py b/electrum/simple_config.py t@@ -31,19 +31,9 @@ FEERATE_STATIC_VALUES = [1000, 2000, 5000, 10000, 20000, 30000, FEERATE_REGTEST_HARDCODED = 180000 # for eclair compat -config = {} _logger = get_logger(__name__) -def get_config(): - global config - return config - - -def set_config(c): - global config - config = c - def estimate_fee(tx_size_bytes: int) -> int: def use_fallback_feerate(): fee_per_kb = FEERATE_FALLBACK_STATIC_FEE t@@ -61,6 +51,10 @@ def estimate_fee(tx_size_bytes: int) -> int: FINAL_CONFIG_VERSION = 3 +_INSTANCE = None +_ENFORCE_SIMPLECONFIG_SINGLETON = True # disabled in tests + + class SimpleConfig(Logger): """ The SimpleConfig class is responsible for handling operations involving t@@ -74,6 +68,12 @@ class SimpleConfig(Logger): def __init__(self, options=None, read_user_config_function=None, read_user_dir_function=None): + # note: To be honest, singletons are bad design... :/ + # However currently we somewhat rely on config being one. + global _INSTANCE + if _ENFORCE_SIMPLECONFIG_SINGLETON: + assert _INSTANCE is None, "SimpleConfig is a singleton!" + _INSTANCE = self if options is None: options = {} t@@ -120,8 +120,9 @@ class SimpleConfig(Logger): if self.requires_upgrade(): self.upgrade() - # Make a singleton instance of 'self' - set_config(self) + @staticmethod + def get_instance() -> Optional["SimpleConfig"]: + return _INSTANCE def electrum_path(self): # Read electrum_path from command line DIR diff --git a/electrum/tests/__init__.py b/electrum/tests/__init__.py t@@ -2,6 +2,7 @@ import unittest import threading from electrum import constants +from electrum import simple_config # Set this locally to make the test suite run faster. t@@ -11,6 +12,9 @@ from electrum import constants FAST_TESTS = False +simple_config._ENFORCE_SIMPLECONFIG_SINGLETON = False + + # some unit tests are modifying globals; sorry. class SequentialTestCase(unittest.TestCase): DIR diff --git a/electrum/wallet.py b/electrum/wallet.py t@@ -47,7 +47,7 @@ from .util import (NotEnoughFunds, UserCancelled, profiler, InvalidPassword, format_time, timestamp_to_datetime, Satoshis, Fiat, bfh, bh2u, TxMinedInfo, quantize_feerate, create_bip21_uri, OrderedDictWithIndex) from .util import PR_TYPE_ADDRESS, PR_TYPE_BIP70, PR_TYPE_LN -from .simple_config import get_config +from .simple_config import SimpleConfig from .bitcoin import (COIN, TYPE_ADDRESS, is_address, address_to_script, is_minikey, relayfee, dust_threshold) from .crypto import sha256d t@@ -71,7 +71,6 @@ from .paymentrequest import PaymentRequest if TYPE_CHECKING: from .network import Network - from .simple_config import SimpleConfig _logger = get_logger(__name__) t@@ -236,7 +235,9 @@ class Abstract_Wallet(AddressSynchronizer): self.contacts = Contacts(self.storage) self._coin_price_cache = {} - self.config = get_config() + # TODO config should be passed as a param instead? SimpleConfig should not be a singleton. + self.config = SimpleConfig.get_instance() + assert self.config is not None, "config must not be None" self.lnworker = LNWallet(self) if self.config.get('lightning') else None def stop_threads(self):