Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Lib/gettext.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,10 +407,21 @@ def _parse(self, fp):
elif lastk:
self._info[lastk] += '\n' + item
if k == 'content-type':
self._charset = v.split('charset=')[1]
try:
self._charset = v.split('charset=')[1]
except IndexError:
raise ValueError(
f"expected 'charset=' in Content-Type metadata in {filename}, got {v!r}"
) from None
elif k == 'plural-forms':
v = v.split(';')
plural = v[1].split('plural=')[1]
try:
plural = v[1].split('plural=')[1]
except IndexError:
raise ValueError(
f"expected ';' and 'plural=' in Plural-Forms metadata in {filename}, "
f"got {';'.join(v)!r}"
) from None
self.plural = c2py(plural)
# Note: we unconditionally convert both msgids and msgstrs to
# Unicode using the character encoding specified in the charset
Expand Down
65 changes: 65 additions & 0 deletions Lib/test/test_gettext.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import base64
import gettext
import sys
import unittest
import unittest.mock
from functools import partial
Expand Down Expand Up @@ -664,6 +665,70 @@ def test_ignore_comments_in_headers_issue36239(self):
t = gettext.GNUTranslations(fp)
self.assertEqual(t.info()["plural-forms"], "nplurals=2; plural=(n != 1);")

@property
def expected_filename(self):
if sys.platform == 'win32':
return r'xx\\LC_MESSAGES\\gettext.mo'
return 'xx/LC_MESSAGES/gettext.mo'

def test_raise_descriptive_error_for_incorrect_content_type(self):
with open(MOFILE, 'wb') as fp:
# below is msgfmt run on such a PO file:
# msgid ""
# msgstr ""
# "Content-Type: text/plain; charste=UTF-8\n"
fp.write(
b'\xde\x12\x04\x95\x00\x00\x00\x00\x01\x00\x00\x00\x1c\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00,\x00'
b'\x00\x00\x00\x00\x00\x008\x00\x00\x00(\x00\x00\x009\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00Content-Type: text/plain; charste=UTF-8\n\x00'
)
with self.assertRaisesRegex(
ValueError,
f"expected 'charset=' in Content-Type metadata in {self.expected_filename}, "
f"got 'text/plain; charste=UTF-8'"
):
with open(MOFILE, 'rb') as fp:
gettext.GNUTranslations(fp)

def test_raise_descriptive_error_for_incorrect_plural_forms(self):
with open(MOFILE, 'wb') as fp:
# below is msgfmt run on such a PO file:
# msgid ""
# msgstr ""
# "Plural-Forms: \n"
fp.write(
b'\xde\x12\x04\x95\x00\x00\x00\x00\x01\x00\x00\x00\x1c\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00,\x00'
b'\x00\x00\x00\x00\x00\x008\x00\x00\x00\x0f\x00\x00\x009\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x00Plural-Forms: \n\x00'
)
with self.assertRaisesRegex(
ValueError,
f"expected ';' and 'plural=' in Plural-Forms metadata in {self.expected_filename}, got ''",
):
with open(MOFILE, 'rb') as fp:
gettext.GNUTranslations(fp)


def test_raise_descriptive_error_for_incorrect_plural_forms_with_semicolon(self):
with open(MOFILE, 'wb') as fp:
# below is msgfmt run on such a PO file:
# msgid ""
# msgstr ""
# "Plural-Forms: nplurals=1; prulal=0;\n"
fp.write(
b'\xde\x12\x04\x95\x00\x00\x00\x00\x01\x00\x00\x00\x1c\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00,\x00'
b'\x00\x00\x00\x00\x00\x008\x00\x00\x00$\x00\x00\x009\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00Plural-Forms: nplurals=1; prulal=0;\n\x00'

)
with self.assertRaisesRegex(
ValueError,
f"expected ';' and 'plural=' in Plural-Forms metadata in {self.expected_filename}, "
"got 'nplurals=1; prulal=0;'"
):
with open(MOFILE, 'rb') as fp:
gettext.GNUTranslations(fp)


class UnicodeTranslationsTest(GettextBaseTest):
def setUp(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Gettext now raises descriptive ``ValueError``\s instead of ``IndexError``\s for
incorrect ``.mo`` files metadata.
Loading