Skip to content

Commit 86a51c5

Browse files
committed
Fix false alarm in E203 rule.
E203 checks for extraneous whitespace before a colon. Yet the colon can be used as a "slice" operator, and as such PEP8 asks for 0 or 1 whitespaces on both sides of the operator.
1 parent d69c15e commit 86a51c5

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

pycodestyle.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,12 @@ def extraneous_whitespace(logical_line):
413413
- Immediately inside parentheses, brackets or braces.
414414
- Immediately before a comma, semicolon, or colon.
415415
416+
Exceptions:
417+
- When the colon acts as a slice, the rule of binary operators
418+
applies and we should have the same amount of space on either side
419+
- When the colon acts as a slice but a parameter is omitted, then
420+
the space is omitted
421+
416422
Okay: spam(ham[1], {eggs: 2})
417423
E201: spam( ham[1], {eggs: 2})
418424
E201: spam(ham[ 1], {eggs: 2})
@@ -421,10 +427,32 @@ def extraneous_whitespace(logical_line):
421427
E202: spam(ham[1 ], {eggs: 2})
422428
E202: spam(ham[1], {eggs: 2 })
423429
430+
Okay: ham[8 : 2]
431+
Okay: ham[: 2]
424432
E203: if x == 4: print x, y; x, y = y , x
425433
E203: if x == 4: print x, y ; x, y = y, x
426434
E203: if x == 4 : print x, y; x, y = y, x
427435
"""
436+
437+
def is_a_slice(line, colon_position):
438+
"""Check colon acts as a slice
439+
440+
Return True if the colon is directly contained within
441+
square brackets.
442+
"""
443+
parentheses_brackets_braces = list()
444+
for i in range(colon_position):
445+
c = line[i]
446+
if c in '[({':
447+
parentheses_brackets_braces += c
448+
elif c in '])}':
449+
last_opened = parentheses_brackets_braces.pop()
450+
expected_close = {'{': '}', '(': ')', '[': ']'}[last_opened]
451+
if c != expected_close: # invalid Python code
452+
return False
453+
return (len(parentheses_brackets_braces) > 0 and
454+
parentheses_brackets_braces.pop() == '[')
455+
428456
line = logical_line
429457
for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
430458
text = match.group()
@@ -433,7 +461,8 @@ def extraneous_whitespace(logical_line):
433461
if text == char + ' ':
434462
# assert char in '([{'
435463
yield found + 1, "E201 whitespace after '%s'" % char
436-
elif line[found - 1] != ',':
464+
elif (line[found - 1] != ',' and
465+
not (char == ':' and is_a_slice(line, found))):
437466
code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
438467
yield found, "%s whitespace before '%s'" % (code, char)
439468

testsuite/E20.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,16 @@
4646
if x == 4:
4747
print x, y
4848
x, y = y , x
49+
#: E203:1:37
50+
foo[idxs[2 : 6] : spam(ham[1], {eggs : a[2 : 4]})]
4951
#: Okay
5052
if x == 4:
5153
print x, y
5254
x, y = y, x
5355
a[b1, :] == a[b1, ...]
5456
b = a[:, b1]
57+
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
58+
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
59+
ham[lower + offset : upper + offset]
60+
foo[idxs[2 : 6] : spam(ham[1], {eggs: a[2 : 4]})]
5561
#:

0 commit comments

Comments
 (0)