Localized exception message hacking check

As per [1], this patch adds a new hacking check that verifies
raised exceptions don't use unlocalized string messages. This
patch also adds unit tests for the new check and enables
checks for neutron-lib itself (as per tox.ini).

Note: Perhaps this check better belongs in openstack-dev/hacking
but it seems we already have a number of more generic checks
in neutron. We can discuss that here need be.

NB: Without [1] this new hacking check fails when running pep8 on
neutron-lib.

[1] https://review.openstack.org/#/c/324374/

Change-Id: Ia13f190ec6843ab360d115871d345c4ddc302cc5
This commit is contained in:
Boden R
2016-06-03 13:32:03 -06:00
committed by Henry Gessau
parent b82347d535
commit ba717a08ec
4 changed files with 37 additions and 4 deletions

View File

@@ -19,3 +19,4 @@ Neutron Specific Commandments
- [N531] Validate that LOG messages, except debug ones, have translations
- [N532] Validate that LOG.warning is used instead of LOG.warn. The latter is deprecated.
- [N533] Validate that debug level logs are not translated
- [N534] Exception messages should be translated

View File

@@ -160,3 +160,4 @@ def factory(register):
register(translation_checks.validate_log_translations)
register(translation_checks.no_translate_debug_logs)
register(translation_checks.check_log_warn_deprecated)
register(translation_checks.check_raised_localized_exceptions)

View File

@@ -75,3 +75,18 @@ def no_translate_debug_logs(logical_line, filename):
for hint in _all_hints:
if logical_line.startswith("LOG.debug(%s(" % hint):
yield(0, "N533 Don't translate debug level logs")
def check_raised_localized_exceptions(logical_line, filename):
# NOTE(boden): tox.ini doesn't permit per check exclusion
if "/tests/" in filename:
return
logical_line = logical_line.strip()
raised_search = re.compile(
r"raise (?:\w*)\((.*)\)").match(logical_line)
if raised_search:
exception_msg = raised_search.groups()[0]
if exception_msg.startswith("\"") or exception_msg.startswith("\'"):
msg = "N534: Untranslated exception message."
yield (logical_line.index(exception_msg), msg)

View File

@@ -19,12 +19,12 @@ from neutron_lib.tests import _base as base
class HackingTestCase(base.BaseTestCase):
def assertLinePasses(self, func, line):
def assertLinePasses(self, func, *args):
with testtools.ExpectedException(StopIteration):
next(func(line))
next(func(*args))
def assertLineFails(self, func, line):
self.assertIsInstance(next(func(line)), tuple)
def assertLineFails(self, func, *args):
self.assertIsInstance(next(func(*args)), tuple)
def test_use_jsonutils(self):
def __get_msg(fun):
@@ -149,3 +149,19 @@ class HackingTestCase(base.BaseTestCase):
bad = "LOG.warn(_LW('i am deprecated!'))"
self.assertEqual(
1, len(list(tc.check_log_warn_deprecated(bad, 'f'))))
def test_check_localized_exception_messages(self):
f = tc.check_raised_localized_exceptions
self.assertLineFails(f, " raise KeyError('Error text')", '')
self.assertLineFails(f, ' raise KeyError("Error text")', '')
self.assertLinePasses(f, ' raise KeyError(_("Error text"))', '')
self.assertLinePasses(f, ' raise KeyError(_ERR("Error text"))', '')
self.assertLinePasses(f, " raise KeyError(translated_msg)", '')
self.assertLinePasses(f, '# raise KeyError("Not translated")', '')
self.assertLinePasses(f, 'print("raise KeyError("Not '
'translated")")', '')
def test_check_localized_exception_message_skip_tests(self):
f = tc.check_raised_localized_exceptions
self.assertLinePasses(f, "raise KeyError('Error text')",
'neutron_lib/tests/unit/mytest.py')