Adds ability to ignore hacking validations with noqa

Add allownoqa decorator that can be applied to any of the hacking
core functions.  This allows a using application to bypass that
particular hacking validation.  The reason this is being introduced
is because I need to bypass H231 and H233, both Python 3.x
validations.  I need to bypass these so we can run pep8 validations
on the nova XenServer plugins.  XenServer usese Python 2.4 in its
environment and therefore the code won't pass those two or future
Python 3.x validations.

It is understood that a patch to hacking won't be held up or reverted
if it breaks anything Python 2.4 related, including breaking of this
patch.

Change-Id: Iea3867b84212ab30bdd168b5dbd43c11a4dc535e
This commit is contained in:
jmeridth 2013-08-13 15:52:58 +00:00
parent 57e14d627a
commit ce4f1f35c9
2 changed files with 78 additions and 7 deletions

View File

@ -54,6 +54,34 @@ def flake8ext(f):
f.version = '0.0.1'
return f
class HackingDecoratorError(Exception):
pass
def allownoqa(f):
def wrapper(*args, **kwargs):
"""Decorator wrapper function for noqa usage.
Will send None as result of parent function if parent function has
physical_line as one of its arguments and also has '# noqa' in the
value of the physical_line argument or it will return
the parent function with its original arguments.
Raises:
HackingDecoratorError: if physical_line argument missing from
decorated function.
"""
if 'physical_line' not in f.func_code.co_varnames:
raise HackingDecoratorError("Missing physical_line argument "
"for decorated function")
index = f.func_code.co_varnames.index('physical_line')
if pep8.noqa(args[index]):
return
else:
return f(*args, **kwargs)
return wrapper
# Error code block layout
#H1xx comments
@ -259,7 +287,8 @@ def hacking_except_format_assert(logical_line):
@flake8ext
def hacking_python3x_except_compatible(logical_line):
@allownoqa
def hacking_python3x_except_compatible(logical_line, physical_line):
r"""Check for except statements to be Python 3.x compatible
As of Python 3.x, the construct 'except x,y:' has been removed.
@ -268,6 +297,7 @@ def hacking_python3x_except_compatible(logical_line):
Okay: try:\n pass\nexcept Exception:\n pass
Okay: try:\n pass\nexcept (Exception, AttributeError):\n pass
Okay: try:\n pass\nexcept AttributeError, e: # noqa\n pass
H231: try:\n pass\nexcept AttributeError, e:\n pass
"""
@ -308,7 +338,8 @@ def hacking_python3x_octal_literals(logical_line, tokens):
@flake8ext
def hacking_python3x_print_function(logical_line):
@allownoqa
def hacking_python3x_print_function(logical_line, physical_line):
r"""Check that all occurrences look like print functions, not
print operator.
@ -317,6 +348,9 @@ def hacking_python3x_print_function(logical_line):
Okay: print(msg)
Okay: print (msg)
Okay: print msg # noqa
Okay: print >>sys.stderr, "hello" # noqa
Okay: print msg, # noqa
H233: print msg
H233: print >>sys.stderr, "hello"
H233: print msg,
@ -334,6 +368,7 @@ RE_RELATIVE_IMPORT = re.compile('^from\s*[.]')
@flake8ext
@allownoqa
def hacking_import_rules(logical_line, physical_line, filename):
r"""Check for imports.
@ -369,9 +404,6 @@ def hacking_import_rules(logical_line, physical_line, filename):
#TODO(mordred: We need to split this into 4 different checks so that they
# can be disabled by command line switches properly
if pep8.noqa(physical_line):
return
def is_module_for_sure(mod, search_path=sys.path):
mod = mod.replace('(', '') # Ignore parentheses
try:
@ -603,6 +635,7 @@ def hacking_docstring_multiline_start(physical_line, previous_logical, tokens):
@flake8ext
@allownoqa
def hacking_no_locals(logical_line, physical_line, tokens):
"""Do not use locals() for string formatting.
@ -613,8 +646,6 @@ def hacking_no_locals(logical_line, physical_line, tokens):
H501: print("%(something)" % locals())
Okay: print("%(something)" % locals()) # noqa
"""
if pep8.noqa(physical_line):
return
for_formatting = False
for token_type, text, start, _, _ in tokens:
if text == "%" and token_type == tokenize.OP:

View File

@ -0,0 +1,40 @@
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from hacking.core import allownoqa, HackingDecoratorError
from testtools import ExpectedException
import hacking.tests
@allownoqa
def method_with_physical_line_argument(physical_line):
return "method_with_physical_line_argument"
@allownoqa
def method_without_physical_line_argument():
return "method_without_physical_line_argument"
class NoqaDecoratorTestCase(hacking.tests.TestCase):
def test_with_physical_line_argument(self):
result = method_with_physical_line_argument("blah")
self.assertEqual(result, "method_with_physical_line_argument")
def test_without_physical_line_argument(self):
with ExpectedException(HackingDecoratorError, "Missing physical_line "
"argument for decorated function"):
method_without_physical_line_argument()