diff options
author | Jason Madden <jamadden@gmail.com> | 2017-12-16 13:27:30 -0600 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2017-12-16 13:58:20 -0600 |
commit | ae0d55da5f686ca3ab4dae15719431531d495245 (patch) | |
tree | a7d2b1c36e93c3d60955833596e710df9c0a86f6 /src | |
parent | 376b5438893ec6b3f456ceb166407bffeacc1b7d (diff) | |
download | zope-i18n-ae0d55da5f686ca3ab4dae15719431531d495245.tar.gz |
100% coverage for compile.py
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/i18n/compile.py | 87 | ||||
-rw-r--r-- | src/zope/i18n/tests/test_compile.py | 68 |
2 files changed, 115 insertions, 40 deletions
diff --git a/src/zope/i18n/compile.py b/src/zope/i18n/compile.py index 88de796..e4f3be2 100644 --- a/src/zope/i18n/compile.py +++ b/src/zope/i18n/compile.py @@ -1,54 +1,61 @@ -from contextlib import closing + import logging -import os -from os.path import join -from stat import ST_MTIME +logger = logging.getLogger('zope.i18n') + +def _cannot_compile_mo_file(domain, lc_messages_path): + logger.critical("Unable to compile messages: Python `gettext` library missing.") + return -HAS_PYTHON_GETTEXT = True try: from pythongettext.msgfmt import Msgfmt from pythongettext.msgfmt import PoSyntaxError -except ImportError: +except ImportError: # pragma: no cover HAS_PYTHON_GETTEXT = False + compile_mo_file = _cannot_compile_mo_file +else: + from contextlib import closing + import os.path + from os.path import join -logger = logging.getLogger('zope.i18n') + HAS_PYTHON_GETTEXT = True + def _safe_mtime(path): + try: + return os.path.getmtime(path) + except (IOError, OSError): + return None -def compile_mo_file(domain, lc_messages_path): - """Creates or updates a mo file in the locales folder.""" - if not HAS_PYTHON_GETTEXT: - logger.critical("Unable to compile messages: Python `gettext` library missing.") - return + def compile_mo_file(domain, lc_messages_path): + """Creates or updates a mo file in the locales folder.""" - base = join(lc_messages_path, domain) - pofile = str(base + '.po') - mofile = str(base + '.mo') + base = join(lc_messages_path, domain) + pofile = str(base + '.po') + mofile = str(base + '.mo') - po_mtime = 0 - try: - po_mtime = os.stat(pofile)[ST_MTIME] - except (IOError, OSError): - return + po_mtime = _safe_mtime(pofile) + mo_mtime = _safe_mtime(mofile) if os.path.exists(mofile) else 0 - mo_mtime = 0 - if os.path.exists(mofile): - # Update mo file? - try: - mo_mtime = os.stat(mofile)[ST_MTIME] - except (IOError, OSError): + if po_mtime is None or mo_mtime is None: + logger.debug("Unable to access either %s (%s) or %s (%s)", + pofile, po_mtime, mofile, mo_mtime) return - if po_mtime > mo_mtime: - try: - # Msgfmt.getAsFile returns io.BytesIO on Python 3, and cStringIO.StringIO - # on Python 2; sadly StringIO isn't a proper context manager, so we have to - # wrap it with `closing`. Also, Msgfmt doesn't properly close a file - # it opens for reading if you pass the path, but it does if you pass - # the file. - with closing(Msgfmt(open(pofile, 'rb'), domain).getAsFile()) as mo: - with open(mofile, 'wb') as fd: - fd.write(mo.read()) - except PoSyntaxError as err: - logger.warning('Syntax error while compiling %s (%s).', pofile, err.msg) - except (IOError, OSError) as err: - logger.warning('Error while compiling %s (%s).', pofile, err) + if po_mtime > mo_mtime: + try: + # Msgfmt.getAsFile returns io.BytesIO on Python 3, and cStringIO.StringIO + # on Python 2; sadly StringIO isn't a proper context manager, so we have to + # wrap it with `closing`. Also, Msgfmt doesn't properly close a file + # it opens for reading if you pass the path, but it does if you pass + # the file. + with open(pofile, 'rb') as pofd: + with closing(Msgfmt(pofd, domain).getAsFile()) as mo: + with open(mofile, 'wb') as fd: + fd.write(mo.read()) + # For testing we return distinct values for each scenario + return True + except PoSyntaxError as err: + logger.warning('Syntax error while compiling %s (%s).', pofile, err.msg) + return 0 + except (IOError, OSError) as err: + logger.warning('Error while compiling %s (%s).', pofile, err) + return False diff --git a/src/zope/i18n/tests/test_compile.py b/src/zope/i18n/tests/test_compile.py new file mode 100644 index 0000000..4a09ee4 --- /dev/null +++ b/src/zope/i18n/tests/test_compile.py @@ -0,0 +1,68 @@ +############################################################################## +# +# Copyright (c) 2017 Zope Foundation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## + +import unittest + +from zope.i18n import compile + + +@unittest.skipUnless(compile.HAS_PYTHON_GETTEXT, + "Need python-gettext") +class TestCompile(unittest.TestCase): + + def test_non_existant_path(self): + + self.assertIsNone(compile.compile_mo_file('no_such_domain', '')) + + def test_po_exists_but_invalid(self): + import tempfile + import shutil + import os.path + + td = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, td) + + with open(os.path.join(td, "foo.po"), 'w') as f: + f.write("this should not compile") + + self.assertEqual( + 0, + compile.compile_mo_file('foo', td)) + + def test_po_exists_cannot_write_mo(self): + import tempfile + import shutil + import os + import os.path + + td = tempfile.mkdtemp(suffix=".zopei18n_test_compile") + self.addCleanup(shutil.rmtree, td) + + mofile = os.path.join(td, 'foo.mo') + with open(mofile, 'w') as f: + f.write("Touching") + + # Put it in the past, make it not writable + os.utime(mofile, (1000, 1000)) + os.chmod(mofile, 0) + + with open(os.path.join(td, "foo.po"), 'w') as f: + f.write("# A comment") + + self.assertIs( + False, + compile.compile_mo_file('foo', td)) + + def test_cannot_compile(self): + self.assertIsNone(compile._cannot_compile_mo_file(None, None)) |