"""Tests to cover the Tools/i18n package"""
import os
+import re
import sys
import unittest
from textwrap import dedent
+from pathlib import Path
from test.support.script_helper import assert_python_ok
from test.test_tools import skip_if_missing, toolsdir
skip_if_missing()
+DATA_DIR = Path(__file__).resolve().parent / 'i18n_data'
+
+
+def normalize_POT_file(pot):
+ """Normalize the POT creation timestamp, charset and
+ file locations to make the POT file easier to compare.
+
+ """
+ # Normalize the creation date.
+ date_pattern = re.compile(r'"POT-Creation-Date: .+?\\n"')
+ header = r'"POT-Creation-Date: 2000-01-01 00:00+0000\\n"'
+ pot = re.sub(date_pattern, header, pot)
+
+ # Normalize charset to UTF-8 (currently there's no way to specify the output charset).
+ charset_pattern = re.compile(r'"Content-Type: text/plain; charset=.+?\\n"')
+ charset = r'"Content-Type: text/plain; charset=UTF-8\\n"'
+ pot = re.sub(charset_pattern, charset, pot)
+
+ # Normalize file location path separators in case this test is
+ # running on Windows (which uses '\').
+ fileloc_pattern = re.compile(r'#:.+')
+
+ def replace(match):
+ return match[0].replace(os.sep, "/")
+ pot = re.sub(fileloc_pattern, replace, pot)
+ return pot
+
class Test_pygettext(unittest.TestCase):
"""Tests for the pygettext.py tool"""
- script = os.path.join(toolsdir,'i18n', 'pygettext.py')
+ script = Path(toolsdir, 'i18n', 'pygettext.py')
def get_header(self, data):
""" utility: return the header of a .po file as a dictionary """
headers = {}
for line in data.split('\n'):
- if not line or line.startswith(('#', 'msgid','msgstr')):
+ if not line or line.startswith(('#', 'msgid', 'msgstr')):
continue
line = line.strip('"')
- key, val = line.split(':',1)
+ key, val = line.split(':', 1)
headers[key] = val.strip()
return headers
return msgids
+ def assert_POT_equal(self, expected, actual):
+ """Check if two POT files are equal"""
+ self.maxDiff = None
+ self.assertEqual(normalize_POT_file(expected), normalize_POT_file(actual))
+
def extract_docstrings_from_str(self, module_content):
""" utility: return all msgids extracted from module_content """
filename = 'test_docstrings.py'
with temp_cwd(None) as cwd:
with open(filename, 'w', encoding='utf-8') as fp:
fp.write(module_content)
- assert_python_ok(self.script, '-D', filename)
+ assert_python_ok('-Xutf8', self.script, '-D', filename)
with open('messages.pot', encoding='utf-8') as fp:
data = fp.read()
return self.get_msgids(data)
http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry
"""
with temp_cwd(None) as cwd:
- assert_python_ok(self.script)
+ assert_python_ok('-Xutf8', self.script)
with open('messages.pot', encoding='utf-8') as fp:
data = fp.read()
header = self.get_header(data)
""" Match the date format from xgettext for POT-Creation-Date """
from datetime import datetime
with temp_cwd(None) as cwd:
- assert_python_ok(self.script)
+ assert_python_ok('-Xutf8', self.script)
with open('messages.pot', encoding='utf-8') as fp:
data = fp.read()
header = self.get_header(data)
self.assertNotIn('foo', msgids)
self.assertIn('bar', msgids)
+ def test_pygettext_output(self):
+ """Test that the pygettext output exactly matches snapshots."""
+ for input_file in DATA_DIR.glob('*.py'):
+ output_file = input_file.with_suffix('.pot')
+ with self.subTest(input_file=f'i18n_data/{input_file}'):
+ contents = input_file.read_text(encoding='utf-8')
+ with temp_cwd(None):
+ Path(input_file.name).write_text(contents)
+ assert_python_ok('-Xutf8', self.script, '--docstrings', input_file.name)
+ output = Path('messages.pot').read_text(encoding='utf-8')
+
+ expected = output_file.read_text(encoding='utf-8')
+ self.assert_POT_equal(expected, output)
+
def test_files_list(self):
"""Make sure the directories are inspected for source files
bpo-31920
text2 = 'Text to translate2'
text3 = 'Text to ignore'
with temp_cwd(None), temp_dir(None) as sdir:
- os.mkdir(os.path.join(sdir, 'pypkg'))
- with open(os.path.join(sdir, 'pypkg', 'pymod.py'), 'w',
- encoding='utf-8') as sfile:
- sfile.write(f'_({text1!r})')
- os.mkdir(os.path.join(sdir, 'pkg.py'))
- with open(os.path.join(sdir, 'pkg.py', 'pymod2.py'), 'w',
- encoding='utf-8') as sfile:
- sfile.write(f'_({text2!r})')
- os.mkdir(os.path.join(sdir, 'CVS'))
- with open(os.path.join(sdir, 'CVS', 'pymod3.py'), 'w',
- encoding='utf-8') as sfile:
- sfile.write(f'_({text3!r})')
- assert_python_ok(self.script, sdir)
- with open('messages.pot', encoding='utf-8') as fp:
- data = fp.read()
+ pymod = Path(sdir, 'pypkg', 'pymod.py')
+ pymod.parent.mkdir()
+ pymod.write_text(f'_({text1!r})', encoding='utf-8')
+
+ pymod2 = Path(sdir, 'pkg.py', 'pymod2.py')
+ pymod2.parent.mkdir()
+ pymod2.write_text(f'_({text2!r})', encoding='utf-8')
+
+ pymod3 = Path(sdir, 'CVS', 'pymod3.py')
+ pymod3.parent.mkdir()
+ pymod3.write_text(f'_({text3!r})', encoding='utf-8')
+
+ assert_python_ok('-Xutf8', self.script, sdir)
+ data = Path('messages.pot').read_text(encoding='utf-8')
self.assertIn(f'msgid "{text1}"', data)
self.assertIn(f'msgid "{text2}"', data)
self.assertNotIn(text3, data)
+
+
+def update_POT_snapshots():
+ for input_file in DATA_DIR.glob('*.py'):
+ output_file = input_file.with_suffix('.pot')
+ contents = input_file.read_bytes()
+ with temp_cwd(None):
+ Path(input_file.name).write_bytes(contents)
+ assert_python_ok('-Xutf8', Test_pygettext.script, '--docstrings', input_file.name)
+ output = Path('messages.pot').read_text(encoding='utf-8')
+
+ output = normalize_POT_file(output)
+ output_file.write_text(output, encoding='utf-8')
+
+
+if __name__ == '__main__':
+ # To regenerate POT files
+ if len(sys.argv) > 1 and sys.argv[1] == '--snapshot-update':
+ update_POT_snapshots()
+ sys.exit(0)
+ unittest.main()