diff --git a/parso/python/normalizer.py b/parso/python/normalizer.py index 413b56d..2d2b663 100644 --- a/parso/python/normalizer.py +++ b/parso/python/normalizer.py @@ -1,11 +1,14 @@ +import re from contextlib import contextmanager + from parso.normalizer import Normalizer, Rule, NormalizerConfig _IMPORT_TYPES = ('import_name', 'import_from') _SUITE_INTRODUCERS = ('classdef', 'funcdef', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt') -_OPENING_BRACKETS = '([{' +_OPENING_BRACKETS = '(', '[', '{' +_CLOSING_BRACKETS = ')', ']', '}' _IMPLICIT_INDENTATION_TYPES = ('dictorsetmaker', 'argument') class CompressNormalizer(Normalizer): @@ -163,6 +166,7 @@ def _is_magic_name(name): class PEP8Normalizer(Normalizer): def __init__(self, config): super(PEP8Normalizer, self).__init__(config) + self._previous_leaf = None self._last_indentation_level = 0 self._on_newline = True self._implicit_indentation_possible = False @@ -334,7 +338,19 @@ class PEP8Normalizer(Normalizer): self.add_issue(136, 'xxx', leaf) else: self.add_issue(126, 'Continuation line over-indented for hanging indent', leaf) - + else: + spaces = info.indentation + if spaces: + if leaf in _CLOSING_BRACKETS: + message = "Whitespace before '%s'" % leaf.value + self.add_issue(202, message, info.indentation_part) + elif leaf in (',', ';') or leaf == ':' \ + and leaf.parent.type not in ('subscript', 'subscriptlist'): + message = "Whitespace before '%s'" % leaf.value + self.add_issue(203, message, info.indentation_part) + elif self._previous_leaf in _OPENING_BRACKETS: + message = "Whitespace after '%s'" % leaf.value + self.add_issue(201, message, info.indentation_part) first = True for comment in info.comments: @@ -412,6 +428,7 @@ class PEP8Normalizer(Normalizer): if value == ':' and leaf.parent.type in _SUITE_INTRODUCERS: self._in_suite_introducer = False + self._previous_leaf = leaf return value @@ -426,7 +443,7 @@ class PEP8Normalizer(Normalizer): self.add_issue(743, message % 'function', leaf) else: self.add_issuadd_issue(741, message % 'variables', leaf) - if leaf.value == ':': + elif leaf.value == ':': from parso.python.tree import Flow, Scope if isinstance(leaf.parent, (Flow, Scope)) and leaf.parent.type != 'lambdef': next_leaf = leaf.get_next_leaf() @@ -435,12 +452,12 @@ class PEP8Normalizer(Normalizer): self.add_issue(704, 'Multiple statements on one line (def)', next_leaf) else: self.add_issue(701, 'Multiple statements on one line (colon)', next_leaf) - if leaf.value == ';': + elif leaf.value == ';': if leaf.get_next_leaf().type in ('newline', 'endmarker'): self.add_issue(703, 'Statement ends with a semicolon', leaf) else: self.add_issue(702, 'Multiple statements on one line (semicolon)', leaf) - if leaf.value in ('==', '!='): + elif leaf.value in ('==', '!='): comparison = leaf.parent index = comparison.children.index(leaf) left = comparison.children[index - 1] @@ -455,13 +472,19 @@ class PEP8Normalizer(Normalizer): message = "comparison to False/True should be 'if cond is True:' or 'if cond:'" self.add_issue(712, message, leaf) break - if leaf.value in ('in', 'is'): + elif leaf.value in ('in', 'is'): comparison = leaf.parent if comparison.type == 'comparison' and comparison.parent.type == 'not_test': if leaf.value == 'in': self.add_issue(713, "test for membership should be 'not in'", leaf) else: self.add_issue(714, "test for object identity should be 'is not'", leaf) + elif typ == 'string': + # Checking multiline strings + for i, line in enumerate(leaf.value.splitlines()[1:]): + indentation = re.match('[ \t]*', line).group(0) + start_pos = leaf.line + i, len(indentation) + # TODO check multiline indentation. return leaf.value diff --git a/test/normalizer_issue_files/E11.py b/test/normalizer_issue_files/E11.py index d644363..0abda9d 100644 --- a/test/normalizer_issue_files/E11.py +++ b/test/normalizer_issue_files/E11.py @@ -1,6 +1,6 @@ if x > 2: #: E111:2 - print x + print(x) if True: #: E111:5 print diff --git a/test/normalizer_issue_files/E12_first.py b/test/normalizer_issue_files/E12_first.py index 79cf627..52bff7a 100644 --- a/test/normalizer_issue_files/E12_first.py +++ b/test/normalizer_issue_files/E12_first.py @@ -60,14 +60,12 @@ rv.update(dict.fromkeys(( '?'), "foo") -#: E126+1:10 E126+2:10 abricot = 3 + \ 4 + \ 5 + 6 print "hello", ( "there", - #: E131:5 # "john", "dude") part = set_mimetype(( diff --git a/test/normalizer_issue_files/E12_not_first.py b/test/normalizer_issue_files/E12_not_first.py index eede02f..5003b35 100644 --- a/test/normalizer_issue_files/E12_not_first.py +++ b/test/normalizer_issue_files/E12_not_first.py @@ -216,7 +216,7 @@ if (a == 2 or "jkl mno"): return True -#: E129+1:4 E127+2:9 +#: E129+1:4 if (a == 2 or b == """abc def ghi jkl mno"""): diff --git a/test/normalizer_issue_files/E12_not_second.py b/test/normalizer_issue_files/E12_not_second.py index 9906cf0..d5261b0 100644 --- a/test/normalizer_issue_files/E12_not_second.py +++ b/test/normalizer_issue_files/E12_not_second.py @@ -93,7 +93,7 @@ help = ur"print total number of errors " \ help = b"print total number of errors " \ b"to standard error" -#: E126+1:5 +#: E122+1:5 help = br"print total number of errors " \ br"to standard error" diff --git a/test/normalizer_issue_files/E12_second.py b/test/normalizer_issue_files/E12_second.py index 1628c94..fffda78 100644 --- a/test/normalizer_issue_files/E12_second.py +++ b/test/normalizer_issue_files/E12_second.py @@ -134,11 +134,11 @@ my_list = [ 4, 5, 6, #: E123:8 ] -#: E126+1:8 E126+2:8 + abris = 3 + \ 4 + \ 5 + 6 -#: E126+1:8 + fixed = re.sub(r'\t+', ' ', target[c::-1], 1)[::-1] + \ target[c + 1:] @@ -156,25 +156,26 @@ eat_a_dict_a_day({ #: E129+1:4 if ( x == ( - #: E126:12 3 + #: E129:4 ) or y == 4): pass -#: E129+1:4 E129+4:4 +#: E129+1:4 E121+2:8 E129+3:4 if ( x == ( 3 ) or - x == ( - #: E126:12 + x == ( + # This one has correct indentation. 3 + #: E129:4 ) or y == 4): pass troublesome_hash = { "hash": "value", - #: E131+1:8 + #: E135+1:8 "long": "the quick brown fox jumps over the lazy dog before doing a " "somersault", } diff --git a/test/normalizer_issue_files/E12_third.py b/test/normalizer_issue_files/E12_third.py index d839d3e..f7ab8db 100644 --- a/test/normalizer_issue_files/E12_third.py +++ b/test/normalizer_issue_files/E12_third.py @@ -58,10 +58,13 @@ rv.update(d=('a', 'b', 'c'), #: E127:13 e=42) -#: E127+2:17 +#: E135+2:17 rv.update(d=('a' + 'b', 'c'), e=42, f=42 + 42) +rv.update(d=('a' + 'b', 'c'), + e=42, f=42 + + 42) #: E127+1:26 input1 = {'a': {'calc': 1 + 2}, 'b': 1 + 42} @@ -102,7 +105,7 @@ print dedent( mkdir -p ./{build}/ mv ./build/ ./{build}/%(revision)s/ '''.format( - #: E121:4 E121+1:5 E123+2:0 + #: E121:4 E123+2:0 build='build', # more stuff ) @@ -112,5 +115,5 @@ if True:\ print(True) #: E128+1 -print(a +foobar(a , end=' ') diff --git a/test/normalizer_issue_files/E20.py b/test/normalizer_issue_files/E20.py new file mode 100644 index 0000000..8de71f7 --- /dev/null +++ b/test/normalizer_issue_files/E20.py @@ -0,0 +1,53 @@ +#: E201:5 +spam( ham[1], {eggs: 2}) +#: E201:9 +spam(ham[ 1], {eggs: 2}) +#: E201:14 +spam(ham[1], { eggs: 2}) + +# Okay +spam(ham[1], {eggs: 2}) + + +#: E202:22 +spam(ham[1], {eggs: 2} ) +#: E202:21 +spam(ham[1], {eggs: 2 }) +#: E202:10 +spam(ham[1 ], {eggs: 2}) +# Okay +spam(ham[1], {eggs: 2}) + +result = func( + arg1='some value', + arg2='another value', +) + +result = func( + arg1='some value', + arg2='another value' +) + +result = [ + item for item in items + if item > 5 +] + +#: E203:9 +if x == 4 : + print x, y + x, y = y, x +if x == 4: + #: E203:12 E702:13 + a = x, y ; x, y = y, x +if x == 4: + print x, y + #: E203:12 + x, y = y , x +# Okay +if x == 4: + print x, y + x, y = y, x +a[b1, :] == a[b1, ...] +a[b1, :1] == 3 +b = a[:, b1]