Files
computer-playbook/tests/unit/python/cli/build/i18n/test_main.py
T
kevinveenbirkenbachandClaude Opus 5 79fde0e0ba perf(i18n): run the cheap languages first and stop saturating the model
Every catalog got a lane derived from the CPU count, so twenty requests met one model instance. That is not throughput, it is self-inflicted saturation: a single catalog recorded 425 translated, 9 discarded and 40 requests refused with HTTP 503, and a discarded entry is simply left pending.

The work is now split by the backend that will answer it. The languages the engine serves keep the wide pool, because Argos answers in about 0.15s; the rest run after them with two lanes, one to occupy the model and one to refill it while the first writes back. Each pass builds its own client, so the chat pass does not inherit the worker count the engine pass was sized with.

Order is the larger half of this. The table is alphabetical, which is why the last run spent its first 45 minutes on af, a language with no Argos model, while fr and de sat untouched. Cost order delivers the engine languages first. For domain=docs that is 47 catalogs of 3963 entries each in roughly an hour; for domain=core it changes nothing today, because those catalogs are already translated.

The test picks aa against fr on purpose: both orders agree on every pair the fixtures held before, so a test built from them would have passed against the old single pass as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-18 12:49:04 +02:00

150 lines
5.2 KiB
Python

from __future__ import annotations
import contextlib
import importlib
import io
import json
import unittest
import unittest.mock as mock
from pathlib import Path
from tempfile import TemporaryDirectory
from utils.i18n.catalog import catalog_path, new_catalog, write_catalog
from utils.i18n.languages import LANGUAGES_FILE
from utils.i18n.libretranslate import SERVICE_KEY, SERVICES_FILE, Outcome
cli = importlib.import_module("cli.build.i18n.__main__")
LANGUAGES = """\
en: {name: English, native: English, direction: ltr}
de: {name: German, native: Deutsch, direction: ltr}
fr: {name: French, native: Français, direction: ltr}
zu: {name: Zulu, native: isiZulu, direction: ltr}
"""
SERVES = f"""\
{SERVICE_KEY}:
serves: [de, fr]
"""
def _catalog(root: Path, code: str, translation: str) -> None:
catalog = new_catalog("core", code)
catalog.add("Hello", translation, context="menu:x:title")
path = catalog_path(root, code, "core")
path.parent.mkdir(parents=True)
write_catalog(path, catalog)
def _checkout(case: unittest.TestCase) -> Path:
"""Return a checkout holding the language table and the engine's own coverage.
Args:
case: the test whose lifetime the temporary directory follows.
"""
tmp = TemporaryDirectory()
case.addCleanup(tmp.cleanup)
root = Path(tmp.name)
(root / LANGUAGES_FILE).parent.mkdir()
(root / LANGUAGES_FILE).write_text(LANGUAGES, encoding="utf-8")
(root / SERVICES_FILE).parent.mkdir(parents=True)
(root / SERVICES_FILE).write_text(SERVES, encoding="utf-8")
return root
class TestLanguages(unittest.TestCase):
def setUp(self) -> None:
self.root = _checkout(self)
def test_the_matrix_gets_every_language_the_table_names(self) -> None:
"""Not the one engine's coverage: the gateway falls through to a chat
backend that declares no catalogue, so a language outside
``serves`` is translated rather than skipped."""
with (
mock.patch.object(cli, "PROJECT_ROOT", self.root),
mock.patch("sys.stdout", new_callable=io.StringIO) as out,
):
status = cli.languages(["core"])
self.assertEqual(status, 0)
self.assertEqual(json.loads(out.getvalue()), ["de", "fr", "zu"])
class TestTranslate(unittest.TestCase):
def setUp(self) -> None:
self.root = _checkout(self)
_catalog(self.root, "de", "Hallo")
def _run(self, requested: list[str] | None = None) -> tuple[int, mock.Mock, mock.Mock]:
started = mock.Mock(return_value=contextlib.nullcontext("http://lt"))
client = mock.Mock()
client.return_value.translate.side_effect = lambda texts, code: Outcome(
["Bonjour"] * len(texts), 0, 0, ""
)
with (
mock.patch.object(cli, "PROJECT_ROOT", self.root),
mock.patch.object(cli, "server", started),
mock.patch.object(cli, "LibreTranslate", client),
):
return cli.translate(["core"], requested or []), started, client
def test_a_code_the_table_does_not_name_is_refused_before_any_deploy(self) -> None:
status, started, _client = self._run(["xx"])
self.assertEqual(status, 2)
started.assert_not_called()
def test_a_language_whose_catalog_is_not_extracted_yet_starts_nothing(self) -> None:
"""``zu`` is in the table and has no catalog on disk. Reading one would
raise, and refusing the language would drop it from the set the
repository promises to translate; it simply has nothing pending."""
status, started, _client = self._run()
self.assertEqual(status, 0)
started.assert_not_called()
def test_only_languages_with_pending_entries_are_awaited(self) -> None:
_catalog(self.root, "fr", "")
status, _started, client = self._run()
self.assertEqual(status, 0)
self.assertEqual(client.return_value.wait.call_args.args[0], ["fr"])
def test_the_engine_languages_are_translated_before_the_chat_ones(self) -> None:
"""A language the engine serves costs a fraction of a chat-served one.
Measured on this deployment, the engine answers in 0.15s and the chat
model in about 6s, so running the catalogs in the table's alphabetical
order spends hours on ``aa`` before it has delivered ``fr``. The
passes are also what bounds the chat lanes: one model instance
answered 40 requests of a single catalog with HTTP 503 when every
core got a lane.
"""
(self.root / LANGUAGES_FILE).write_text(
LANGUAGES + "aa: {name: Afar, native: Qafar, direction: ltr}\n",
encoding="utf-8",
)
_catalog(self.root, "aa", "")
_catalog(self.root, "fr", "")
seen: list[str] = []
with mock.patch.object(
cli, "one_catalog", lambda _client, _domain, code: seen.append(code)
):
status, _started, _client = self._run()
self.assertEqual(status, 0)
self.assertEqual(seen, ["fr", "aa"])
def test_nothing_pending_starts_no_container(self) -> None:
_catalog(self.root, "fr", "Bonjour")
status, started, _client = self._run()
self.assertEqual(status, 0)
started.assert_not_called()
if __name__ == "__main__":
unittest.main()