mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 00:27:01 +01:00
`requires-python` and the CI pin already said 3.14, but ruff, mypy and pylint were still grading `meta/` against 3.10 -- three tools judging an interpreter nothing runs any more, and ruff withholding the pyupgrade fixes that only become safe at the newer target. `pin_ci_python.py` rewrites these three knobs. What the stale target was hiding: `datetime.timezone.utc` where `datetime.UTC` is now correct (UP017), and ruff's stable formatter applying PEP 758 -- `except (A, B):` becomes `except A, B:`. That makes the source 3.14-only at the syntax level, which is what `requires-python = ">=3.14"` already promised; kuhy chose it deliberately over holding ruff a release back (2026-08-29). Also drops a comment in `wsg_grabber/models.py` that the bump makes false: it explained why the file used ``str, Enum`` instead of ``StrEnum`` under mypy at 3.10, sitting directly above a ``class Verdict(StrEnum)`` that had already stopped obeying it. ruff, ruff-format, mypy --strict and pylint all clean at the new target. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
132 lines
4.0 KiB
Python
132 lines
4.0 KiB
Python
"""Interactive study session orchestrator.
|
|
|
|
Thin coordination layer: loads plan + progress, calls the Verifier per item,
|
|
saves progress after each lesson, and shows a summary table at the end.
|
|
No LLM calls or judgment logic live here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import TYPE_CHECKING
|
|
|
|
from rich.table import Table
|
|
|
|
from python_pkg.code_tutor._progress import (
|
|
append_session_record,
|
|
item_from_data,
|
|
load_plan,
|
|
load_progress,
|
|
save_progress,
|
|
)
|
|
from python_pkg.code_tutor._verifier import Verifier
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
from pathlib import Path
|
|
|
|
from rich.console import Console
|
|
|
|
from python_pkg.code_tutor._analyzer import CodeItem
|
|
from python_pkg.code_tutor._llm import Backend
|
|
from python_pkg.code_tutor._progress import PlanData, ProgressData
|
|
|
|
|
|
def _items_from_plan(plan: PlanData) -> list[CodeItem]:
|
|
"""Reconstruct ``CodeItem`` objects from a loaded ``PlanData`` dict.
|
|
|
|
Args:
|
|
plan: Plan as loaded from ``plan.json``.
|
|
|
|
Returns:
|
|
Flat list of ``CodeItem`` instances in session order.
|
|
"""
|
|
return [
|
|
item_from_data(data)
|
|
for session in plan["sessions"]
|
|
for data in session["items"]
|
|
]
|
|
|
|
|
|
def _show_summary(
|
|
results: dict[str, list[str]],
|
|
console: Console,
|
|
) -> None:
|
|
"""Print a session summary table to *console*.
|
|
|
|
Args:
|
|
results: Mapping of outcome (``"learned"``, ``"struggled"``,
|
|
``"skipped"``) to lists of item IDs.
|
|
console: Rich console for output.
|
|
"""
|
|
table = Table(title="Session summary", show_header=True, header_style="bold")
|
|
table.add_column("Outcome")
|
|
table.add_column("Count", justify="right")
|
|
table.add_row("[green]Learned[/green]", str(len(results.get("learned", []))))
|
|
table.add_row("[red]Struggled[/red]", str(len(results.get("struggled", []))))
|
|
table.add_row("[yellow]Skipped[/yellow]", str(len(results.get("skipped", []))))
|
|
console.print(table)
|
|
|
|
|
|
def run_session(
|
|
codebase: Path,
|
|
backend: Backend,
|
|
*,
|
|
console: Console,
|
|
input_fn: Callable[[str], str] = input,
|
|
) -> None:
|
|
"""Run an interactive study session for *codebase*.
|
|
|
|
Loads the saved plan and progress, iterates over unfinished items, calls
|
|
the Verifier per item, saves progress after each lesson, and shows a
|
|
summary table on completion.
|
|
|
|
Args:
|
|
codebase: Root directory of the codebase being studied.
|
|
backend: LLM backend to pass to the Verifier.
|
|
console: Rich console for all output.
|
|
input_fn: Callable used for user input (injectable for testing).
|
|
"""
|
|
plan = load_plan(codebase)
|
|
if plan is None:
|
|
console.print(
|
|
"[red]No plan found. "
|
|
"Run [bold]code_tutor analyze <path>[/bold] first.[/red]"
|
|
)
|
|
return
|
|
|
|
progress: ProgressData = load_progress(codebase)
|
|
done_ids: set[str] = (
|
|
set(progress["learned"]) | set(progress["struggled"]) | set(progress["skipped"])
|
|
)
|
|
|
|
all_items = _items_from_plan(plan)
|
|
pending = [it for it in all_items if it.id not in done_ids]
|
|
|
|
if not pending:
|
|
console.print(
|
|
"[green]All items complete! "
|
|
"Run [bold]code_tutor status[/bold] to see your progress.[/green]"
|
|
)
|
|
return
|
|
|
|
verifier = Verifier(backend, console)
|
|
results: dict[str, list[str]] = {"learned": [], "struggled": [], "skipped": []}
|
|
codebase_str = str(codebase.resolve())
|
|
|
|
for item in pending:
|
|
record = verifier.run_lesson(item, codebase_str, input_fn=input_fn)
|
|
outcome = record.outcome
|
|
results[outcome].append(item.id)
|
|
append_session_record(codebase, record)
|
|
if outcome == "learned":
|
|
progress["learned"].append(item.id)
|
|
elif outcome == "struggled":
|
|
progress["struggled"].append(item.id)
|
|
else:
|
|
progress["skipped"].append(item.id)
|
|
progress["last_session"] = datetime.now(tz=UTC).isoformat(timespec="seconds")
|
|
save_progress(codebase, progress)
|
|
|
|
_show_summary(results, console)
|