From d1a5ea03c28f0da5651c3432072396d1ea6195ba Mon Sep 17 00:00:00 2001 From: Boden R Date: Wed, 7 Dec 2016 14:11:33 -0700 Subject: [PATCH] Separate hacking check factories Neutron-lib adopters should be using neutron-lib's hacking checks (factory) to validate compliance, but are susceptible to breakage when new checks are released in neutron-lib (see partial bug). What we need is a way to roll-out adopter hacking checks in a controlled manner, giving consumers the opportunity and tools to comply with new checks. This patch begins to address this need by: - Separating neutron-lib hacking checks into 3 separate factories; adopter, incubating and neutron-lib internal (private). - Moving any existing checks into their respective factory. - Updating the usage docs on how to adopt our hacking checks. - Trusty ole unit test; for obvious reasons. This patch plays a part in a longer term hacking check strategy: - Adopters must run neutron-lib's hacking check factory() or its equivalent via their pep8 checks. This is part of their pep8 gate job once they update their tox.ini to use neutron's factory(). - Adopters must run a non-voting neutron-lib-pep8-incubating gate job that runs pep8 with neutron-lib's incubating_factory(). This is means to warn adopters of upcoming checks without failing their gates. This job will be created (by me) assuming reviewers agree to this approach. - We'll communicate hacking checks via the standard means (see usage docs herein). Closure of Bug #1609478 will follow completion of the strategy above. Partial-Bug: #1609478 Change-Id: I5b8d5c41f1bf463109baf9c26ae9d9db5719097d --- doc/source/usage.rst | 54 +++++++++++++++++++ neutron_lib/hacking/checks.py | 41 ++++++++++++-- neutron_lib/tests/unit/hacking/test_checks.py | 37 +++++++++++-- ...te-hacking-factories-6fc36b38de95662a.yaml | 7 +++ tox.ini | 2 +- 5 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 releasenotes/notes/separate-hacking-factories-6fc36b38de95662a.yaml diff --git a/doc/source/usage.rst b/doc/source/usage.rst index 2237659b8..9498d7d08 100644 --- a/doc/source/usage.rst +++ b/doc/source/usage.rst @@ -5,3 +5,57 @@ Usage To use neutron-lib in a project:: import neutron_lib + + +Hacking Checks +-------------- + +The ``neutron_lib.hacking`` package implements a number of public +`hacking checks `_ intended to help +adopters validate their compliance with the latest hacking standards. + +To adopt neutron-lib's hacking checks: + +#. Update your project's ``tox.ini`` to use + ``neutron_lib.hacking.checks.factory`` for its ``local-check-factory``. + + For example in your ``tox.ini``:: + + [hacking] + local-check-factory = neutron_lib.hacking.checks.factory + + If your project needs to register additional project specific hacking + checks, you can define your own factory function that calls neutron-lib's + ``factory`` function. + + For example in your project's python source:: + + def my_factory(register): + # register neutron-lib checks + neutron_lib_checks.factory(register) + # register project specific checks + register(my_project_check) + + And use your project's own factory in ``tox.ini``:: + + [hacking] + local-check-factory = myproject.mypkg.my_factory + +#. Actively adopt neutron-lib hacking checks that are incubating and will + soon become adopter checks by manually running the checks on your project. + This can be done by modifying your ``tox.ini`` to use the + ``incubating_factory`` in neutron-lib:: + + [hacking] + local-check-factory = neutron_lib.hacking.checks.incubating_factory + + And then manually running pep8 on your project:: + + tox -e pep8 + + New adopter hacking checks in neutron-lib will be registered via the + ``incubating_factory`` while sub-projects are adopting the new check(s) + and then be moved out of incubating and into ``factory``. Announcements + regarding neutron-lib adopter hacking checks will be communicated via + openstack-dev email list and `neutron meetings + `_. diff --git a/neutron_lib/hacking/checks.py b/neutron_lib/hacking/checks.py index 174c93ed3..6d6d0b962 100644 --- a/neutron_lib/hacking/checks.py +++ b/neutron_lib/hacking/checks.py @@ -224,6 +224,14 @@ def check_no_eventlet_imports(logical_line): def factory(register): + """Hacking check factory for neutron-lib adopter compliant checks. + + Hacking check factory for use with tox.ini. This factory registers all + neutron-lib adopter checks consumers should seek to comply with. + + :param register: The function to register the check functions with. + :returns: None. + """ register(use_jsonutils) register(check_no_contextlib_nested) register(check_python3_xrange) @@ -231,11 +239,36 @@ def factory(register): register(check_python3_no_iteritems) register(no_mutable_default_args) register(check_neutron_namespace_imports) - # TODO(boden) - uncomment this after 0.4.0 ships - # register(check_no_eventlet_imports) 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) - # TODO(boden) - uncomment this after 0.4.0 ships - # register(translation_checks.check_delayed_string_interpolation) + + +def incubating_factory(register): + """Hacking check factory for neutron-lib incubating checks. + + Hacking check factory for use with tox.ini. This factory registers all + neutron-lib incubating checks. Each incubating check will become an adopter + check after undergoing an incubation period. + + :param register: The function to register the check functions with. + :returns: None. + """ + register(translation_checks.check_delayed_string_interpolation) + + +def _neutron_lib_factory(register): + """Hacking check factory for neutron-lib internal project checks. + + Hacking check factory for use with tox.ini. This factory registers all + checks that are run with the neutron-lib project itself. + + :param register: The function to register the check functions with. + :returns: None. + """ + factory(register) + incubating_factory(register) + + # neutron-lib project specific checks below + register(check_no_eventlet_imports) diff --git a/neutron_lib/tests/unit/hacking/test_checks.py b/neutron_lib/tests/unit/hacking/test_checks.py index 4889bd96b..5dc68ff88 100644 --- a/neutron_lib/tests/unit/hacking/test_checks.py +++ b/neutron_lib/tests/unit/hacking/test_checks.py @@ -28,10 +28,41 @@ class HackingTestCase(base.BaseTestCase): def assertLineFails(self, func, *args): self.assertIsInstance(next(func(*args)), tuple) + def _get_factory_checks(self, factory): + check_fns = [] + + def _reg(check_fn): + self.assertTrue(hasattr(check_fn, '__call__')) + self.assertFalse(check_fn in check_fns) + check_fns.append(check_fn) + + factory(_reg) + return check_fns + def test_factory(self): - def check_callable(fn): - self.assertTrue(hasattr(fn, '__call__')) - self.assertIsNone(checks.factory(check_callable)) + self.assertTrue(len(self._get_factory_checks(checks.factory)) > 0) + + def test_incubating_factory(self): + incubating_checks = self._get_factory_checks( + checks.incubating_factory) + + if incubating_checks: + adopter_checks = self._get_factory_checks(checks.factory) + for incubating_check in incubating_checks: + self.assertFalse(incubating_check in adopter_checks) + + def test_neutron_lib_factory(self): + lib_checks = self._get_factory_checks(checks._neutron_lib_factory) + other_checks = self._get_factory_checks(checks.factory) + other_checks.extend(self._get_factory_checks( + checks.incubating_factory)) + + self.assertTrue(len(lib_checks) > 0) + + if other_checks: + for other_check in other_checks: + # lib checks are superset of all checks + self.assertTrue(other_check in lib_checks) def test_use_jsonutils(self): def __get_msg(fun): diff --git a/releasenotes/notes/separate-hacking-factories-6fc36b38de95662a.yaml b/releasenotes/notes/separate-hacking-factories-6fc36b38de95662a.yaml new file mode 100644 index 000000000..477e6d2b6 --- /dev/null +++ b/releasenotes/notes/separate-hacking-factories-6fc36b38de95662a.yaml @@ -0,0 +1,7 @@ +--- +features: + - The hacking check factory ``incubating_factory`` has been added + to ``neutron_lib.hacking.checks`` allowing adopters to test + compliance on incubating hacking checks. See the usage documentation + for additional details. + diff --git a/tox.ini b/tox.ini index 062126478..1db6c9f6f 100644 --- a/tox.ini +++ b/tox.ini @@ -59,4 +59,4 @@ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools [hacking] import_exceptions = neutron_lib._i18n -local-check-factory = neutron_lib.hacking.checks.factory +local-check-factory = neutron_lib.hacking.checks._neutron_lib_factory