Add StatsManager for single display

This commit is contained in:
thePR0M3TH3AN
2025-07-31 16:01:40 -04:00
parent a4ddd120c8
commit 6d82ef1815
5 changed files with 76 additions and 3 deletions

View File

@@ -281,6 +281,7 @@ def _display_live_stats(
displayed if newer data exists on Nostr.
"""
stats_mgr = getattr(password_manager, "stats_manager", None)
display_fn = getattr(password_manager, "display_stats", None)
sync_fn = getattr(password_manager, "start_background_sync", None)
if not callable(display_fn):
@@ -294,12 +295,17 @@ def _display_live_stats(
if not sys.stdin or not sys.stdin.isatty():
clear_screen()
display_fn()
if stats_mgr is not None:
stats_mgr.display_stats_once(password_manager)
else:
display_fn()
note = get_notification_text(password_manager)
if note:
print(note)
print(colored("Press Enter to continue.", "cyan"))
pause()
if stats_mgr is not None:
stats_mgr.reset()
return
while True:
@@ -309,7 +315,10 @@ def _display_live_stats(
except Exception: # pragma: no cover - sync best effort
logging.debug("Background sync failed during stats display")
clear_screen()
display_fn()
if stats_mgr is not None:
stats_mgr.display_stats_once(password_manager)
else:
display_fn()
note = get_notification_text(password_manager)
if note:
print(note)
@@ -324,6 +333,8 @@ def _display_live_stats(
except KeyboardInterrupt:
print()
break
if stats_mgr is not None:
stats_mgr.reset()
def handle_display_stats(password_manager: PasswordManager) -> None:

View File

@@ -4,7 +4,14 @@
from importlib import import_module
__all__ = ["PasswordManager", "ConfigManager", "Vault", "EntryType", "StateManager"]
__all__ = [
"PasswordManager",
"ConfigManager",
"Vault",
"EntryType",
"StateManager",
"StatsManager",
]
def __getattr__(name: str):
@@ -18,4 +25,6 @@ def __getattr__(name: str):
return import_module(".entry_types", __name__).EntryType
if name == "StateManager":
return import_module(".state_manager", __name__).StateManager
if name == "StatsManager":
return import_module(".stats_manager", __name__).StatsManager
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")

View File

@@ -99,6 +99,7 @@ from utils.fingerprint_manager import FingerprintManager
from nostr.client import NostrClient, DEFAULT_RELAYS, MANIFEST_ID_PREFIX
from .config_manager import ConfigManager
from .state_manager import StateManager
from .stats_manager import StatsManager
# Instantiate the logger
logger = logging.getLogger(__name__)
@@ -163,6 +164,7 @@ class PasswordManager:
self.nostr_client: Optional[NostrClient] = None
self.config_manager: Optional[ConfigManager] = None
self.state_manager: Optional[StateManager] = None
self.stats_manager: StatsManager = StatsManager()
self.notifications: queue.Queue[Notification] = queue.Queue()
self._current_notification: Optional[Notification] = None
self._notification_expiry: float = 0.0

View File

@@ -0,0 +1,20 @@
"""Manage display of stats screens."""
from __future__ import annotations
class StatsManager:
"""Track whether stats have been displayed."""
def __init__(self) -> None:
self._displayed = False
def display_stats_once(self, manager) -> None:
"""Display stats using ``manager`` once per reset."""
if not self._displayed:
manager.display_stats()
self._displayed = True
def reset(self) -> None:
"""Reset the displayed flag."""
self._displayed = False

View File

@@ -2,6 +2,7 @@ import sys
from types import SimpleNamespace
from pathlib import Path
import pytest
from seedpass.core.stats_manager import StatsManager
sys.path.append(str(Path(__file__).resolve().parents[1]))
@@ -12,6 +13,7 @@ def _make_pm():
return SimpleNamespace(
display_stats=lambda: print("stats"),
start_background_sync=lambda: None,
stats_manager=StatsManager(),
)
@@ -57,3 +59,32 @@ def test_live_stats_triggers_background_sync(monkeypatch):
main._display_live_stats(pm)
assert called["sync"] >= 1
def test_stats_display_only_once(monkeypatch, capsys):
pm = _make_pm()
monkeypatch.setattr(main, "get_notification_text", lambda *_: "")
events = [TimeoutError(), KeyboardInterrupt()]
def fake_input(*_args, **_kwargs):
raise events.pop(0)
monkeypatch.setattr(main, "timed_input", fake_input)
main._display_live_stats(pm, interval=0.01)
out = capsys.readouterr().out
assert out.count("stats") == 1
def test_stats_display_resets_after_exit(monkeypatch, capsys):
pm = _make_pm()
monkeypatch.setattr(main, "get_notification_text", lambda *_: "")
monkeypatch.setattr(
main,
"timed_input",
lambda *_args, **_kwargs: (_ for _ in ()).throw(KeyboardInterrupt()),
)
main._display_live_stats(pm)
main._display_live_stats(pm)
out = capsys.readouterr().out
assert out.count("stats") == 2