From f445a476f92bd752319e9bb7782f27a97aa32345 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Mon, 3 Mar 2025 17:41:23 +0000 Subject: [PATCH] config: raise on setting mistyped or non-existent ConfigVar --- electrum/simple_config.py | 17 +++++++++++++++++ tests/test_simple_config.py | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 5834a1a65..26042b30b 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -244,6 +244,8 @@ class SimpleConfig(Logger): self.amt_precision_post_satoshi = self.BTC_AMOUNTS_PREC_POST_SAT self.amt_add_thousands_sep = self.BTC_AMOUNTS_ADD_THOUSANDS_SEP + self._init_done = True + def list_config_vars(self) -> Sequence[str]: return list(sorted(_config_var_from_key.keys())) @@ -897,6 +899,21 @@ class SimpleConfig(Logger): def get_decimal_point(self): return self.decimal_point + def __setattr__(self, name, value): + """Disallows setting instance attributes outside __init__. + + The point is to make the following code raise: + >>> config.NETORK_AUTO_CONNECTT = False + (i.e. catch mistyped or non-existent ConfigVars) + """ + # If __init__ not finished yet, or this field already exists, set it: + if not getattr(self, "_init_done", False) or hasattr(self, name): + return super().__setattr__(name, value) + raise AttributeError( + f"Tried to define new instance attribute for config: {name=!r}. " + "Did you perhaps mistype a ConfigVar?" + ) + @cached_property def cv(config): """Allows getting a reference to a config variable without dereferencing it. diff --git a/tests/test_simple_config.py b/tests/test_simple_config.py index 2b1da5b87..dc79b21bb 100644 --- a/tests/test_simple_config.py +++ b/tests/test_simple_config.py @@ -136,6 +136,12 @@ class Test_SimpleConfig(ElectrumTestCase): # revert: config.NETWORK_SERVER = None + def test_configvars_setter_catches_typo(self): + config = SimpleConfig(self.options) + assert not hasattr(config, "NETORK_AUTO_CONNECTT") + with self.assertRaises(AttributeError): + config.NETORK_AUTO_CONNECTT = False + def test_configvars_get_default_value(self): config = SimpleConfig(self.options) self.assertEqual(MAX_MSG_SIZE_DEFAULT, config.cv.NETWORK_MAX_INCOMING_MSG_SIZE.get_default_value())