Merge ~cjwatson/launchpad:py3-parse-po-file-content-bytes into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 07164c67e9629f1f05039d133c9f8f65b5dac406
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:py3-parse-po-file-content-bytes
Merge into: launchpad:master
Diff against target: 712 lines (+115/-134)
5 files modified
lib/lp/translations/interfaces/translationimporter.py (+4/-1)
lib/lp/translations/utilities/doc/gettext_po_parser.txt (+16/-16)
lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py (+8/-8)
lib/lp/translations/utilities/tests/test_gettext_po_exporter.py (+49/-74)
lib/lp/translations/utilities/tests/test_gettext_po_parser.py (+38/-35)
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+397817@code.launchpad.net

Commit message

Parse PO file content as bytes

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve
Revision history for this message
Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/translations/interfaces/translationimporter.py b/lib/lp/translations/interfaces/translationimporter.py
2index 7547050..10f3775 100644
3--- a/lib/lp/translations/interfaces/translationimporter.py
4+++ b/lib/lp/translations/interfaces/translationimporter.py
5@@ -15,6 +15,7 @@ __all__ = [
6 'TranslationFormatInvalidInputError',
7 ]
8
9+import six
10 from zope.interface import Interface
11 from zope.schema import (
12 Bool,
13@@ -83,9 +84,10 @@ class TranslationFormatBaseError(TranslationImportExportBaseException):
14 else:
15 text = default_message
16
17- return "%s%s" % (location_prefix, text)
18+ return u"%s%s" % (location_prefix, text)
19
20
21+@six.python_2_unicode_compatible
22 class TranslationFormatSyntaxError(TranslationFormatBaseError):
23 """A syntax error occurred while parsing a translation file."""
24
25@@ -93,6 +95,7 @@ class TranslationFormatSyntaxError(TranslationFormatBaseError):
26 return self.represent("Unknown syntax error")
27
28
29+@six.python_2_unicode_compatible
30 class TranslationFormatInvalidInputError(TranslationFormatBaseError):
31 """Some fields in the parsed file contain bad content."""
32
33diff --git a/lib/lp/translations/utilities/doc/gettext_po_parser.txt b/lib/lp/translations/utilities/doc/gettext_po_parser.txt
34index f2f63bb..8ce9e60 100644
35--- a/lib/lp/translations/utilities/doc/gettext_po_parser.txt
36+++ b/lib/lp/translations/utilities/doc/gettext_po_parser.txt
37@@ -14,7 +14,7 @@ The PO parser handles GNU gettext format human readable files.
38 PO files with empty headers are not allowed.
39
40 >>> parser = POParser()
41- >>> parser.parse('msgid "foo"\nmsgstr ""\n')
42+ >>> parser.parse(b'msgid "foo"\nmsgstr ""\n')
43 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
44 Traceback (most recent call last):
45 ...
46@@ -22,8 +22,8 @@ PO files with empty headers are not allowed.
47
48 PO files with context after msgids are reported as broken.
49
50- >>> parser.parse('msgid ""\nmsgstr ""\n'
51- ... 'msgid "blah"\nmsgctxt "foo"\nmsgstr "bar"\n')
52+ >>> parser.parse(b'msgid ""\nmsgstr ""\n'
53+ ... b'msgid "blah"\nmsgctxt "foo"\nmsgstr "bar"\n')
54 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
55 Traceback (most recent call last):
56 ...
57@@ -31,9 +31,9 @@ PO files with context after msgids are reported as broken.
58
59 And a msgctxt followed by msgctxt is caught as well.
60
61- >>> parser.parse('msgid ""\nmsgstr ""\n'
62- ... 'msgctxt "foo"\nmsgctxt "foo1"\n'
63- ... 'msgid "blah"\nmsgstr "bar"\n')
64+ >>> parser.parse(b'msgid ""\nmsgstr ""\n'
65+ ... b'msgctxt "foo"\nmsgctxt "foo1"\n'
66+ ... b'msgid "blah"\nmsgstr "bar"\n')
67 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
68 Traceback (most recent call last):
69 ...
70@@ -42,8 +42,8 @@ And a msgctxt followed by msgctxt is caught as well.
71 When a string is followed by non-string, non-space data, it is caught
72 as an error.
73
74- >>> parser.parse('msgid ""\nmsgstr "something"\n'
75- ... '"foo" whatever\n')
76+ >>> parser.parse(b'msgid ""\nmsgstr "something"\n'
77+ ... b'"foo" whatever\n')
78 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
79 Traceback (most recent call last):
80 ...
81@@ -51,7 +51,7 @@ as an error.
82
83 Unrecognized escape sequences are caught as well.
84
85- >>> parser.parse('msgid "\!"\nmsgstr ""\n')
86+ >>> parser.parse(b'msgid "\!"\nmsgstr ""\n')
87 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
88 Traceback (most recent call last):
89 ...
90@@ -59,7 +59,7 @@ Unrecognized escape sequences are caught as well.
91
92 Unclosed strings (missing closing quotes) are caught.
93
94- >>> parser.parse('msgid ""\nmsgstr "\n')
95+ >>> parser.parse(b'msgid ""\nmsgstr "\n')
96 ... # doctest: +IGNORE_EXCEPTION_MODULE_IN_PYTHON2
97 Traceback (most recent call last):
98 ...
99@@ -283,7 +283,7 @@ template.
100
101 Parsing a PO template:
102
103- >>> content = """
104+ >>> content = b"""
105 ... msgid ""
106 ... msgstr ""
107 ... "Project-Id-Version: Foobar 1.0\\n"
108@@ -312,7 +312,7 @@ PO templates, and other PO files that do not specify their encoding,
109 are parsed as UTF-8 text. If they contain non UTF-8 characters, parsing
110 errors occur:
111
112- >>> chunk2 = """
113+ >>> chunk2 = b"""
114 ... #:foo/bar.c:42
115 ... msgid "Bar"
116 ... msgstr "\xb5\x7b\xa6\xa1\xbf\xf9\xbb\x7e"
117@@ -338,7 +338,7 @@ may include backslashes inside multibyte sequences. These backslashes
118 must be interpreted as part of the character rather than as an escape
119 character.
120
121- >>> content = """
122+ >>> content = b"""
123 ... msgid ""
124 ... msgstr ""
125 ... "Last-Translator: \xb5\x7b\xa6\xa1\xbf\xf9\xbb\x7e\\n"
126@@ -384,7 +384,7 @@ which would cause problems if we naively use '\n' as a line separator.
127
128 Change the last PO file to use Mac-style newlines:
129
130- >>> content = content.replace('\n', '\r')
131+ >>> content = content.replace(b'\n', b'\r')
132
133 Verify that it still parses:
134
135@@ -401,7 +401,7 @@ them have special meaning like 'new line': '\n' or 'tabs' '\t' and others are
136 just the numeric representation of a character in the declared encoding by
137 the Content-Type field of the header.
138
139- >>> content = """
140+ >>> content = b"""
141 ... msgid ""
142 ... msgstr ""
143 ... "POT-Creation-Date: 2004-05-11 20:22+0800\\n"
144@@ -521,7 +521,7 @@ Let's parse a Spanish PO file with an inverted plural formula.
145
146 >>> spanish_pluralformula = 'n!=1'
147
148- >>> content = """
149+ >>> content = b"""
150 ... msgid ""
151 ... msgstr ""
152 ... "POT-Creation-Date: 2004-05-11 20:22+0800\\n"
153diff --git a/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py b/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py
154index b56970d..6a39c57 100644
155--- a/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py
156+++ b/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py
157@@ -33,7 +33,7 @@ class TestGettextMOExporter(TestCaseWithFactory):
158
159 msgid "foo"
160 msgstr "bar"
161- """))
162+ """).encode("UTF-8"))
163 file_data.is_template = is_template
164 file_data.language_code = 'my'
165 file_data.translation_domain = 'main'
166@@ -69,9 +69,9 @@ class TestGettextMOExporter(TestCaseWithFactory):
167 universal_newlines=False)
168
169 self.assertEqual(0, retval)
170- self.assertIn('MIME-Version', text)
171- self.assertIn('msgid', text)
172- self.assertIn('"foo"', text)
173+ self.assertIn(b'MIME-Version', text)
174+ self.assertIn(b'msgid', text)
175+ self.assertIn(b'"foo"', text)
176
177 def test_export_template_stays_pot(self):
178 # The MO exporter exports templates in their original POT
179@@ -85,7 +85,7 @@ class TestGettextMOExporter(TestCaseWithFactory):
180 self.assertEqual('application/x-po', output.content_type)
181 self.assertTrue(output.path.endswith('.pot'))
182 text = output.read()
183- self.assertIn('POT-Creation-Date:', text)
184- self.assertIn('MIME-Version:', text)
185- self.assertIn('msgid', text)
186- self.assertIn('"foo"', text)
187+ self.assertIn(b'POT-Creation-Date:', text)
188+ self.assertIn(b'MIME-Version:', text)
189+ self.assertIn(b'msgid', text)
190+ self.assertIn(b'"foo"', text)
191diff --git a/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py b/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py
192index 0a9a38a..7bf5479 100644
193--- a/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py
194+++ b/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py
195@@ -1,10 +1,13 @@
196 # Copyright 2009-2010 Canonical Ltd. This software is licensed under the
197 # GNU Affero General Public License version 3 (see the file LICENSE).
198
199+from __future__ import absolute_import, print_function, unicode_literals
200+
201 __metaclass__ = type
202
203 from textwrap import dedent
204
205+import six
206 from zope.interface.verify import verifyObject
207
208 from lp.services.helpers import test_diff
209@@ -43,12 +46,18 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
210 :param import_file: buffer with the source file content.
211 :param export_file: buffer with the output file content.
212 """
213- import_lines = [line for line in import_file.split('\n')]
214+ if import_file == export_file:
215+ return
216+
217+ import_lines = [
218+ six.ensure_text(line, errors='replace')
219+ for line in import_file.split(b'\n')]
220 # Remove X-Launchpad-Export-Date line to prevent time bombs in tests.
221 export_lines = [
222- line for line in export_file.split('\n')
223- if (not line.startswith('"X-Launchpad-Export-Date:') and
224- not line.startswith('"X-Generator: Launchpad'))]
225+ six.ensure_text(line, errors='replace')
226+ for line in export_file.split(b'\n')
227+ if (not line.startswith(b'"X-Launchpad-Export-Date:') and
228+ not line.startswith(b'"X-Generator: Launchpad'))]
229
230 line_pairs = zip(export_lines, import_lines)
231 debug_diff = test_diff(import_lines, export_lines)
232@@ -124,7 +133,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
233
234 #~ msgid "zot"
235 #~ msgstr "zat"
236- ''')
237+ ''').encode('UTF-8')
238 cy_translation_file = self.parser.parse(pofile_cy)
239 cy_translation_file.is_template = False
240 cy_translation_file.language_code = 'cy'
241@@ -159,7 +168,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
242 #| msgid "zog"
243 msgid "zig"
244 msgstr "zag"
245- ''')
246+ ''').encode('UTF-8')
247
248 pofile_eo_obsolete = dedent('''
249 msgid ""
250@@ -179,7 +188,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
251 #~| msgid "zog"
252 #~ msgid "zig"
253 #~ msgstr "zag"
254- ''')
255+ ''').encode('UTF-8')
256 eo_translation_file = self.parser.parse(pofile_eo)
257 eo_translation_file.is_template = False
258 eo_translation_file.language_code = 'eo'
259@@ -220,64 +229,30 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
260 self._compareImportAndExport(
261 pofile.strip(), storage.export().read().strip())
262
263- # File representing the same PO file three times. Each is identical
264- # except for the charset declaration in the header.
265- pofiles = [
266- dedent('''
267- msgid ""
268- msgstr ""
269- "Project-Id-Version: foo\\n"
270- "Report-Msgid-Bugs-To: \\n"
271- "POT-Creation-Date: 2007-07-09 03:39+0100\\n"
272- "PO-Revision-Date: 2001-09-09 01:46+0000\\n"
273- "Last-Translator: Kubla Kahn <kk@pleasure-dome.com>\\n"
274- "Language-Team: LANGUAGE <LL@li.org>\\n"
275- "MIME-Version: 1.0\\n"
276- "Content-Type: text/plain; charset=UTF-8\\n"
277- "Content-Transfer-Encoding: 8bit\\n"
278-
279- msgid "Japanese"
280- msgstr "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
281- '''),
282- dedent('''
283- msgid ""
284- msgstr ""
285- "Project-Id-Version: foo\\n"
286- "Report-Msgid-Bugs-To: \\n"
287- "POT-Creation-Date: 2007-07-09 03:39+0100\\n"
288- "PO-Revision-Date: 2001-09-09 01:46+0000\\n"
289- "Last-Translator: Kubla Kahn <kk@pleasure-dome.com>\\n"
290- "Language-Team: LANGUAGE <LL@li.org>\\n"
291- "MIME-Version: 1.0\\n"
292- "Content-Type: text/plain; charset=Shift-JIS\\n"
293- "Content-Transfer-Encoding: 8bit\\n"
294-
295- msgid "Japanese"
296- msgstr "\x93\xfa\x96\x7b\x8c\xea"
297- '''),
298- dedent('''
299- msgid ""
300- msgstr ""
301- "Project-Id-Version: foo\\n"
302- "Report-Msgid-Bugs-To: \\n"
303- "POT-Creation-Date: 2007-07-09 03:39+0100\\n"
304- "PO-Revision-Date: 2001-09-09 01:46+0000\\n"
305- "Last-Translator: Kubla Kahn <kk@pleasure-dome.com>\\n"
306- "Language-Team: LANGUAGE <LL@li.org>\\n"
307- "MIME-Version: 1.0\\n"
308- "Content-Type: text/plain; charset=EUC-JP\\n"
309- "Content-Transfer-Encoding: 8bit\\n"
310-
311- msgid "Japanese"
312- msgstr "\xc6\xfc\xcb\xdc\xb8\xec"
313- '''),
314- ]
315- for pofile in pofiles:
316+ pofile_content = dedent('''
317+ msgid ""
318+ msgstr ""
319+ "Project-Id-Version: foo\\n"
320+ "Report-Msgid-Bugs-To: \\n"
321+ "POT-Creation-Date: 2007-07-09 03:39+0100\\n"
322+ "PO-Revision-Date: 2001-09-09 01:46+0000\\n"
323+ "Last-Translator: Kubla Kahn <kk@pleasure-dome.com>\\n"
324+ "Language-Team: LANGUAGE <LL@li.org>\\n"
325+ "MIME-Version: 1.0\\n"
326+ "Content-Type: text/plain; charset=%(charset)s\\n"
327+ "Content-Transfer-Encoding: 8bit\\n"
328+
329+ msgid "Japanese"
330+ msgstr "\u65e5\u672c\u8a9e"
331+ ''')
332+ for charset in ('UTF-8', 'Shift-JIS', 'EUC-JP'):
333+ pofile = (pofile_content % {'charset': charset}).encode(charset)
334 compare(self, pofile)
335
336 def _testBrokenEncoding(self, pofile_content):
337 translation_file = self.parser.parse(
338- pofile_content % {'charset': 'ISO-8859-15', 'special': '\xe1'})
339+ (pofile_content %
340+ {'charset': 'ISO-8859-15'}).encode('ISO-8859-15'))
341 translation_file.is_template = False
342 translation_file.language_code = 'es'
343 translation_file.path = 'po/es.po'
344@@ -291,8 +266,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
345 translation_file, storage)
346
347 self._compareImportAndExport(
348- pofile_content.strip() % {
349- 'charset': 'UTF-8', 'special': '\xc3\xa1'},
350+ (pofile_content.strip() % {'charset': 'UTF-8'}).encode('UTF-8'),
351 storage.export().read().strip())
352
353 def testBrokenEncodingExport(self):
354@@ -317,7 +291,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
355 "Content-Transfer-Encoding: 8bit\\n"
356
357 msgid "a"
358- msgstr "%(special)s"
359+ msgstr "\xe1"
360 ''')
361 self._testBrokenEncoding(pofile_content)
362
363@@ -339,7 +313,7 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
364 "Report-Msgid-Bugs-To: \\n"
365 "POT-Creation-Date: 2007-07-09 03:39+0100\\n"
366 "PO-Revision-Date: 2001-09-09 01:46+0000\\n"
367- "Last-Translator: Kubla K%(special)shn <kk@pleasure-dome.com>\\n"
368+ "Last-Translator: Kubla K\xe1hn <kk@pleasure-dome.com>\\n"
369 "Language-Team: LANGUAGE <LL@li.org>\\n"
370 "MIME-Version: 1.0\\n"
371 "Content-Type: text/plain; charset=%(charset)s\\n"
372@@ -369,9 +343,9 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
373
374 msgid "1 dead horse"
375 msgid_plural "%%d dead horses"
376- msgstr[0] "ning\xc3\xban caballo muerto"
377+ msgstr[0] "ning\xfan caballo muerto"
378 %s''')
379- translation_file = self.parser.parse(pofile % (''))
380+ translation_file = self.parser.parse((pofile % '').encode('UTF-8'))
381 translation_file.is_template = False
382 translation_file.language_code = 'es'
383 translation_file.path = 'po/es.po'
384@@ -381,7 +355,8 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
385 translation_file, storage)
386
387 self._compareImportAndExport(
388- pofile.strip() % 'msgstr[1] ""', storage.export().read().strip())
389+ (pofile.strip() % 'msgstr[1] ""').encode('UTF-8'),
390+ storage.export().read().strip())
391
392 def testClashingSingularMsgIds(self):
393 # We don't accept it in gettext imports directly, since it's not
394@@ -404,9 +379,9 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
395 msgid_plural "%d foos"
396 msgstr[0] ""
397 msgstr[1] ""
398- """).strip()
399+ """).strip().encode('UTF-8')
400
401- body = exported_file.split('\n\n', 1)[1].strip()
402+ body = exported_file.split(b'\n\n', 1)[1].strip()
403 self.assertEqual(body, expected_output)
404
405 def testObsoleteMessageYieldsToNonObsoleteClashingOne(self):
406@@ -442,9 +417,9 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
407 msgid_plural "%d gooim"
408 msgstr[0] "%d gargl"
409 msgstr[1] "%d garglii"
410- """).strip()
411+ """).strip().encode('UTF-8')
412
413- body = exported_file.split('\n\n', 1)[1].strip()
414+ body = exported_file.split(b'\n\n', 1)[1].strip()
415 self.assertEqual(expected_output, body)
416
417 def test_strip_last_newline(self):
418@@ -489,5 +464,5 @@ class GettextPOExporterTestCase(TestCaseWithFactory):
419 # Exporting an empty gettext file does not break the exporter.
420 # The output does contain one message: the header.
421 output = self.factory.makePOFile('nl').export()
422- self.assertTrue(output.startswith('# Dutch translation for '))
423- self.assertEqual(1, output.count('msgid'))
424+ self.assertTrue(output.startswith(b'# Dutch translation for '))
425+ self.assertEqual(1, output.count(b'msgid'))
426diff --git a/lib/lp/translations/utilities/tests/test_gettext_po_parser.py b/lib/lp/translations/utilities/tests/test_gettext_po_parser.py
427index 0ea27cd..ad3619e 100644
428--- a/lib/lp/translations/utilities/tests/test_gettext_po_parser.py
429+++ b/lib/lp/translations/utilities/tests/test_gettext_po_parser.py
430@@ -27,15 +27,18 @@ class POBasicTestCase(unittest.TestCase):
431 def setUp(self):
432 self.parser = gettext_po_parser.POParser()
433
434+ def parse(self, content_text):
435+ return self.parser.parse(content_text.encode('ASCII'))
436+
437 def testEmptyFile(self):
438 # The parser reports an empty file as an error.
439- self.assertRaises(TranslationFormatSyntaxError, self.parser.parse, '')
440+ self.assertRaises(TranslationFormatSyntaxError, self.parse, '')
441
442 def testEmptyFileError(self):
443 # Trying to import an empty file produces a sensible error
444 # message.
445 try:
446- self.parser.parse('')
447+ self.parse('')
448 self.assertTrue(
449 False,
450 "Importing an empty file succeeded; it should have failed.")
451@@ -48,10 +51,10 @@ class POBasicTestCase(unittest.TestCase):
452 # The parser reports a non-empty file holding no messages as an
453 # error.
454 self.assertRaises(
455- TranslationFormatSyntaxError, self.parser.parse, '# Comment')
456+ TranslationFormatSyntaxError, self.parse, '# Comment')
457
458 def testSingular(self):
459- translation_file = self.parser.parse(
460+ translation_file = self.parse(
461 '%smsgid "foo"\nmsgstr "bar"\n' % DEFAULT_HEADER)
462 messages = translation_file.messages
463 self.assertEqual(len(messages), 1, "incorrect number of messages")
464@@ -63,7 +66,7 @@ class POBasicTestCase(unittest.TestCase):
465
466 def testNoNewLine(self):
467 # note, no trailing newline; this raises a warning
468- translation_file = self.parser.parse(
469+ translation_file = self.parse(
470 '%smsgid "foo"\nmsgstr "bar"' % DEFAULT_HEADER)
471 messages = translation_file.messages
472 self.assertEqual(messages[0].msgid_singular, "foo", "incorrect msgid")
473@@ -73,37 +76,37 @@ class POBasicTestCase(unittest.TestCase):
474
475 def testMissingQuote(self):
476 self.assertRaises(
477- TranslationFormatSyntaxError, self.parser.parse,
478+ TranslationFormatSyntaxError, self.parse,
479 '%smsgid "foo"\nmsgstr "bar' % DEFAULT_HEADER)
480
481 def testBadNewline(self):
482 self.assertRaises(
483- TranslationFormatSyntaxError, self.parser.parse,
484+ TranslationFormatSyntaxError, self.parse,
485 '%smsgid "foo\n"\nmsgstr "bar"\n' % DEFAULT_HEADER)
486
487 def testBadBackslash(self):
488 self.assertRaises(
489- TranslationFormatSyntaxError, self.parser.parse,
490+ TranslationFormatSyntaxError, self.parse,
491 '%smsgid "foo\\"\nmsgstr "bar"\n' % DEFAULT_HEADER)
492
493 def testMissingMsgstr(self):
494 self.assertRaises(
495- TranslationFormatSyntaxError, self.parser.parse,
496+ TranslationFormatSyntaxError, self.parse,
497 '%smsgid "foo"\n' % DEFAULT_HEADER)
498
499 def testMissingMsgid1(self):
500 self.assertRaises(
501- TranslationFormatSyntaxError, self.parser.parse,
502+ TranslationFormatSyntaxError, self.parse,
503 '%smsgid_plural "foos"\n' % DEFAULT_HEADER)
504
505 def testFuzzy(self):
506- translation_file = self.parser.parse(
507+ translation_file = self.parse(
508 '%s#, fuzzy\nmsgid "foo"\nmsgstr "bar"\n' % DEFAULT_HEADER)
509 messages = translation_file.messages
510 assert 'fuzzy' in messages[0].flags, "missing fuzziness"
511
512 def testComment(self):
513- translation_file = self.parser.parse('''
514+ translation_file = self.parse('''
515 %s
516 #. foo/bar.baz\n
517 # cake not drugs\n
518@@ -117,7 +120,7 @@ class POBasicTestCase(unittest.TestCase):
519 assert 'fuzzy' not in messages[0].flags, "incorrect fuzziness"
520
521 def testEscape(self):
522- translation_file = self.parser.parse(
523+ translation_file = self.parse(
524 '%smsgid "foo\\"bar\\nbaz\\\\xyzzy"\nmsgstr"z"\n' % (
525 DEFAULT_HEADER))
526 messages = translation_file.messages
527@@ -127,11 +130,11 @@ class POBasicTestCase(unittest.TestCase):
528 # def badEscapeTest(self):
529 #
530 # self.assertRaises(
531- # TranslationFormatSyntaxError, self.parser.parse,
532+ # TranslationFormatSyntaxError, self.parse,
533 # 'msgid "foo\."\nmsgstr "bar"\n')
534
535 def testPlural(self):
536- translation_file = self.parser.parse('''
537+ translation_file = self.parse('''
538 %s"Plural-Forms: nplurals=2; plural=foo;\\n"
539
540 msgid "foo"
541@@ -161,7 +164,7 @@ class POBasicTestCase(unittest.TestCase):
542 msgid_plural "%%d bottles of beer on the wall"
543 msgstr[zero] = "%%d flessen"''' % DEFAULT_HEADER
544 self.assertRaises(
545- TranslationFormatSyntaxError, self.parser.parse, content)
546+ TranslationFormatSyntaxError, self.parse, content)
547
548 def testNegativePluralCase(self):
549 # If a msgid's plural case number is negative, that's a syntax
550@@ -173,7 +176,7 @@ class POBasicTestCase(unittest.TestCase):
551 msgid_plural "%%d ts"
552 msgstr[-1] "%%d bs"''' % DEFAULT_HEADER
553 self.assertRaises(
554- TranslationFormatSyntaxError, self.parser.parse, content)
555+ TranslationFormatSyntaxError, self.parse, content)
556
557 def testUnsupportedPluralCase(self):
558 # If a msgid's plural case number isn't lower than the maximum
559@@ -187,10 +190,10 @@ class POBasicTestCase(unittest.TestCase):
560 msgstr[%d] "%%d bs"''' % (
561 DEFAULT_HEADER, TranslationConstants.MAX_PLURAL_FORMS)
562 self.assertRaises(
563- TranslationFormatSyntaxError, self.parser.parse, content)
564+ TranslationFormatSyntaxError, self.parse, content)
565
566 def testObsolete(self):
567- translation_file = self.parser.parse(
568+ translation_file = self.parse(
569 '%s#, fuzzy\n#~ msgid "foo"\n#~ msgstr "bar"\n' % DEFAULT_HEADER)
570 messages = translation_file.messages
571 self.assertEqual(messages[0].msgid_singular, "foo", "incorrect msgid")
572@@ -203,7 +206,7 @@ class POBasicTestCase(unittest.TestCase):
573 def testObsoleteChangedMsgid(self):
574 # Test "previous msgid" feature in obsolete messages. These are
575 # marked with "#~|"
576- translation_file = self.parser.parse("""
577+ translation_file = self.parse("""
578 %s
579
580 #~| msgid "old"
581@@ -216,7 +219,7 @@ class POBasicTestCase(unittest.TestCase):
582 self.assertEqual(messages[0].translations, ["nouveau"])
583
584 def testMultiLineObsolete(self):
585- translation_file = self.parser.parse(
586+ translation_file = self.parse(
587 '%s#~ msgid "foo"\n#~ msgstr ""\n#~ "bar"\n' % DEFAULT_HEADER)
588 messages = translation_file.messages
589 self.assertEqual(messages[0].msgid_singular, "foo")
590@@ -226,7 +229,7 @@ class POBasicTestCase(unittest.TestCase):
591
592 def testDuplicateMsgid(self):
593 self.assertRaises(
594- TranslationFormatInvalidInputError, self.parser.parse,
595+ TranslationFormatInvalidInputError, self.parse,
596 '''
597 %s
598 msgid "foo"
599@@ -238,7 +241,7 @@ class POBasicTestCase(unittest.TestCase):
600
601 def testRedundantMsgstr(self):
602 self.assertRaises(
603- TranslationFormatSyntaxError, self.parser.parse,
604+ TranslationFormatSyntaxError, self.parse,
605 '''
606 %s
607 msgid "foo"
608@@ -248,7 +251,7 @@ class POBasicTestCase(unittest.TestCase):
609
610 def testRedundantPlural(self):
611 self.assertRaises(
612- TranslationFormatSyntaxError, self.parser.parse,
613+ TranslationFormatSyntaxError, self.parse,
614 '''
615 %s
616 msgid "%%d foo"
617@@ -260,7 +263,7 @@ class POBasicTestCase(unittest.TestCase):
618
619 def testSquareBracketAndPlural(self):
620 try:
621- self.parser.parse('''
622+ self.parse('''
623 %s
624 msgid "foo %%d"
625 msgid_plural "foos %%d"
626@@ -274,14 +277,14 @@ class POBasicTestCase(unittest.TestCase):
627 # DEFAULT_HEADER already contains a msgid and one msgstr
628 # declaring ASCII encoding. Adding a second msgstr with a
629 # different text is an error.
630- self.assertRaises(TranslationFormatSyntaxError, self.parser.parse,
631+ self.assertRaises(TranslationFormatSyntaxError, self.parse,
632 '''
633 %s
634 msgstr "Content-Type: text/plain; charset=UTF-8\\n
635 ''' % DEFAULT_HEADER)
636
637 def testUpdateHeader(self):
638- translation_file = self.parser.parse(
639+ translation_file = self.parse(
640 'msgid ""\nmsgstr "foo: bar\\n"\n')
641 translation_file.header.number_plurals = 2
642 translation_file.header.plural_form_expression = 'random()'
643@@ -328,14 +331,14 @@ class POBasicTestCase(unittest.TestCase):
644 msgid "foo"
645 msgstr "barf"
646 """ % DEFAULT_HEADER
647- translation_file = self.parser.parse(easy_string)
648+ translation_file = self.parse(easy_string)
649
650 # If we add an escaped newline, this breaks with a syntax error.
651 (hard_string, changes) = re.subn("barf", "bar\\\nf", easy_string)
652 self.assertEqual(changes, 1,
653 "Failed to add 1 escaped newline to test string.")
654
655- translation_file = self.parser.parse(hard_string)
656+ translation_file = self.parse(hard_string)
657 messages = translation_file.messages
658 self.assertEqual(len(messages), 1, "Expected exactly 1 message.")
659 self.assertEqual(
660@@ -345,7 +348,7 @@ class POBasicTestCase(unittest.TestCase):
661 # Test escaped newlines at beginning and end of string, and check for
662 # interaction with multiple strings on a line.
663 hard_string = re.sub("barf", "\\\nb" "a\\\nr\\\nf\\\n", easy_string)
664- translation_file = self.parser.parse(hard_string)
665+ translation_file = self.parse(hard_string)
666 messages = translation_file.messages
667 self.assertEqual(
668 messages[0].translations[TranslationConstants.SINGULAR_FORM],
669@@ -354,7 +357,7 @@ class POBasicTestCase(unittest.TestCase):
670 # After an escaped newline, any indentation on the continued line is
671 # removed.
672 hard_string = re.sub("barf", "bar\\\n f", easy_string)
673- translation_file = self.parser.parse(hard_string)
674+ translation_file = self.parse(hard_string)
675 messages = translation_file.messages
676 self.assertEqual(
677 messages[0].translations[TranslationConstants.SINGULAR_FORM],
678@@ -363,7 +366,7 @@ class POBasicTestCase(unittest.TestCase):
679 # Escaped newlines inside a string do not interfere with the ability
680 # to continue the string on the next line.
681 hard_string = re.sub("barf", 'b\\\n"\n"arf', easy_string)
682- translation_file = self.parser.parse(hard_string)
683+ translation_file = self.parse(hard_string)
684 messages = translation_file.messages
685 self.assertEqual(
686 messages[0].translations[TranslationConstants.SINGULAR_FORM],
687@@ -385,7 +388,7 @@ class POBasicTestCase(unittest.TestCase):
688 break up long strings into multiple lines in the PO file.
689 """
690 foos = 9
691- translation_file = self.parser.parse('''
692+ translation_file = self.parse('''
693 %s
694 msgid "foo1"
695 msgstr ""
696@@ -429,14 +432,14 @@ class POBasicTestCase(unittest.TestCase):
697
698 def testGetLastTranslator(self):
699 """Tests whether we extract last translator information correctly."""
700- template_file = self.parser.parse(DEFAULT_HEADER)
701+ template_file = self.parse(DEFAULT_HEADER)
702 # When it's the default one in Gettext (FULL NAME <EMAIL@ADDRESS>),
703 # used in templates, we get a tuple with None values.
704 name, email = template_file.header.getLastTranslator()
705 self.assertIsNone(name, "Didn't detect default Last Translator name")
706 self.assertIsNone(email, "Didn't detect default Last Translator email")
707
708- translation_file = self.parser.parse('''
709+ translation_file = self.parse('''
710 msgid ""
711 msgstr ""
712 "Last-Translator: Carlos Perello Marin <carlos@canonical.com>\\n"

Subscribers

People subscribed via source and target branches

to status/vote changes: