summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2017-12-16 13:27:30 -0600
committerJason Madden <jamadden@gmail.com>2017-12-16 13:58:20 -0600
commitae0d55da5f686ca3ab4dae15719431531d495245 (patch)
treea7d2b1c36e93c3d60955833596e710df9c0a86f6
parent376b5438893ec6b3f456ceb166407bffeacc1b7d (diff)
downloadzope-i18n-ae0d55da5f686ca3ab4dae15719431531d495245.tar.gz
100% coverage for compile.py
-rw-r--r--src/zope/i18n/compile.py87
-rw-r--r--src/zope/i18n/tests/test_compile.py68
-rw-r--r--tox.ini2
3 files changed, 116 insertions, 41 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))
diff --git a/tox.ini b/tox.ini
index f9b40c5..c9086ca 100644
--- a/tox.ini
+++ b/tox.ini
@@ -16,7 +16,7 @@ basepython =
commands =
coverage run -m zope.testrunner --test-path=src []
coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest
- coverage report --fail-under=97
+ coverage report --fail-under=98
deps =
{[testenv]deps}
coverage