mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 21:07:03 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JThjboXTeZ3yJPBzxMx5wS
124 lines
3.8 KiB
Python
124 lines
3.8 KiB
Python
"""Shared dashboard test setup: source isolation and transcript builders.
|
|
|
|
The autouse fixture keeps every test away from the real ``~/.claude`` state;
|
|
the builders below make synthetic transcript records.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
import json
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import pytest
|
|
|
|
from python_pkg.token_dashboard import ab, aux, context_files, walk
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
from python_pkg.token_dashboard.detail_rows import DetailRows
|
|
|
|
BASE = 1_791_600_000.0 # 2026-10-09, a fixed anchor so day buckets are stable
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _isolated_sources(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Point every aux source at an empty tmp directory."""
|
|
claude = tmp_path / "claude-home"
|
|
monkeypatch.setattr(aux, "AUTOPSY", claude / "autopsy.jsonl")
|
|
monkeypatch.setattr(aux, "PROMPT_HISTORY", claude / "history.jsonl")
|
|
monkeypatch.setattr(aux, "TIME_CAP", claude / "time-cap.jsonl")
|
|
monkeypatch.setattr(ab, "LOG", claude / "agent-ab.jsonl")
|
|
monkeypatch.setattr(context_files, "CLAUDE_DIR", claude)
|
|
monkeypatch.setattr(context_files, "SRC_DIR", claude / "src")
|
|
|
|
|
|
def iso(offset: float) -> str:
|
|
"""ISO timestamp ``offset`` seconds after :data:`BASE`."""
|
|
return datetime.fromtimestamp(BASE + offset, tz=UTC).isoformat()
|
|
|
|
|
|
def prompt(text: str, at: float, **extra: object) -> dict[str, Any]:
|
|
"""A typed user prompt."""
|
|
return {
|
|
"type": "user",
|
|
"timestamp": iso(at),
|
|
"cwd": "/repo",
|
|
"message": {"role": "user", "content": text},
|
|
**extra,
|
|
}
|
|
|
|
|
|
def assistant(
|
|
mid: str,
|
|
at: float,
|
|
*,
|
|
output: int = 1000,
|
|
model: str = "claude-opus-5-5",
|
|
blocks: list[dict[str, Any]] | None = None,
|
|
context: int = 0,
|
|
**usage: object,
|
|
) -> dict[str, Any]:
|
|
"""One assistant record; ``context`` becomes cache-read tokens.
|
|
|
|
``usage`` adds raw usage fields, e.g. a cache-write split.
|
|
"""
|
|
return {
|
|
"type": "assistant",
|
|
"timestamp": iso(at),
|
|
"message": {
|
|
"id": mid,
|
|
"model": model,
|
|
"usage": {
|
|
"output_tokens": output,
|
|
"cache_read_input_tokens": context,
|
|
**usage,
|
|
},
|
|
"content": blocks or [{"type": "text", "text": "ok"}],
|
|
},
|
|
}
|
|
|
|
|
|
def use(tid: str, name: str, **tool_input: object) -> dict[str, Any]:
|
|
"""A ``tool_use`` content block."""
|
|
return {"type": "tool_use", "id": tid, "name": name, "input": tool_input}
|
|
|
|
|
|
def result(
|
|
tid: str, at: float, text: str = "x" * 40, **extra: object
|
|
) -> dict[str, Any]:
|
|
"""A user record carrying one ``tool_result``."""
|
|
return {
|
|
"type": "user",
|
|
"timestamp": iso(at),
|
|
"message": {
|
|
"role": "user",
|
|
"content": [{"type": "tool_result", "tool_use_id": tid, "content": text}],
|
|
},
|
|
**extra,
|
|
}
|
|
|
|
|
|
def write(path: Path, records: list[dict[str, Any]]) -> Path:
|
|
"""Write records as JSONL, creating parent directories."""
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text("\n".join(json.dumps(r) for r in records) + "\n", encoding="utf-8")
|
|
return path
|
|
|
|
|
|
def usd_opus_output(tokens: int) -> float:
|
|
"""List price of ``tokens`` Opus 5.5 output tokens (USD 20 / MTok)."""
|
|
return tokens * 20 / 1_000_000
|
|
|
|
|
|
def attach(at: float, **attachment: object) -> dict[str, Any]:
|
|
"""An ``attachment`` record."""
|
|
return {"type": "attachment", "timestamp": iso(at), "attachment": attachment}
|
|
|
|
|
|
def walk_detail(tmp_path: Path, records: list[dict[str, Any]]) -> DetailRows:
|
|
"""Walk one main-session file and return its detail rows."""
|
|
path = write(tmp_path / "proj" / "s.jsonl", records)
|
|
return walk.walk_file(path, tmp_path).rows.detail
|