From 81d0a9501017adfc79c21da8510f1fb778754fa1 Mon Sep 17 00:00:00 2001 From: Vineeth Sai Date: Sat, 13 Jun 2026 10:41:25 -0700 Subject: [PATCH] Handle an invalid plural index in msgstr[...] instead of raising ValueError read_po parsed the plural index of a `msgstr[N]` line with `int(idxarg[:-1])`, which leaked a bare `ValueError: invalid literal for int()` to the caller when N was not an integer (e.g. `msgstr[\x0c]`). Route a non-integer index through the parser's existing `_invalid_pofile` handling, so it raises a `PoFileError` when `abort_invalid=True` and otherwise warns and skips the line, consistent with other malformed input. Fixes #1209 Co-Authored-By: Claude Opus 4.8 (1M context) --- babel/messages/pofile.py | 6 +++++- tests/messages/test_pofile.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/babel/messages/pofile.py b/babel/messages/pofile.py index b9678a924..cb72cdc4e 100644 --- a/babel/messages/pofile.py +++ b/babel/messages/pofile.py @@ -276,7 +276,11 @@ def _process_keyword_line(self, lineno, line, obsolete=False) -> None: self.in_msgid = False self.in_msgstr = True kwarg, has_bracket, idxarg = keyword.partition('[') - idx = int(idxarg[:-1]) if has_bracket else 0 + try: + idx = int(idxarg[:-1]) if has_bracket else 0 + except ValueError: + self._invalid_pofile(line, lineno, f"Invalid plural index in keyword {keyword!r}") + return s = _NormalizedString(arg) if arg != '""' else _NormalizedString() self.translations.append([idx, s]) return diff --git a/tests/messages/test_pofile.py b/tests/messages/test_pofile.py index cdbb58262..547fd1631 100644 --- a/tests/messages/test_pofile.py +++ b/tests/messages/test_pofile.py @@ -160,3 +160,17 @@ def test_issue_1134(case: str, abort_invalid: bool): output = pofile.read_po(buf) assert len(output) == 1 assert output["foo"].string in ((''), ('', '')) + + +@pytest.mark.parametrize("abort_invalid", [False, True]) +def test_invalid_msgstr_index_issue_1209(abort_invalid: bool): + # Regression test for #1209: a non-integer plural index in msgstr[...] must be reported + # through the normal invalid-pofile handling, not leak a bare ValueError from int(). + buf = StringIO('msgstr[\x0c]') + + if abort_invalid: + with pytest.raises(pofile.PoFileError): + pofile.read_po(buf, abort_invalid=True) + else: + # No crash: an invalid entry is skipped with a warning. + pofile.read_po(buf)