diff --git a/pycodestyle.py b/pycodestyle.py index 83069c50..cbbcf4a5 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -422,8 +422,69 @@ def blank_lines(logical_line, blank_lines, indent_level, line_number, top_level_lines, blank_before) +def _E203(tokens, count): + """Additional check for E203 to allow whitespace in slices""" + + sqbrackets = 0 + last = 0 + + col_count = 0 + + in_lambda = False + delim_history = [] + + for token in tokens: + if token.exact_type == tokenize.LSQB: + sqbrackets += 1 + elif token.exact_type == tokenize.RSQB: + sqbrackets -= 1 + if token.exact_type in ( + tokenize.LBRACE, tokenize.RBRACE, tokenize.RSQB, tokenize.LSQB + ): + delim_history.append(token.exact_type) + + if token.exact_type == tokenize.NAME and token[1] == "lambda": + in_lambda = True + + if token.exact_type == tokenize.COLON and col_count == count: + + # Colon not inside brackets or + # following another colon or in lambda expression + if sqbrackets <= 0 or last == tokenize.COLON or in_lambda: + return True + + # Colon in dict + if tokenize.LBRACE not in delim_history: + break + needs = 0 + count = 0 + for d in delim_history[::-1]: + if needs == 0: + if d == tokenize.LBRACE: + return True + if d == tokenize.LSQB: + return False + needs = d - 1 + else: + if d == needs: + if count == 0: + needs = 0 + else: + count -= 1 + if d == needs + 1: + count += 1 + break + + if token.exact_type == tokenize.COLON: + col_count += 1 + in_lambda = False + last = token.exact_type + + return False + + @register_check -def extraneous_whitespace(logical_line): +def extraneous_whitespace(logical_line, tokens): r"""Avoid extraneous whitespace. Avoid extraneous whitespace in these situations: @@ -442,7 +503,8 @@ def extraneous_whitespace(logical_line): E203: if x == 4: print x, y ; x, y = y, x E203: if x == 4 : print x, y; x, y = y, x """ - line = logical_line + line: str = logical_line + colons = [m.end() for m in re.compile(r":").finditer(line)] for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line): text = match.group() char = text.strip() @@ -451,6 +513,9 @@ def extraneous_whitespace(logical_line): # assert char in '([{' yield found + 1, "E201 whitespace after '%s'" % char elif line[found - 1] != ',': + if (char == ":" and line[found - 1] != " " and + not _E203(tokens, colons.index(match.end()))): + continue code = ('E202' if char in '}])' else 'E203') # if char in ',;:' yield found, f"{code} whitespace before '{char}'" diff --git a/testsuite/E20.py b/testsuite/E20.py index 20c6dfd8..bd20ebe0 100644 --- a/testsuite/E20.py +++ b/testsuite/E20.py @@ -69,10 +69,28 @@ if x == 4: print x, y x, y = y , x +#: E203:1:20 +ham[lower + offset : upper + offset] +#: E203:1:12 +ham[lower : : upper] +#: E203:1:14 +ham[(lambda x : x)(5) :] +#: E203:1:9 +ham[{"a" : 6}["a"] :] +#: E203:1:38 +ham[{"a": [1, {}, {"a": [{}, []], "b" :[3]}, 3][1 : 3]}["a"] :] #: Okay if x == 4: print x, y x, y = y, x a[b1, :] == a[b1, ...] b = a[:, b1] +ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] +ham[lower:upper], ham[lower:upper:], ham[lower::step] +ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)] +ham[{"a": [1, {}, {"a": [{}, []], "b": [3]}, 3][1 : 3]}["a"] :] +append_leaves( + new_line, line, LL[string_idx + 1 : rpar_idx] + LL[rpar_idx + 1 :] +) +if token.PERCENT in {leaf.type for leaf in LL[idx - 1 : next_idx]} #: diff --git a/testsuite/python35.py b/testsuite/python35.py index 1bedee5d..d653fc85 100644 --- a/testsuite/python35.py +++ b/testsuite/python35.py @@ -4,3 +4,5 @@ def bar(a, b)->int: #: Okay def baz(a, b) -> int: pass +#: E203 +a : int