Update hacking for Python3

The repo is Python 3 now, so update hacking to version 3.0 which
supports Python 3.

Fix problems found by updated hacking version.

Update local hacking checks for new flake8, remove
test B314 since that tests difference between Python 2 and 3,
there's no need to advise using six anymore.
Use oslotest.base directly, this fixes the hacking tests.

Remove ddt usage in testsuite, it does not work with current hacking
version anymore.

Change-Id: Iee4584c6fde08728c017468d9de1db73f2c79d8d
This commit is contained in:
Andreas Jaeger 2020-04-01 20:56:29 +02:00
parent 6be43dffe3
commit 9dbeefb55e
16 changed files with 66 additions and 187 deletions

View File

@ -53,7 +53,6 @@ openstackdocs_bug_project = 'barbican'
copyright = u'2016, OpenStack contributors' copyright = u'2016, OpenStack contributors'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
# language = None # language = None

View File

@ -81,5 +81,6 @@ def main():
except RuntimeError as e: except RuntimeError as e:
fail(1, e) fail(1, e)
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -188,5 +188,6 @@ def main():
rewrapper.execute(args.dry_run) rewrapper.execute(args.dry_run)
rewrapper.pkcs11.return_session(rewrapper.hsm_session) rewrapper.pkcs11.return_session(rewrapper.hsm_session)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -167,5 +167,6 @@ def main():
) )
migrator.execute(args.dry_run) migrator.execute(args.dry_run)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -73,5 +73,6 @@ def main():
except RuntimeError as e: except RuntimeError as e:
fail(1, e) fail(1, e)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -352,6 +352,7 @@ def set_middleware_defaults():
'PATCH'] 'PATCH']
) )
CONF = new_config() CONF = new_config()
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
parse_args(CONF) parse_args(CONF)

View File

@ -88,7 +88,7 @@ def get_base_url_from_request():
# FIXME: implement SERVER_NAME lookup if HTTP_HOST is not set # FIXME: implement SERVER_NAME lookup if HTTP_HOST is not set
if p_url.path: if p_url.path:
# Remove the version from the path to extract the base path # Remove the version from the path to extract the base path
base_path = re.sub('/v[0-9\.]+$', '', p_url.path) base_path = re.sub(r'/v[0-9\.]+$', '', p_url.path)
base_url = '%s://%s%s' % (scheme, netloc, base_path) base_url = '%s://%s%s' % (scheme, netloc, base_path)
else: else:
base_url = '%s://%s' % (scheme, netloc) base_url = '%s://%s' % (scheme, netloc)
@ -204,7 +204,7 @@ def is_multiple_backends_enabled():
secretstore_conf = config.get_module_config('secretstore') secretstore_conf = config.get_module_config('secretstore')
except KeyError: except KeyError:
# Ensure module is initialized # Ensure module is initialized
from barbican.plugin.interface import secret_store # nopep8 from barbican.plugin.interface import secret_store # noqa: F401
secretstore_conf = config.get_module_config('secretstore') secretstore_conf = config.get_module_config('secretstore')
return secretstore_conf.secretstore.enable_multiple_secret_stores return secretstore_conf.secretstore.enable_multiple_secret_stores

View File

@ -17,7 +17,8 @@ import ast
import re import re
import six import six
import pep8 from hacking import core
import pycodestyle
""" """
@ -61,7 +62,7 @@ class BaseASTChecker(ast.NodeVisitor):
CHECK_DESC = 'No check message specified' CHECK_DESC = 'No check message specified'
def __init__(self, tree, filename): def __init__(self, tree, filename):
"""This object is created automatically by pep8. """This object is created automatically by pycodestyle.
:param tree: an AST tree :param tree: an AST tree
:param filename: name of the file being analyzed :param filename: name of the file being analyzed
@ -71,12 +72,13 @@ class BaseASTChecker(ast.NodeVisitor):
self._errors = [] self._errors = []
def run(self): def run(self):
"""Called automatically by pep8.""" """Called automatically by pycodestyle."""
self.visit(self._tree) self.visit(self._tree)
return self._errors return self._errors
def add_error(self, node, message=None): def add_error(self, node, message=None):
"""Add an error caused by a node to the list of errors for pep8.""" """Add an error caused by a node to the list of errors for pep8."""
message = message or self.CHECK_DESC message = message or self.CHECK_DESC
error = (node.lineno, node.col_offset, message, self.__class__) error = (node.lineno, node.col_offset, message, self.__class__)
self._errors.append(error) self._errors.append(error)
@ -98,6 +100,8 @@ class CheckLoggingFormatArgs(BaseASTChecker):
The format arguments should not be a tuple as it is easy to miss. The format arguments should not be a tuple as it is easy to miss.
""" """
name = "check_logging_format_args"
version = "1.0"
CHECK_DESC = 'B310 Log method arguments should not be a tuple.' CHECK_DESC = 'B310 Log method arguments should not be a tuple.'
LOG_METHODS = [ LOG_METHODS = [
@ -154,59 +158,13 @@ class CheckLoggingFormatArgs(BaseASTChecker):
return super(CheckLoggingFormatArgs, self).generic_visit(node) return super(CheckLoggingFormatArgs, self).generic_visit(node)
class CheckForStrUnicodeExc(BaseASTChecker): @core.flake8ext
"""Checks for the use of str() or unicode() on an exception. def check_oslo_namespace_imports(physical_line, logical_line, filename):
This currently only handles the case where str() or unicode()
is used in the scope of an exception handler. If the exception
is passed into a function, returned from an assertRaises, or
used on an exception created in the same scope, this does not
catch it.
"""
CHECK_DESC = ('B314 str() and unicode() cannot be used on an '
'exception. Remove or use six.text_type()')
def __init__(self, tree, filename):
super(CheckForStrUnicodeExc, self).__init__(tree, filename)
self.name = []
self.already_checked = []
# Python 2
def visit_TryExcept(self, node):
for handler in node.handlers:
if handler.name:
self.name.append(handler.name.id)
super(CheckForStrUnicodeExc, self).generic_visit(node)
self.name = self.name[:-1]
else:
super(CheckForStrUnicodeExc, self).generic_visit(node)
# Python 3
def visit_ExceptHandler(self, node):
if node.name:
self.name.append(node.name)
super(CheckForStrUnicodeExc, self).generic_visit(node)
self.name = self.name[:-1]
else:
super(CheckForStrUnicodeExc, self).generic_visit(node)
def visit_Call(self, node):
if self._check_call_names(node, ['str', 'unicode']):
if node not in self.already_checked:
self.already_checked.append(node)
if isinstance(node.args[0], ast.Name):
if node.args[0].id in self.name:
self.add_error(node.args[0])
super(CheckForStrUnicodeExc, self).generic_visit(node)
def check_oslo_namespace_imports(logical_line, physical_line, filename):
"""'oslo_' should be used instead of 'oslo.' """'oslo_' should be used instead of 'oslo.'
B317 B317
""" """
if pep8.noqa(physical_line): if pycodestyle.noqa(physical_line):
return return
if re.match(oslo_namespace_imports, logical_line): if re.match(oslo_namespace_imports, logical_line):
msg = ("B317: '%s' must be used instead of '%s'.") % ( msg = ("B317: '%s' must be used instead of '%s'.") % (
@ -215,6 +173,7 @@ def check_oslo_namespace_imports(logical_line, physical_line, filename):
yield(0, msg) yield(0, msg)
@core.flake8ext
def dict_constructor_with_list_copy(logical_line): def dict_constructor_with_list_copy(logical_line):
"""Use a dict comprehension instead of a dict constructor """Use a dict comprehension instead of a dict constructor
@ -227,6 +186,7 @@ def dict_constructor_with_list_copy(logical_line):
yield (0, msg) yield (0, msg)
@core.flake8ext
def no_xrange(logical_line): def no_xrange(logical_line):
"""Do not use 'xrange' """Do not use 'xrange'
@ -236,6 +196,7 @@ def no_xrange(logical_line):
yield(0, "B319: Do not use xrange().") yield(0, "B319: Do not use xrange().")
@core.flake8ext
def validate_assertTrue(logical_line): def validate_assertTrue(logical_line):
"""Use 'assertTrue' instead of 'assertEqual' """Use 'assertTrue' instead of 'assertEqual'
@ -247,6 +208,7 @@ def validate_assertTrue(logical_line):
yield(0, msg) yield(0, msg)
@core.flake8ext
def validate_assertIsNone(logical_line): def validate_assertIsNone(logical_line):
"""Use 'assertIsNone' instead of 'assertEqual' """Use 'assertIsNone' instead of 'assertEqual'
@ -258,6 +220,7 @@ def validate_assertIsNone(logical_line):
yield(0, msg) yield(0, msg)
@core.flake8ext
def no_log_warn_check(logical_line): def no_log_warn_check(logical_line):
"""Disallow 'LOG.warn' """Disallow 'LOG.warn'
@ -268,6 +231,7 @@ def no_log_warn_check(logical_line):
yield(0, msg) yield(0, msg)
@core.flake8ext
def validate_assertIsNotNone(logical_line): def validate_assertIsNotNone(logical_line):
"""Use 'assertIsNotNone' """Use 'assertIsNotNone'
@ -279,15 +243,3 @@ def validate_assertIsNotNone(logical_line):
" of using assertNotEqual(None, value) or" " of using assertNotEqual(None, value) or"
" assertIsNot(None, value).") " assertIsNot(None, value).")
yield(0, msg) yield(0, msg)
def factory(register):
register(CheckForStrUnicodeExc)
register(CheckLoggingFormatArgs)
register(check_oslo_namespace_imports)
register(dict_constructor_with_list_copy)
register(no_xrange)
register(validate_assertTrue)
register(validate_assertIsNone)
register(no_log_warn_check)
register(validate_assertIsNotNone)

View File

@ -54,7 +54,7 @@ def cleanup_unassociated_projects():
for model in project_children_tables: for model in project_children_tables:
sub_query = sub_query.outerjoin(model, sub_query = sub_query.outerjoin(model,
models.Project.id == model.project_id) models.Project.id == model.project_id)
sub_query = sub_query.filter(model.id == None) # nopep8 sub_query = sub_query.filter(model.id == None) # noqa
sub_query = sub_query.subquery() sub_query = sub_query.subquery()
sub_query = sa_sql.select([sub_query]) sub_query = sa_sql.select([sub_query])
query = session.query(models.Project) query = session.query(models.Project)
@ -89,7 +89,7 @@ def cleanup_parent_with_no_child(parent_model, child_model,
session = repo.get_session() session = repo.get_session()
sub_query = session.query(parent_model.id) sub_query = session.query(parent_model.id)
sub_query = sub_query.outerjoin(child_model) sub_query = sub_query.outerjoin(child_model)
sub_query = sub_query.filter(child_model.id == None) # nopep8 sub_query = sub_query.filter(child_model.id == None) # noqa
sub_query = sub_query.subquery() sub_query = sub_query.subquery()
sub_query = sa_sql.select([sub_query]) sub_query = sa_sql.select([sub_query])
query = session.query(parent_model) query = session.query(parent_model)

View File

@ -133,6 +133,7 @@ def create_connection(conf, subsystem_path):
connection.set_authentication_cert(pem_path) connection.set_authentication_cert(pem_path)
return connection return connection
crypto = _setup_nss_db_services(CONF) crypto = _setup_nss_db_services(CONF)
if crypto: if crypto:
crypto.initialize() crypto.initialize()

View File

@ -83,7 +83,7 @@ def set_subject_X509Name(target, dn):
elif name.lower() == 'l': elif name.lower() == 'l':
target.L = value target.L = value
elif name.lower() == 'o': elif name.lower() == 'o':
target.O = value target.O = value # noqa: E741
return target return target

View File

@ -12,23 +12,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import sys
import textwrap import textwrap
from unittest import mock from unittest import mock
import ddt import pycodestyle
import pep8
from barbican.hacking import checks from barbican.hacking import checks
from barbican.tests import utils import oslotest
@ddt.ddt class HackingTestCase(oslotest.base.BaseTestCase):
class HackingTestCase(utils.BaseTestCase):
"""Hacking test cases """Hacking test cases
This class tests the hacking checks in barbican.hacking.checks by passing This class tests the hacking checks in barbican.hacking.checks by passing
strings to the check methods like the pep8/flake8 parser would. The parser strings to the check methods like the pycodestyle/flake8 parser would. The
parser
loops over each line in the file and then passes the parameters to the loops over each line in the file and then passes the parameters to the
check method. The parameter names in the check method dictate what type of check method. The parameter names in the check method dictate what type of
object is passed to the check method. The parameter types are:: object is passed to the check method. The parameter types are::
@ -48,7 +46,7 @@ class HackingTestCase(utils.BaseTestCase):
indent_level: indentation (with tabs expanded to multiples of 8) indent_level: indentation (with tabs expanded to multiples of 8)
previous_indent_level: indentation on previous line previous_indent_level: indentation on previous line
previous_logical: previous logical line previous_logical: previous logical line
filename: Path of the file being run through pep8 filename: Path of the file being run through pycodestyle
When running a test on a check method the return will be False/None if When running a test on a check method the return will be False/None if
there is no violation in the sample input. If there is an error a tuple is there is no violation in the sample input. If there is an error a tuple is
@ -57,16 +55,16 @@ class HackingTestCase(utils.BaseTestCase):
should pass. should pass.
""" """
# We are patching pep8 so that only the check under test is actually # We are patching pycodestyle so that only the check under test is actually
# installed. # installed.
@mock.patch('pep8._checks', @mock.patch('pycodestyle._checks',
{'physical_line': {}, 'logical_line': {}, 'tree': {}}) {'physical_line': {}, 'logical_line': {}, 'tree': {}})
def _run_check(self, code, checker, filename=None): def _run_check(self, code, checker, filename=None):
pep8.register_check(checker) pycodestyle.register_check(checker)
lines = textwrap.dedent(code).strip().splitlines(True) lines = textwrap.dedent(code).strip().splitlines(True)
checker = pep8.Checker(filename=filename, lines=lines) checker = pycodestyle.Checker(filename=filename, lines=lines)
checker.check_all() checker.check_all()
checker.report._deferred_print.sort() checker.report._deferred_print.sort()
return checker.report._deferred_print return checker.report._deferred_print
@ -92,95 +90,6 @@ class HackingTestCase(utils.BaseTestCase):
""" """
self._assert_has_no_errors(code, checker) self._assert_has_no_errors(code, checker)
@ddt.data(*checks.CheckLoggingFormatArgs.LOG_METHODS)
def test_logging_with_tuple_argument(self, log_method):
checker = checks.CheckLoggingFormatArgs
code = """
import logging
LOG = logging.getLogger()
LOG.{0}("Volume %s caught fire and is at %d degrees C and "
"climbing.", ('volume1', 500))
"""
if (sys.version_info >= (3, 8)):
exc_errors = [(4, 20, 'B310')]
else:
exc_errors = [(4, 21, 'B310')]
self._assert_has_errors(code.format(log_method), checker,
expected_errors=exc_errors)
def test_str_on_exception(self):
checker = checks.CheckForStrUnicodeExc
code = """
def f(a, b):
try:
p = str(a) + str(b)
except ValueError as e:
p = str(e)
return p
"""
errors = [(5, 16, 'B314')]
self._assert_has_errors(code, checker, expected_errors=errors)
def test_no_str_unicode_on_exception(self):
checker = checks.CheckForStrUnicodeExc
code = """
def f(a, b):
try:
p = unicode(a) + str(b)
except ValueError as e:
p = e
return p
"""
self._assert_has_no_errors(code, checker)
def test_unicode_on_exception(self):
checker = checks.CheckForStrUnicodeExc
code = """
def f(a, b):
try:
p = str(a) + str(b)
except ValueError as e:
p = unicode(e)
return p
"""
errors = [(5, 20, 'B314')]
self._assert_has_errors(code, checker, expected_errors=errors)
def test_str_on_multiple_exceptions(self):
checker = checks.CheckForStrUnicodeExc
code = """
def f(a, b):
try:
p = str(a) + str(b)
except ValueError as e:
try:
p = unicode(a) + unicode(b)
except ValueError as ve:
p = str(e) + str(ve)
p = e
return p
"""
errors = [(8, 20, 'B314'), (8, 29, 'B314')]
self._assert_has_errors(code, checker, expected_errors=errors)
def test_str_unicode_on_multiple_exceptions(self):
checker = checks.CheckForStrUnicodeExc
code = """
def f(a, b):
try:
p = str(a) + str(b)
except ValueError as e:
try:
p = unicode(a) + unicode(b)
except ValueError as ve:
p = str(e) + unicode(ve)
p = str(e)
return p
"""
errors = [(8, 20, 'B314'), (8, 33, 'B314'), (9, 16, 'B314')]
self._assert_has_errors(code, checker, expected_errors=errors)
def test_dict_constructor_with_list_copy(self): def test_dict_constructor_with_list_copy(self):
self.assertEqual(1, len(list(checks.dict_constructor_with_list_copy( self.assertEqual(1, len(list(checks.dict_constructor_with_list_copy(
" dict([(i, connect_info[i])")))) " dict([(i, connect_info[i])"))))

View File

@ -36,6 +36,7 @@ def get_default_container_create_data(secret):
] ]
} }
create_container_data = { create_container_data = {
"name": "containername", "name": "containername",
"type": "generic", "type": "generic",

View File

@ -3,11 +3,10 @@
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
# hacking should appear first in case something else depends on pep8 # hacking should appear first in case something else depends on pep8
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 hacking>=3.0,<3.1.0 # Apache-2.0
pyflakes>=2.1.1 pyflakes>=2.1.1
coverage!=4.4,>=4.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0
ddt>=1.0.1 # MIT
oslotest>=3.2.0 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0
pykmip>=0.7.0 # Apache 2.0 License pykmip>=0.7.0 # Apache 2.0 License
stestr>=2.0.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0

19
tox.ini
View File

@ -69,7 +69,7 @@ commands = oslo_debug_helper -t barbican/tests {posargs}
# without installing barbican. # without installing barbican.
install_command = /bin/echo {packages} install_command = /bin/echo {packages}
commands = commands =
pip install "hacking>=0.10.0,<0.11" pip install "hacking>=3.0,<3.1.0"
flake8 barbican setup.py flake8 barbican setup.py
[testenv:docs] [testenv:docs]
@ -151,6 +151,10 @@ ignore-path = .venv,.git,.tox,.tmp,*barbican/locale*,*lib/python*,barbican.egg*,
filename = *.py,app.wsgi filename = *.py,app.wsgi
exclude = .git,.idea,.tox,bin,dist,debian,rpmbuild,tools,*.egg-info,*.eggs,contrib, exclude = .git,.idea,.tox,bin,dist,debian,rpmbuild,tools,*.egg-info,*.eggs,contrib,
*docs/target,*.egg,build *docs/target,*.egg,build
# E402 module level import not at top of file
# W503 line break before binary operator
# W504 line break after binary operator
ignore = E402,W503,W504,
[testenv:bandit] [testenv:bandit]
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
@ -168,5 +172,14 @@ commands = bindep test
envdir = {toxworkdir}/pep8 envdir = {toxworkdir}/pep8
commands = oslopolicy-sample-generator --config-file=etc/oslo-config-generator/policy.conf commands = oslopolicy-sample-generator --config-file=etc/oslo-config-generator/policy.conf
[hacking] [flake8:local-plugins]
local-check-factory = barbican.hacking.checks.factory extension =
B310 = checks:CheckLoggingFormatArgs
B311 = checks:validate_assertIsNone
B312 = checks:validate_assertTrue
B317 = checks:check_oslo_namespace_imports
B318 = checks:dict_constructor_with_list_copy
B319 = checks:no_xrange
B320 = checks:no_log_warn_check
B321 = checks:validate_assertIsNotNone
paths = ./barbican/hacking