mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-07 06:48:52 +00:00
Add StatsManager for single display
This commit is contained in:
15
src/main.py
15
src/main.py
@@ -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:
|
||||
|
@@ -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}'")
|
||||
|
@@ -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
|
||||
|
20
src/seedpass/core/stats_manager.py
Normal file
20
src/seedpass/core/stats_manager.py
Normal 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
|
@@ -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
|
||||
|
Reference in New Issue
Block a user