Merge ~cjwatson/launchpad:py3-parse-po-file-content-bytes into launchpad:master
- Git
- lp:~cjwatson/launchpad
- py3-parse-po-file-content-bytes
- Merge into 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) |
Related bugs: |
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
Description of the change
To post a comment you must log in.
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
1 | diff --git a/lib/lp/translations/interfaces/translationimporter.py b/lib/lp/translations/interfaces/translationimporter.py |
2 | index 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 | |
33 | diff --git a/lib/lp/translations/utilities/doc/gettext_po_parser.txt b/lib/lp/translations/utilities/doc/gettext_po_parser.txt |
34 | index 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" |
153 | diff --git a/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py b/lib/lp/translations/utilities/tests/test_gettext_mo_exporter.py |
154 | index 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) |
191 | diff --git a/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py b/lib/lp/translations/utilities/tests/test_gettext_po_exporter.py |
192 | index 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')) |
426 | diff --git a/lib/lp/translations/utilities/tests/test_gettext_po_parser.py b/lib/lp/translations/utilities/tests/test_gettext_po_parser.py |
427 | index 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" |
LGTM