Report the elapsed time when run-llm finishes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,7 @@ from typing import Any, Self
|
|||||||
import anthropic
|
import anthropic
|
||||||
|
|
||||||
from ..config import get_settings
|
from ..config import get_settings
|
||||||
|
from ..utils import format_duration
|
||||||
|
|
||||||
MODEL: str = "claude-sonnet-4-6"
|
MODEL: str = "claude-sonnet-4-6"
|
||||||
TEMPERATURE: float = 0.0
|
TEMPERATURE: float = 0.0
|
||||||
@@ -450,6 +451,7 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
:param argv: The command-line arguments, or None for ``sys.argv``.
|
:param argv: The command-line arguments, or None for ``sys.argv``.
|
||||||
:return: The exit status: 0 on success, non-zero on failure.
|
:return: The exit status: 0 on success, non-zero on failure.
|
||||||
"""
|
"""
|
||||||
|
started: float = time.monotonic()
|
||||||
args: argparse.Namespace = parse_args(argv)
|
args: argparse.Namespace = parse_args(argv)
|
||||||
try:
|
try:
|
||||||
items: list[InputItem] = load_items(args.input)
|
items: list[InputItem] = load_items(args.input)
|
||||||
@@ -504,6 +506,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
print(f"error: failed items: {', '.join(failed)}",
|
print(f"error: failed items: {', '.join(failed)}",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
elapsed: str = format_duration(time.monotonic() - started)
|
||||||
print(f"done: {len(items)} items;"
|
print(f"done: {len(items)} items;"
|
||||||
f" archived to {archive_dir}", file=sys.stderr)
|
f" archived to {archive_dir} {elapsed} elapsed.",
|
||||||
|
file=sys.stderr)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -326,13 +326,15 @@ class TestMainFlow(RunLLMTestCase):
|
|||||||
return client
|
return client
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __run_main(argv: list[str],
|
def __run_main(
|
||||||
client: mock.Mock | None = None) -> tuple[int, str]:
|
argv: list[str],
|
||||||
|
client: mock.Mock | None = None) -> tuple[int, str, str]:
|
||||||
"""Run main() with a mocked client and captured output.
|
"""Run main() with a mocked client and captured output.
|
||||||
|
|
||||||
:param argv: The command-line arguments.
|
:param argv: The command-line arguments.
|
||||||
:param client: The mock client, or None for dry runs.
|
:param client: The mock client, or None for dry runs.
|
||||||
:return: A tuple of the exit status and the standard output.
|
:return: A tuple of the exit status, the standard output,
|
||||||
|
and the standard error.
|
||||||
"""
|
"""
|
||||||
stdout: io.StringIO = io.StringIO()
|
stdout: io.StringIO = io.StringIO()
|
||||||
stderr: io.StringIO = io.StringIO()
|
stderr: io.StringIO = io.StringIO()
|
||||||
@@ -340,13 +342,14 @@ class TestMainFlow(RunLLMTestCase):
|
|||||||
return_value=client), \
|
return_value=client), \
|
||||||
redirect_stdout(stdout), redirect_stderr(stderr):
|
redirect_stdout(stdout), redirect_stderr(stderr):
|
||||||
status: int = run_llm.main(argv)
|
status: int = run_llm.main(argv)
|
||||||
return status, stdout.getvalue()
|
return status, stdout.getvalue(), stderr.getvalue()
|
||||||
|
|
||||||
def test_dry_run(self) -> None:
|
def test_dry_run(self) -> None:
|
||||||
"""Test the dry-run behavior."""
|
"""Test the dry-run behavior."""
|
||||||
status: int
|
status: int
|
||||||
stdout: str
|
stdout: str
|
||||||
status, stdout = self.__run_main(
|
stderr: str
|
||||||
|
status, stdout, stderr = self.__run_main(
|
||||||
self.__argv + ["--dry-run"])
|
self.__argv + ["--dry-run"])
|
||||||
self.assertEqual(status, 0)
|
self.assertEqual(status, 0)
|
||||||
run_dir: Path = self.__archive_dir
|
run_dir: Path = self.__archive_dir
|
||||||
@@ -363,13 +366,18 @@ class TestMainFlow(RunLLMTestCase):
|
|||||||
self.assertEqual(request["custom_id"], "a")
|
self.assertEqual(request["custom_id"], "a")
|
||||||
self.assertEqual(request["params"]["system"],
|
self.assertEqual(request["params"]["system"],
|
||||||
"The task prompt.\n")
|
"The task prompt.\n")
|
||||||
|
self.assertNotRegex(stderr, r"\d{2}:\d{2} elapsed\.")
|
||||||
|
|
||||||
def test_run_produces_output_file(self) -> None:
|
def test_run_produces_output_file(self) -> None:
|
||||||
"""Test that a run submits one batch and writes output."""
|
"""Test that a run submits one batch and writes output."""
|
||||||
client: mock.Mock = self.__make_client(
|
client: mock.Mock = self.__make_client(
|
||||||
[self._make_success_entry("a", "answer a"),
|
[self._make_success_entry("a", "answer a"),
|
||||||
self._make_success_entry("b", "answer b")])
|
self._make_success_entry("b", "answer b")])
|
||||||
status: int = self.__run_main(self.__argv, client)[0]
|
status: int
|
||||||
|
stderr: str
|
||||||
|
with mock.patch(
|
||||||
|
"time.monotonic", side_effect=[1000.0, 1125.0]):
|
||||||
|
status, _, stderr = self.__run_main(self.__argv, client)
|
||||||
self.assertEqual(status, 0)
|
self.assertEqual(status, 0)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
client.messages.batches.create.call_count, 1)
|
client.messages.batches.create.call_count, 1)
|
||||||
@@ -385,6 +393,9 @@ class TestMainFlow(RunLLMTestCase):
|
|||||||
self.assertEqual(meta["batch"]["batch_id"], "batch_run1")
|
self.assertEqual(meta["batch"]["batch_id"], "batch_run1")
|
||||||
self.assertEqual(meta["usage"],
|
self.assertEqual(meta["usage"],
|
||||||
{"input_tokens": 20, "output_tokens": 10})
|
{"input_tokens": 20, "output_tokens": 10})
|
||||||
|
self.assertTrue(stderr.rstrip("\n").endswith(
|
||||||
|
"done: 2 items; archived to"
|
||||||
|
f" {run_dir} 02:05 elapsed."))
|
||||||
|
|
||||||
def test_existing_archive_rejected_without_replace(self) -> None:
|
def test_existing_archive_rejected_without_replace(self) -> None:
|
||||||
"""Test that an existing archive without --replace fails."""
|
"""Test that an existing archive without --replace fails."""
|
||||||
|
|||||||
Reference in New Issue
Block a user