diff --git a/HACKING.rst b/HACKING.rst index a0595952cae..92765bc4d0d 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -12,6 +12,7 @@ Neutron Specific Commandments - [N321] Validate that jsonutils module is used instead of json - [N322] We do not use @authors tags in source files. We have git to track authorship. +- [N323] Enforce oslo.* namespace imports for oslo libraries Creating Unit Tests ------------------- diff --git a/neutron/hacking/checks.py b/neutron/hacking/checks.py index a170a0d4be8..610bb3961f3 100644 --- a/neutron/hacking/checks.py +++ b/neutron/hacking/checks.py @@ -37,6 +37,12 @@ author_tag_re = (re.compile("^\s*#\s*@?(a|A)uthor"), re.compile("^\.\.\s+moduleauthor::")) +oslo_namespace_imports_underscore = re.compile( + r"import[\s]+oslo_[^\s]+") +oslo_namespace_imports_from_underscore = re.compile( + r"from[\s]+oslo_[^\s]+[\s]+import[\s]+") + + def validate_log_translations(logical_line, physical_line, filename): # Translations are not required in the test directory if "neutron/tests" in filename: @@ -79,7 +85,21 @@ def no_author_tags(physical_line): return pos, "N322: Don't use author tags" +def check_oslo_namespace_imports(logical_line): + if re.match(oslo_namespace_imports_underscore, logical_line): + msg = ("N323: '%s' must be used instead of '%s'.") % ( + logical_line.replace('import', 'from').replace('_', ' import '), + logical_line) + yield(0, msg) + elif re.match(oslo_namespace_imports_from_underscore, logical_line): + msg = ("N323: '%s' must be used instead of '%s'.") % ( + logical_line.replace('_', '.'), + logical_line) + yield(0, msg) + + def factory(register): register(validate_log_translations) register(use_jsonutils) register(no_author_tags) + register(check_oslo_namespace_imports) diff --git a/neutron/tests/unit/test_hacking.py b/neutron/tests/unit/test_hacking.py index 895dbe91019..c8df48beea4 100644 --- a/neutron/tests/unit/test_hacking.py +++ b/neutron/tests/unit/test_hacking.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import testtools + from neutron.hacking import checks from neutron.tests import base @@ -79,3 +81,18 @@ class HackingTestCase(base.BaseTestCase): self.assertEqual(2, checks.no_author_tags("# author: pele")[0]) self.assertEqual(2, checks.no_author_tags("# Author: pele")[0]) self.assertEqual(3, checks.no_author_tags(".. moduleauthor:: pele")[0]) + + def test_check_oslo_namespace_imports(self): + def check(s, fail=True): + func = checks.check_oslo_namespace_imports + if fail: + self.assertIsInstance(next(func(s)), tuple) + else: + with testtools.ExpectedException(StopIteration): + next(func(s)) + + check('from oslo_utils import importutils') + check('import oslo_messaging') + check('from oslo.utils import importutils', fail=False) + check('from oslo import messaging', fail=False) + check('import oslo.messaging', fail=False)