Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix E203 false positive in list slices #1047

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
69 changes: 67 additions & 2 deletions pycodestyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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()
Expand All @@ -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}'"

Expand Down
18 changes: 18 additions & 0 deletions testsuite/E20.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]}
#:
2 changes: 2 additions & 0 deletions testsuite/python35.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ def bar(a, b)->int:
#: Okay
def baz(a, b) -> int:
pass
#: E203
a : int