feat: Session Sovereignty Report Generator (#957)
- Add `src/timmy/sovereignty/session_report.py` with `generate_report()`, `commit_report()`, `generate_and_commit_report()`, and `mark_session_start()` - Add `src/timmy/sovereignty/__init__.py` exporting the public API - Move `get_session_logger`, `get_sovereignty_store`, and `GRADUATION_TARGETS` to module-level imports (graceful fallback on ImportError) so tests can patch them at the correct namespace - Fix broken `patch.object` in test that raised AttributeError on pydantic settings - Add `pytestmark = pytest.mark.unit` so tests run under `tox -e unit` - All 23 sovereignty report tests pass Fixes #957 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,18 @@ import httpx
|
||||
|
||||
from config import settings
|
||||
|
||||
# Optional module-level imports — degrade gracefully if unavailable at import time
|
||||
try:
|
||||
from timmy.session_logger import get_session_logger
|
||||
except Exception: # ImportError or circular import during early startup
|
||||
get_session_logger = None # type: ignore[assignment]
|
||||
|
||||
try:
|
||||
from infrastructure.sovereignty_metrics import GRADUATION_TARGETS, get_sovereignty_store
|
||||
except Exception:
|
||||
GRADUATION_TARGETS: dict = {} # type: ignore[assignment]
|
||||
get_sovereignty_store = None # type: ignore[assignment]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Module-level session start time; set by mark_session_start()
|
||||
@@ -197,8 +209,8 @@ def _gather_session_data() -> dict[str, Any]:
|
||||
}
|
||||
|
||||
try:
|
||||
from timmy.session_logger import get_session_logger
|
||||
|
||||
if get_session_logger is None:
|
||||
return default
|
||||
sl = get_session_logger()
|
||||
sl.flush()
|
||||
|
||||
@@ -255,8 +267,8 @@ def _gather_sovereignty_data() -> dict[str, Any]:
|
||||
- ``previous_session``: most recent prior value for each metric
|
||||
"""
|
||||
try:
|
||||
from infrastructure.sovereignty_metrics import GRADUATION_TARGETS, get_sovereignty_store
|
||||
|
||||
if get_sovereignty_store is None:
|
||||
return {"metrics": {}, "deltas": {}, "previous_session": {}}
|
||||
store = get_sovereignty_store()
|
||||
summary = store.get_summary()
|
||||
|
||||
@@ -333,10 +345,6 @@ def _render_markdown(
|
||||
lines.append("")
|
||||
|
||||
# Sovereignty scorecard
|
||||
try:
|
||||
from infrastructure.sovereignty_metrics import GRADUATION_TARGETS
|
||||
except Exception:
|
||||
GRADUATION_TARGETS = {}
|
||||
|
||||
lines += [
|
||||
"## Sovereignty Scorecard",
|
||||
|
||||
@@ -12,6 +12,8 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.unit
|
||||
|
||||
from timmy.sovereignty.session_report import (
|
||||
_format_duration,
|
||||
_gather_session_data,
|
||||
@@ -293,9 +295,6 @@ class TestGenerateReport:
|
||||
|
||||
class TestCommitReport:
|
||||
def test_returns_false_when_gitea_disabled(self):
|
||||
with patch.object(type(settings := __import__("config").settings), "gitea_enabled", False):
|
||||
pass # mock via config patch instead
|
||||
|
||||
with patch("timmy.sovereignty.session_report.settings") as mock_settings:
|
||||
mock_settings.gitea_enabled = False
|
||||
result = commit_report("# test", "dashboard")
|
||||
|
||||
Reference in New Issue
Block a user