diff --git a/tools/src/pop_fem_audit_tools/commands/export_llm_input.py b/tools/src/pop_fem_audit_tools/commands/export_llm_input.py index 458d280..52c784b 100644 --- a/tools/src/pop_fem_audit_tools/commands/export_llm_input.py +++ b/tools/src/pop_fem_audit_tools/commands/export_llm_input.py @@ -28,6 +28,7 @@ keys, then that song's own keys, each group in its file order. import argparse import json import sys +import time from pathlib import Path from typing import Any @@ -36,6 +37,7 @@ from sqlalchemy.orm import Session from ..database import ds from ..models import Song +from ..utils import format_duration def parse_args(argv: list[str] | None) -> argparse.Namespace: @@ -231,6 +233,7 @@ def main(argv: list[str] | None = None) -> int: ``sys.argv``. :return: The exit status: 0 on success, non-zero on failure. """ + started: float = time.monotonic() args: argparse.Namespace = parse_args(argv) session: Session = ds.get_db() lines: list[str] @@ -252,5 +255,7 @@ def main(argv: list[str] | None = None) -> int: line: str for line in lines: file.write(line + "\n") - print(f"done: {len(lines)} songs exported", file=sys.stderr) + elapsed: str = format_duration(time.monotonic() - started) + print(f"Done. {len(lines)} songs exported." + f" {elapsed} elapsed.", file=sys.stderr) return 0 diff --git a/tools/src/pop_fem_audit_tools/commands/run_llm.py b/tools/src/pop_fem_audit_tools/commands/run_llm.py index eb5aa88..44bef19 100644 --- a/tools/src/pop_fem_audit_tools/commands/run_llm.py +++ b/tools/src/pop_fem_audit_tools/commands/run_llm.py @@ -488,8 +488,9 @@ def main(argv: list[str] | None = None) -> int: print(json.dumps( build_request(items[0], prompt_text, args.max_tokens), ensure_ascii=False, indent=2)) - print(f"dry run: archive created at {archive_dir}", - file=sys.stderr) + elapsed: str = format_duration(time.monotonic() - started) + print(f"Done. {len(items)} jobs finished." + f" {elapsed} elapsed.", file=sys.stderr) return 0 client: anthropic.Anthropic = anthropic.Anthropic( api_key=get_settings().ANTHROPIC_API_KEY) @@ -507,7 +508,6 @@ def main(argv: list[str] | None = None) -> int: file=sys.stderr) return 1 elapsed: str = format_duration(time.monotonic() - started) - print(f"done: {len(items)} items;" - f" archived to {archive_dir} {elapsed} elapsed.", - file=sys.stderr) + print(f"Done. {len(items)} jobs finished." + f" {elapsed} elapsed.", file=sys.stderr) return 0 diff --git a/tools/tests/test_export_llm_input.py b/tools/tests/test_export_llm_input.py index f5c6cf2..303374c 100644 --- a/tools/tests/test_export_llm_input.py +++ b/tools/tests/test_export_llm_input.py @@ -141,7 +141,7 @@ class TestExportLlmInput(unittest.TestCase): self.assertEqual(records, [ {"id": "song-1", "content": "hello lyrics\n"}, {"id": "song-2", "content": "umbrella lyrics\n"}]) - self.assertIn("done: 2 songs exported", stderr) + self.assertIn("Done. 2 songs exported.", stderr) def test_preserves_non_ascii_lyrics(self) -> None: """Test that non-ASCII lyrics are written verbatim.""" @@ -291,7 +291,7 @@ class TestExportLlmInput(unittest.TestCase): self.__output) self.assertEqual( [x["id"] for x in records], ["song-1", "song-3"]) - self.assertIn("done: 2 songs exported", stderr) + self.assertIn("Done. 2 songs exported.", stderr) def test_extras_per_id_unknown_id_fails(self) -> None: """Test that a per-ID extras file naming a song the diff --git a/tools/tests/test_run_llm.py b/tools/tests/test_run_llm.py index 317008e..17ca47f 100644 --- a/tools/tests/test_run_llm.py +++ b/tools/tests/test_run_llm.py @@ -349,8 +349,10 @@ class TestMainFlow(RunLLMTestCase): status: int stdout: str stderr: str - status, stdout, stderr = self.__run_main( - self.__argv + ["--dry-run"]) + with mock.patch( + "time.monotonic", side_effect=[1000.0, 1125.0]): + status, stdout, stderr = self.__run_main( + self.__argv + ["--dry-run"]) self.assertEqual(status, 0) run_dir: Path = self.__archive_dir self.assertEqual((run_dir / "prompt.md").read_text( @@ -366,7 +368,8 @@ class TestMainFlow(RunLLMTestCase): self.assertEqual(request["custom_id"], "a") self.assertEqual(request["params"]["system"], "The task prompt.\n") - self.assertNotRegex(stderr, r"\d{2}:\d{2} elapsed\.") + self.assertTrue(stderr.rstrip("\n").endswith( + "Done. 2 jobs finished. 02:05 elapsed.")) def test_run_produces_output_file(self) -> None: """Test that a run submits one batch and writes output.""" @@ -394,8 +397,7 @@ class TestMainFlow(RunLLMTestCase): self.assertEqual(meta["usage"], {"input_tokens": 20, "output_tokens": 10}) self.assertTrue(stderr.rstrip("\n").endswith( - "done: 2 items; archived to" - f" {run_dir} 02:05 elapsed.")) + "Done. 2 jobs finished. 02:05 elapsed.")) def test_existing_archive_rejected_without_replace(self) -> None: """Test that an existing archive without --replace fails."""