Switch to hacking 2.0

In hacking 2.0, local-check-factory was removed as it is not compatible
with flake8 3.x and it is advised to use flake8's local plugins [1].
Checks specific to neutron-lib registered via local-check-factory are
converted into flake8's local plugins [2].

Note that neutron_lib.hacking.checks.factory is kept not to break hacking
checks in neutron-lib consumers. They need to be converted into the style
in hacking 2.x in each repository and then we can drop the factory here.

[1] https://docs.openstack.org/releasenotes/hacking/unreleased.html#relnotes-2-0-0
[2] https://flake8.pycqa.org/en/3.7.0/user/configuration.html#using-local-plugins

Change-Id: I90419fe0b385e7bee216a52c1169aba6d6975d56
This commit is contained in:
Akihiro Motoki 2020-02-21 06:05:59 +09:00
parent c099a22789
commit f4f5f1c719
7 changed files with 93 additions and 55 deletions

View File

@ -3,35 +3,43 @@ Hacking Checks
==============
The ``neutron_lib.hacking`` package implements a number of public
`hacking checks <https://github.com/openstack-dev/hacking>`_ intended to help
`flake8 checks <https://gitlab.com/pycqa/flake8>`__ 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``.
#. Update your project's ``tox.ini`` to include hacking checks from
neutron-lib. More specifically, copy hacking checks under
"Checks for neutron and related projects" in
``[flake8.local-plugin] extension`` in neutron-lib ``tox.ini``
to ``[flake8.local-plugin] extension`` in your project's ``tox.ini``.
For example in your ``tox.ini``::
[hacking]
local-check-factory = neutron_lib.hacking.checks.factory
[flake8:local-plugins]
extension =
# Checks from neutron-lib
N521 = neutron_lib.hacking.checks:use_jsonutils
N524 = neutron_lib.hacking.checks:check_no_contextlib_nested
N529 = neutron_lib.hacking.checks:no_mutable_default_args
N530 = neutron_lib.hacking.checks:check_neutron_namespace_imports
N532 = neutron_lib.hacking.translation_checks:check_log_warn_deprecated
N534 = neutron_lib.hacking.translation_checks:check_raised_localized_exceptions
N536 = neutron_lib.hacking.checks:assert_equal_none
N537 = neutron_lib.hacking.translation_checks:no_translate_logs
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.
Under certain circumstances, adopters may need to ignore specific
neutron-lib hacking checks temporarily. You can ignore such checks
just by commenting out them (hopefully with a proper reason).
For example in your project's python source::
If your project has its own hacking checks, you can add more rules
to ``[flake8.local-plugin] extension`` along with hacking checks
from neutron-lib.
def my_factory(register):
# register neutron-lib checks
neutron_lib_checks.factory(register)
# register project specific checks
register(my_project_check)
.. note::
And use your project's own factory in ``tox.ini``::
[hacking]
local-check-factory = myproject.mypkg.my_factory
The above configuration assumes hacking 2.x.
If your project uses hacking 1.x, see :ref:`hacking1_support` below.
#. Update your project's ``tox.ini`` enable any flake8 extensions neutron-lib's
``tox.ini`` does. These are hacking checks otherwise disabled by default
@ -54,12 +62,40 @@ To adopt neutron-lib's hacking checks:
hacking checks will be communicated via openstack-discuss email list
and `neutron meetings <https://wiki.openstack.org/wiki/Network/Meetings>`_.
Under certain circumstances, adopters may need to ignore specific
neutron-lib hacking checks temporarily. This can be done using the
``ignore`` property in the ``[flake8]`` section of your ``tox.ini``.
For example, to ignore the hacking check ``N536`` your tox.ini might
have::
.. _hacking1_support:
[flake8]
# temporarily ignore N536 while fixing failing checks
ignore = N536
Hacking 1.x support
-------------------
If your project uses hacking 1.x, you need a different way to consume hacking
checks from neutron-lib.
.. warning::
hacking 1.x support is deprecated and will be dropped once all neutron
related projects migrate to hacking 2.x.
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

View File

@ -14,6 +14,8 @@
import re
from hacking import core
from neutron_lib.hacking import translation_checks
# Guidelines for writing new hacking checks
@ -41,6 +43,7 @@ assert_is_none_re = re.compile(
r"assertIs(Not)?\(.*,\s+None\)(( |\t)*#.*)?$|assertIs(Not)?\(None,")
@core.flake8ext
def use_jsonutils(logical_line, filename):
"""N521 - jsonutils must be used instead of json.
@ -105,6 +108,7 @@ def _check_namespace_imports(failure_code, namespace, new_ns, logical_line,
return (0, msg_o or msg)
@core.flake8ext
def check_no_contextlib_nested(logical_line, filename):
"""N524 - Use of contextlib.nested is deprecated.
@ -123,6 +127,7 @@ def check_no_contextlib_nested(logical_line, filename):
yield(0, msg)
@core.flake8ext
def no_mutable_default_args(logical_line):
"""N529 - Method's default argument shouldn't be mutable.
@ -139,6 +144,7 @@ def no_mutable_default_args(logical_line):
# Chances are that most projects will need to put an ignore on this rule
# until they can fully migrate to the lib.
@core.flake8ext
def check_neutron_namespace_imports(logical_line):
"""N530 - Direct neutron imports not allowed.
@ -154,6 +160,7 @@ def check_neutron_namespace_imports(logical_line):
yield x
@core.flake8ext
def check_no_eventlet_imports(logical_line):
"""N535 - Usage of Python eventlet module not allowed.
@ -167,6 +174,7 @@ def check_no_eventlet_imports(logical_line):
yield logical_line.index('eventlet'), msg
@core.flake8ext
def assert_equal_none(logical_line):
"""N536 - Use assertIsNone."""
if assert_equal_none_re.search(logical_line):
@ -180,6 +188,8 @@ def assert_equal_none(logical_line):
yield logical_line.index('assert'), msg
# TODO(amotoki): Drop this once all neutron related projects
# have switched to hacking 2.x
def factory(register):
"""Hacking check factory for neutron-lib adopter compliant checks.
@ -197,18 +207,3 @@ def factory(register):
register(translation_checks.check_log_warn_deprecated)
register(translation_checks.check_raised_localized_exceptions)
register(assert_equal_none)
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)
# neutron-lib project specific checks below
register(check_no_eventlet_imports)

View File

@ -14,6 +14,8 @@
import re
from hacking import core
_all_log_levels = {'critical', 'error', 'exception', 'info',
'warning', 'debug'}
@ -36,6 +38,7 @@ def _translation_checks_not_enforced(filename):
return any(pat in filename for pat in ["/tests/", "rally-jobs/plugins/"])
@core.flake8ext
def check_log_warn_deprecated(logical_line, filename):
"""N532 - Use LOG.warning due to compatibility with py3.
@ -50,6 +53,7 @@ def check_log_warn_deprecated(logical_line, filename):
yield (0, msg)
@core.flake8ext
def check_raised_localized_exceptions(logical_line, filename):
"""N534 - Untranslated exception message.
@ -72,6 +76,7 @@ def check_raised_localized_exceptions(logical_line, filename):
yield (logical_line.index(exception_msg), msg)
@core.flake8ext
def no_translate_logs(logical_line, filename):
"""N537 - Don't translate logs.

View File

@ -117,7 +117,7 @@ class NoAuthClient(object):
LOG.exception('requests Timeout, let\'s retry it...')
except requests.ConnectionError:
LOG.exception('Connection Error appeared')
except requests.RequestException as e:
except requests.RequestException:
LOG.exception('Some really weird thing happened, let\'s '
'retry it')
time.sleep(self.timeout)

View File

@ -40,17 +40,6 @@ class HackingTestCase(base.BaseTestCase):
def test_factory(self):
self.assertGreater(len(self._get_factory_checks(checks.factory)), 0)
def test_neutron_lib_factory(self):
lib_checks = self._get_factory_checks(checks._neutron_lib_factory)
other_checks = self._get_factory_checks(checks.factory)
self.assertGreater(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):
msg = ("N521: jsonutils.%(fun)s must be used instead of "

View File

@ -2,7 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking>=1.1.0,<1.2.0 # Apache-2.0
hacking>=2.0.0,<2.1 # Apache-2.0
bandit!=1.6.0,>=1.1.0 # Apache-2.0
coverage!=4.4,>=4.0 # Apache-2.0

15
tox.ini
View File

@ -101,6 +101,20 @@ show-source = True
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools
import-order-style = pep8
[flake8:local-plugins]
extension =
# Checks for neutron and related projects
N521 = neutron_lib.hacking.checks:use_jsonutils
N524 = neutron_lib.hacking.checks:check_no_contextlib_nested
N529 = neutron_lib.hacking.checks:no_mutable_default_args
N530 = neutron_lib.hacking.checks:check_neutron_namespace_imports
N532 = neutron_lib.hacking.translation_checks:check_log_warn_deprecated
N534 = neutron_lib.hacking.translation_checks:check_raised_localized_exceptions
N536 = neutron_lib.hacking.checks:assert_equal_none
N537 = neutron_lib.hacking.translation_checks:no_translate_logs
# Checks specific to neutron-lib only
N535 = neutron_lib.hacking.checks:check_no_eventlet_imports
[testenv:bandit]
# B104: Possible binding to all interfaces
# B303: Blacklist use of insecure MD2, MD4, MD5, or SHA1 hash functions
@ -110,7 +124,6 @@ commands = bandit -r neutron_lib -x tests -n5 -s B104,B303,B311
[hacking]
import_exceptions = neutron_lib._i18n
local-check-factory = neutron_lib.hacking.checks._neutron_lib_factory
[testenv:lower-constraints]
deps =