refactor: cache Settings() namespace tree as a singleton
What changed, and why it matters
This commit is a performance refactor, not a security fix. It caches a single copy of the app's settings object tree so it doesn't rebuild ~16 objects every time code asks for Settings(). The actual setting values are still read fresh from storage, so behavior should not change. A test helper is updated to clear that cache so a mocked wallet class gets picked up during tests.
No security action needed. Treat as a normal code-quality/performance change. Reviewers may want to confirm that no code path relies on Settings() returning a fresh object identity or freshly re-evaluated child namespaces.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change adds a singleton-style new to the Settings class in src/krux/krux_settings.py, returning an existing _instance if present. init now short-circuits when _built is True, so child namespace objects (DefaultWallet, SecuritySettings, HardwareSettings, etc.) are constructed only once. Because values are read live from the underlying store singleton, the cache does not introduce stale setting data. The test fixture mock_retro_compatibility resets Settings._instance to None so a patched DefaultWallet is used in tests despite the new caching.
Changed components
src/krux/krux_settings.pytests/pages/test_login.pyInspect captured patch +17 / −0
diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py
index 765f180..e19ab91 100644
--- a/src/krux/krux_settings.py
+++ b/src/krux/krux_settings.py
@@ -490,8 +490,19 @@ class Settings(SettingsNamespace):
"""The top-level settings namespace under which other namespaces reside"""
namespace = "settings"
+ _instance = None
+
+ def __new__(cls):
+ # Cache the namespace tree: values are read live from the `store`
+ # singleton, so reusing the instance avoids rebuilding ~16 objects
+ # on every Settings() call without staling any setting.
+ if cls._instance is None:
+ cls._instance = super().__new__(cls)
+ return cls._instance
def __init__(self):
+ if getattr(self, "_built", False):
+ return
self.wallet = DefaultWallet()
self.security = SecuritySettings()
self.hardware = HardwareSettings()
@@ -499,6 +510,7 @@ class Settings(SettingsNamespace):
self.encryption = EncryptionSettings()
self.persist = PersistSettings()
self.appearance = ThemeSettings()
+ self._built = True
def is_flipped_orientation(self):
"""Returns flipped orientation setting"""
diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py
index 2023fba..c802a4c 100644
--- a/tests/pages/test_login.py
+++ b/tests/pages/test_login.py
@@ -10,6 +10,7 @@ def mocker_printer(mocker):
@pytest.fixture
def mock_retro_compatibility(mocker, amigo):
from krux.settings import CategorySetting
+ from krux.krux_settings import Settings
class MockDefaultWallet:
namespace = "settings.wallet"
@@ -24,6 +25,10 @@ def mock_retro_compatibility(mocker, amigo):
"krux.krux_settings.DefaultWallet",
mocker.MagicMock(return_value=MockDefaultWallet()),
)
+ # Settings caches its namespace tree, which may already have been built
+ # (e.g. via krux.themes at import). Drop the cache so the next Settings()
+ # rebuilds with the patched DefaultWallet.
+ mocker.patch.object(Settings, "_instance", None)
################### Test menus
Why this scored 13/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.