Swich the add_sisue signature around.

This commit is contained in:
Dave Halter
2017-08-16 22:44:33 +02:00
parent fc80cebfb8
commit e37e2e1ff6
3 changed files with 63 additions and 60 deletions

View File

@@ -35,7 +35,7 @@ class Normalizer(object):
def finalize(self): def finalize(self):
pass pass
def add_issue(self, code, message, node): def add_issue(self, node, code, message):
issue = Issue(node, code, message) issue = Issue(node, code, message)
if issue not in self.issues: if issue not in self.issues:
self.issues.append(issue) self.issues.append(issue)
@@ -125,7 +125,7 @@ class Rule(object):
if message is None: if message is None:
raise ValueError("The message on the class is not set.") raise ValueError("The message on the class is not set.")
self._normalizer.add_issue(code, message, node) self._normalizer.add_issue(node, code, message)
def feed_node(self, node): def feed_node(self, node):
if self.check(node): if self.check(node):

View File

@@ -671,6 +671,9 @@ class ErrorFinder(Normalizer):
and leaf.get_next_leaf() != 'from' \ and leaf.get_next_leaf() != 'from' \
and self._version == (3, 5): and self._version == (3, 5):
self._add_syntax_error("'yield' inside async function", leaf.parent) self._add_syntax_error("'yield' inside async function", leaf.parent)
elif leaf.value == 'await':
if not self._context.is_async_funcdef():
self._add_syntax_error("'await' outside async function", leaf.parent)
elif leaf.value == 'from' and leaf.parent.type == 'yield_arg' \ elif leaf.value == 'from' and leaf.parent.type == 'yield_arg' \
and self._context.is_async_funcdef(): and self._context.is_async_funcdef():
yield_ = leaf.parent.parent yield_ = leaf.parent.parent

View File

@@ -185,19 +185,19 @@ class PEP8Normalizer(ErrorFinder):
names = node.get_defined_names() names = node.get_defined_names()
if len(names) > 1: if len(names) > 1:
for name in names[:1]: for name in names[:1]:
self.add_issue(401, 'Multiple imports on one line', name) self.add_issue(name, 401, 'Multiple imports on one line')
elif typ == 'lambdef': elif typ == 'lambdef':
expr_stmt = node.parent expr_stmt = node.parent
# Check if it's simply defining a single name, not something like # Check if it's simply defining a single name, not something like
# foo.bar or x[1], where using a lambda could make more sense. # foo.bar or x[1], where using a lambda could make more sense.
if expr_stmt.type == 'expr_stmt' and any(n.type == 'name' for n in expr_stmt.children[:-2:2]): if expr_stmt.type == 'expr_stmt' and any(n.type == 'name' for n in expr_stmt.children[:-2:2]):
self.add_issue(731, 'Do not assign a lambda expression, use a def', node) self.add_issue(node, 731, 'Do not assign a lambda expression, use a def')
elif typ == 'try_stmt': elif typ == 'try_stmt':
for child in node.children: for child in node.children:
# Here we can simply check if it's an except, because otherwise # Here we can simply check if it's an except, because otherwise
# it would be an except_clause. # it would be an except_clause.
if child.type == 'keyword' and child.value == 'except': if child.type == 'keyword' and child.value == 'except':
self.add_issue(722, 'Do not use bare except, specify exception instead', child) self.add_issue(child, 722, 'Do not use bare except, specify exception instead')
elif typ == 'comparison': elif typ == 'comparison':
for child in node.children: for child in node.children:
if child.type not in ('atom_expr', 'power'): if child.type not in ('atom_expr', 'power'):
@@ -208,7 +208,7 @@ class PEP8Normalizer(ErrorFinder):
atom = child.children[0] atom = child.children[0]
if trailer.type == 'trailer' and atom.type == 'name' \ if trailer.type == 'trailer' and atom.type == 'name' \
and atom.value == 'type': and atom.value == 'type':
self.add_issue(721, "Do not compare types, use 'isinstance()", node) self.add_issue(node, 721, "Do not compare types, use 'isinstance()")
break break
elif typ == 'file_input': elif typ == 'file_input':
endmarker = node.children[-1] endmarker = node.children[-1]
@@ -216,7 +216,7 @@ class PEP8Normalizer(ErrorFinder):
prefix = endmarker.prefix prefix = endmarker.prefix
if (not prefix.endswith('\n') and ( if (not prefix.endswith('\n') and (
prefix or prev is None or prev.value != '\n')): prefix or prev is None or prev.value != '\n')):
self.add_issue(292, "No newline at end of file", endmarker) self.add_issue(endmarker, 292, "No newline at end of file")
if typ in _IMPORT_TYPES: if typ in _IMPORT_TYPES:
simple_stmt = node.parent simple_stmt = node.parent
@@ -243,7 +243,7 @@ class PEP8Normalizer(ErrorFinder):
if c.type in _IMPORT_TYPES or isinstance(c, Flow): if c.type in _IMPORT_TYPES or isinstance(c, Flow):
continue continue
self.add_issue(402, 'Module level import not at top of file', node) self.add_issue(node, 402, 'Module level import not at top of file')
break break
else: else:
continue continue
@@ -281,7 +281,7 @@ class PEP8Normalizer(ErrorFinder):
def _check_tabs_spaces(self, spacing): def _check_tabs_spaces(self, spacing):
if self._wrong_indentation_char in spacing.value: if self._wrong_indentation_char in spacing.value:
self.add_issue(101, 'Indentation contains ' + self._indentation_type, spacing) self.add_issue(spacing, 101, 'Indentation contains ' + self._indentation_type)
return True return True
return False return False
@@ -304,7 +304,7 @@ class PEP8Normalizer(ErrorFinder):
code = 302 if wanted == 2 else 301 code = 302 if wanted == 2 else 301
message = "expected %s blank line, found %s" \ message = "expected %s blank line, found %s" \
% (wanted, blank_lines) % (wanted, blank_lines)
self.add_issue(code, message, spacing) self.add_issue(spacing, code, message)
self._wanted_newline_count = None self._wanted_newline_count = None
else: else:
self._wanted_newline_count = None self._wanted_newline_count = None
@@ -334,7 +334,7 @@ class PEP8Normalizer(ErrorFinder):
code = 302 if wanted == 2 else 301 code = 302 if wanted == 2 else 301
message = "expected %s blank line, found %s" \ message = "expected %s blank line, found %s" \
% (wanted, actual) % (wanted, actual)
self.add_issue(code, message, spacing) self.add_issue(spacing, code, message)
self._max_new_lines_in_prefix = 0 self._max_new_lines_in_prefix = 0
@@ -389,22 +389,22 @@ class PEP8Normalizer(ErrorFinder):
if value.startswith('##'): if value.startswith('##'):
# Whole blocks of # should not raise an error. # Whole blocks of # should not raise an error.
if value.lstrip('#'): if value.lstrip('#'):
self.add_issue(266, "Too many leading '#' for block comment.", part) self.add_issue(part, 266, "Too many leading '#' for block comment.")
elif self._on_newline: elif self._on_newline:
if not re.match('#:? ', value) and not value == '#' \ if not re.match('#:? ', value) and not value == '#' \
and not (value.startswith('#!') and part.start_pos == (1, 0)): and not (value.startswith('#!') and part.start_pos == (1, 0)):
self.add_issue(265, "Block comment should start with '# '", part) self.add_issue(part, 265, "Block comment should start with '# '")
else: else:
if not re.match('#:? [^ ]', value): if not re.match('#:? [^ ]', value):
self.add_issue(262, "Inline comment should start with '# '", part) self.add_issue(part, 262, "Inline comment should start with '# '")
self._reset_newlines(spacing, leaf, is_comment=True) self._reset_newlines(spacing, leaf, is_comment=True)
elif type_ == 'newline': elif type_ == 'newline':
if self._newline_count > self._get_wanted_blank_lines_count(): if self._newline_count > self._get_wanted_blank_lines_count():
self.add_issue(303, "Too many blank lines (%s)" % self._newline_count, part) self.add_issue(part, 303, "Too many blank lines (%s)" % self._newline_count)
elif leaf in ('def', 'class') \ elif leaf in ('def', 'class') \
and leaf.parent.parent.type == 'decorated': and leaf.parent.parent.type == 'decorated':
self.add_issue(304, "Blank lines found after function decorator", part) self.add_issue(part, 304, "Blank lines found after function decorator")
self._newline_count += 1 self._newline_count += 1
@@ -413,7 +413,7 @@ class PEP8Normalizer(ErrorFinder):
# TODO is this enough checking? What about ==? # TODO is this enough checking? What about ==?
if node.type != IndentationTypes.BACKSLASH: if node.type != IndentationTypes.BACKSLASH:
if node.type != IndentationTypes.SUITE: if node.type != IndentationTypes.SUITE:
self.add_issue(502, 'The backslash is redundant between brackets', part) self.add_issue(part, 502, 'The backslash is redundant between brackets')
else: else:
indentation = node.indentation indentation = node.indentation
if self._in_suite_introducer and node.type == IndentationTypes.SUITE: if self._in_suite_introducer and node.type == IndentationTypes.SUITE:
@@ -451,10 +451,10 @@ class PEP8Normalizer(ErrorFinder):
if self._new_statement: if self._new_statement:
if type_ == 'newline': if type_ == 'newline':
if indentation: if indentation:
self.add_issue(291, 'Trailing whitespace', spacing) self.add_issue(spacing, 291, 'Trailing whitespace')
elif indentation != should_be_indentation: elif indentation != should_be_indentation:
s = '%s %s' % (len(self._config.indentation), self._indentation_type) s = '%s %s' % (len(self._config.indentation), self._indentation_type)
self.add_issue(111, 'Indentation is not a multiple of ' + s, part) self.add_issue(part, 111, 'Indentation is not a multiple of ' + s)
else: else:
if value in '])}': if value in '])}':
should_be_indentation = node.bracket_indentation should_be_indentation = node.bracket_indentation
@@ -463,31 +463,31 @@ class PEP8Normalizer(ErrorFinder):
if self._in_suite_introducer and indentation == \ if self._in_suite_introducer and indentation == \
node.get_latest_suite_node().indentation \ node.get_latest_suite_node().indentation \
+ self._config.indentation: + self._config.indentation:
self.add_issue(129, "Line with same indent as next logical block", part) self.add_issue(part, 129, "Line with same indent as next logical block")
elif indentation != should_be_indentation: elif indentation != should_be_indentation:
if not self._check_tabs_spaces(spacing) and part.value != '\n': if not self._check_tabs_spaces(spacing) and part.value != '\n':
if value in '])}': if value in '])}':
if node.type == IndentationTypes.VERTICAL_BRACKET: if node.type == IndentationTypes.VERTICAL_BRACKET:
self.add_issue(124, "Closing bracket does not match visual indentation", part) self.add_issue(part, 124, "Closing bracket does not match visual indentation")
else: else:
self.add_issue(123, "Losing bracket does not match indentation of opening bracket's line", part) self.add_issue(part, 123, "Losing bracket does not match indentation of opening bracket's line")
else: else:
if len(indentation) < len(should_be_indentation): if len(indentation) < len(should_be_indentation):
if node.type == IndentationTypes.VERTICAL_BRACKET: if node.type == IndentationTypes.VERTICAL_BRACKET:
self.add_issue(128, 'Continuation line under-indented for visual indent', part) self.add_issue(part, 128, 'Continuation line under-indented for visual indent')
elif node.type == IndentationTypes.BACKSLASH: elif node.type == IndentationTypes.BACKSLASH:
self.add_issue(122, 'Continuation line missing indentation or outdented', part) self.add_issue(part, 122, 'Continuation line missing indentation or outdented')
elif node.type == IndentationTypes.IMPLICIT: elif node.type == IndentationTypes.IMPLICIT:
self.add_issue(135, 'xxx', part) self.add_issue(part, 135, 'xxx')
else: else:
self.add_issue(121, 'Continuation line under-indented for hanging indent', part) self.add_issue(part, 121, 'Continuation line under-indented for hanging indent')
else: else:
if node.type == IndentationTypes.VERTICAL_BRACKET: if node.type == IndentationTypes.VERTICAL_BRACKET:
self.add_issue(127, 'Continuation line over-indented for visual indent', part) self.add_issue(part, 127, 'Continuation line over-indented for visual indent')
elif node.type == IndentationTypes.IMPLICIT: elif node.type == IndentationTypes.IMPLICIT:
self.add_issue(136, 'xxx', part) self.add_issue(part, 136, 'xxx')
else: else:
self.add_issue(126, 'Continuation line over-indented for hanging indent', part) self.add_issue(part, 126, 'Continuation line over-indented for hanging indent')
else: else:
self._check_spacing(part, spacing) self._check_spacing(part, spacing)
@@ -535,10 +535,10 @@ class PEP8Normalizer(ErrorFinder):
report = False report = False
if report: if report:
self.add_issue( self.add_issue(
part,
501, 501,
'Line too long (%s > %s characters)' % 'Line too long (%s > %s characters)' %
(last_column, self._config.max_characters), (last_column, self._config.max_characters),
part
) )
def _check_spacing(self, part, spacing): def _check_spacing(self, part, spacing):
@@ -557,29 +557,29 @@ class PEP8Normalizer(ErrorFinder):
type_ = part.type type_ = part.type
if '\t' in spaces: if '\t' in spaces:
self.add_issue(223, 'Used tab to separate tokens', spacing) self.add_issue(spacing, 223, 'Used tab to separate tokens')
elif type_ == 'comment': elif type_ == 'comment':
if len(spaces) < self._config.spaces_before_comment: if len(spaces) < self._config.spaces_before_comment:
self.add_issue(261, 'At least two spaces before inline comment', spacing) self.add_issue(spacing, 261, 'At least two spaces before inline comment')
elif type_ == 'newline': elif type_ == 'newline':
add_if_spaces(291, 'Trailing whitespace', spacing) add_if_spaces(spacing, 291, 'Trailing whitespace')
elif len(spaces) > 1: elif len(spaces) > 1:
self.add_issue(221, 'Multiple spaces used', spacing) self.add_issue(spacing, 221, 'Multiple spaces used')
else: else:
if prev in _OPENING_BRACKETS: if prev in _OPENING_BRACKETS:
message = "Whitespace after '%s'" % part.value message = "Whitespace after '%s'" % part.value
add_if_spaces(201, message, spacing) add_if_spaces(spacing, 201, message)
elif part in _CLOSING_BRACKETS: elif part in _CLOSING_BRACKETS:
message = "Whitespace before '%s'" % part.value message = "Whitespace before '%s'" % part.value
add_if_spaces(202, message, spacing) add_if_spaces(spacing, 202, message)
elif part in (',', ';') or part == ':' \ elif part in (',', ';') or part == ':' \
and part.parent.type not in _POSSIBLE_SLICE_PARENTS: and part.parent.type not in _POSSIBLE_SLICE_PARENTS:
message = "Whitespace before '%s'" % part.value message = "Whitespace before '%s'" % part.value
add_if_spaces(203, message, spacing) add_if_spaces(spacing, 203, message)
elif prev == ':' and prev.parent.type in _POSSIBLE_SLICE_PARENTS: elif prev == ':' and prev.parent.type in _POSSIBLE_SLICE_PARENTS:
pass # TODO pass # TODO
elif prev in (',', ';', ':'): elif prev in (',', ';', ':'):
add_not_spaces(231, "missing whitespace after '%s'", spacing) add_not_spaces(spacing, 231, "missing whitespace after '%s'")
elif part == ':': # Is a subscript elif part == ':': # Is a subscript
# TODO # TODO
pass pass
@@ -600,33 +600,33 @@ class PEP8Normalizer(ErrorFinder):
else: else:
param = prev.parent param = prev.parent
if param.type == 'param' and param.annotation: if param.type == 'param' and param.annotation:
add_not_spaces(252, 'Expected spaces around annotation equals', spacing) add_not_spaces(spacing, 252, 'Expected spaces around annotation equals')
else: else:
add_if_spaces(251, 'Unexpected spaces around keyword / parameter equals', spacing) add_if_spaces(spacing, 251, 'Unexpected spaces around keyword / parameter equals')
elif part in _BITWISE_OPERATOR or prev in _BITWISE_OPERATOR: elif part in _BITWISE_OPERATOR or prev in _BITWISE_OPERATOR:
add_not_spaces(227, 'Missing whitespace around bitwise or shift operator', spacing) add_not_spaces(spacing, 227, 'Missing whitespace around bitwise or shift operator')
elif part == '%' or prev == '%': elif part == '%' or prev == '%':
add_not_spaces(228, 'Missing whitespace around modulo operator', spacing) add_not_spaces(spacing, 228, 'Missing whitespace around modulo operator')
else: else:
message_225 = 'Missing whitespace between tokens' message_225 = 'Missing whitespace between tokens'
add_not_spaces(225, message_225, spacing) add_not_spaces(spacing, 225, message_225)
elif type_ == 'keyword' or prev.type == 'keyword': elif type_ == 'keyword' or prev.type == 'keyword':
add_not_spaces(275, 'Missing whitespace around keyword', spacing) add_not_spaces(spacing, 275, 'Missing whitespace around keyword')
else: else:
prev_spacing = self._previous_spacing prev_spacing = self._previous_spacing
if prev in _ALLOW_SPACE and spaces != prev_spacing.value \ if prev in _ALLOW_SPACE and spaces != prev_spacing.value \
and '\n' not in self._previous_leaf.prefix: and '\n' not in self._previous_leaf.prefix:
message = "Whitespace before operator doesn't match with whitespace after" message = "Whitespace before operator doesn't match with whitespace after"
self.add_issue(229, message, spacing) self.add_issue(spacing, 229, message)
if spaces and part not in _ALLOW_SPACE and prev not in _ALLOW_SPACE: if spaces and part not in _ALLOW_SPACE and prev not in _ALLOW_SPACE:
message_225 = 'Missing whitespace between tokens' message_225 = 'Missing whitespace between tokens'
#print('xy', spacing) #print('xy', spacing)
#self.add_issue(225, message_225, spacing) #self.add_issue(spacing, 225, message_225)
# TODO why only brackets? # TODO why only brackets?
if part in _OPENING_BRACKETS: if part in _OPENING_BRACKETS:
message = "Whitespace before '%s'" % part.value message = "Whitespace before '%s'" % part.value
add_if_spaces(211, message, spacing) add_if_spaces(spacing, 211, message)
def _analyse_non_prefix(self, leaf): def _analyse_non_prefix(self, leaf):
typ = leaf.type typ = leaf.type
@@ -634,9 +634,9 @@ class PEP8Normalizer(ErrorFinder):
if leaf.is_definition(): if leaf.is_definition():
message = "Do not define %s named 'l', 'O', or 'I' one line" message = "Do not define %s named 'l', 'O', or 'I' one line"
if leaf.parent.type == 'class' and leaf.parent.name == leaf: if leaf.parent.type == 'class' and leaf.parent.name == leaf:
self.add_issue(742, message % 'classes', leaf) self.add_issue(leaf, 742, message % 'classes')
elif leaf.parent.type == 'function' and leaf.parent.name == leaf: elif leaf.parent.type == 'function' and leaf.parent.name == leaf:
self.add_issue(743, message % 'function', leaf) self.add_issue(leaf, 743, message % 'function')
else: else:
self.add_issuadd_issue(741, message % 'variables', leaf) self.add_issuadd_issue(741, message % 'variables', leaf)
elif leaf.value == ':': elif leaf.value == ':':
@@ -644,14 +644,14 @@ class PEP8Normalizer(ErrorFinder):
next_leaf = leaf.get_next_leaf() next_leaf = leaf.get_next_leaf()
if next_leaf.type != 'newline': if next_leaf.type != 'newline':
if leaf.parent.type == 'funcdef': if leaf.parent.type == 'funcdef':
self.add_issue(704, 'Multiple statements on one line (def)', next_leaf) self.add_issue(next_leaf, 704, 'Multiple statements on one line (def)')
else: else:
self.add_issue(701, 'Multiple statements on one line (colon)', next_leaf) self.add_issue(next_leaf, 701, 'Multiple statements on one line (colon)')
elif leaf.value == ';': elif leaf.value == ';':
if leaf.get_next_leaf().type in ('newline', 'endmarker'): if leaf.get_next_leaf().type in ('newline', 'endmarker'):
self.add_issue(703, 'Statement ends with a semicolon', leaf) self.add_issue(leaf, 703, 'Statement ends with a semicolon')
else: else:
self.add_issue(702, 'Multiple statements on one line (semicolon)', leaf) self.add_issue(leaf, 702, 'Multiple statements on one line (semicolon)')
elif leaf.value in ('==', '!='): elif leaf.value in ('==', '!='):
comparison = leaf.parent comparison = leaf.parent
index = comparison.children.index(leaf) index = comparison.children.index(leaf)
@@ -661,19 +661,19 @@ class PEP8Normalizer(ErrorFinder):
if node.type == 'keyword' or node.type == 'name': if node.type == 'keyword' or node.type == 'name':
if node.value == 'None': if node.value == 'None':
message = "comparison to None should be 'if cond is None:'" message = "comparison to None should be 'if cond is None:'"
self.add_issue(711, message, leaf) self.add_issue(leaf, 711, message)
break break
elif node.value in ('True', 'False'): elif node.value in ('True', 'False'):
message = "comparison to False/True should be 'if cond is True:' or 'if cond:'" message = "comparison to False/True should be 'if cond is True:' or 'if cond:'"
self.add_issue(712, message, leaf) self.add_issue(leaf, 712, message)
break break
elif leaf.value in ('in', 'is'): elif leaf.value in ('in', 'is'):
comparison = leaf.parent comparison = leaf.parent
if comparison.type == 'comparison' and comparison.parent.type == 'not_test': if comparison.type == 'comparison' and comparison.parent.type == 'not_test':
if leaf.value == 'in': if leaf.value == 'in':
self.add_issue(713, "test for membership should be 'not in'", leaf) self.add_issue(leaf, 713, "test for membership should be 'not in'")
else: else:
self.add_issue(714, "test for object identity should be 'is not'", leaf) self.add_issue(leaf, 714, "test for object identity should be 'is not'")
elif typ == 'string': elif typ == 'string':
# Checking multiline strings # Checking multiline strings
for i, line in enumerate(leaf.value.splitlines()[1:]): for i, line in enumerate(leaf.value.splitlines()[1:]):
@@ -682,9 +682,9 @@ class PEP8Normalizer(ErrorFinder):
# TODO check multiline indentation. # TODO check multiline indentation.
elif typ == 'endmarker': elif typ == 'endmarker':
if self._newline_count >= 2: if self._newline_count >= 2:
self.add_issue(391, 'Blank line at end of file', leaf) self.add_issue(leaf, 391, 'Blank line at end of file')
def add_issue(self, code, message, node): def add_issue(self, node, code, message):
if self._previous_leaf is not None: if self._previous_leaf is not None:
if search_ancestor(self._previous_leaf, 'error_node') is not None: if search_ancestor(self._previous_leaf, 'error_node') is not None:
return return
@@ -692,7 +692,7 @@ class PEP8Normalizer(ErrorFinder):
return return
if search_ancestor(node, 'error_node') is not None: if search_ancestor(node, 'error_node') is not None:
return return
super(PEP8Normalizer, self).add_issue(code, message, node) super(PEP8Normalizer, self).add_issue(node, code, message)
class PEP8NormalizerConfig(ErrorFinderConfig): class PEP8NormalizerConfig(ErrorFinderConfig):