Skip to content

Commit dedd237

Browse files
committed
Add support for assignment expressions
Introduced in Python 3.8 with PEP-572. Refer to https://www.python.org/dev/peps/pep-0572.
1 parent 9726e10 commit dedd237

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

pycodestyle.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,13 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
117117
WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
118118
# Warn for -> function annotation operator in py3.5+ (issue 803)
119119
FUNCTION_RETURN_ANNOTATION_OP = ['->'] if sys.version_info >= (3, 5) else []
120+
ASSIGNMENT_EXPRESSION_OP = [':='] if sys.version_info >= (3, 8) else []
120121
WS_NEEDED_OPERATORS = frozenset([
121122
'**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
122123
'%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=',
123124
'and', 'in', 'is', 'or'] +
124-
FUNCTION_RETURN_ANNOTATION_OP)
125+
FUNCTION_RETURN_ANNOTATION_OP +
126+
ASSIGNMENT_EXPRESSION_OP)
125127
WHITESPACE = frozenset(' \t')
126128
NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
127129
SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
@@ -134,7 +136,7 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
134136
RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
135137
ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
136138
DOCSTRING_REGEX = re.compile(r'u?r?["\']')
137-
EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({] | [\]}),;:]')
139+
EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({] | [\]}),;]| :(?!=)')
138140
WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
139141
COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
140142
r'\s*(?(1)|(None|False|True))\b')
@@ -495,13 +497,16 @@ def missing_whitespace(logical_line):
495497
line = logical_line
496498
for index in range(len(line) - 1):
497499
char = line[index]
498-
if char in ',;:' and line[index + 1] not in WHITESPACE:
500+
next_char = line[index + 1]
501+
if char in ',;:' and next_char not in WHITESPACE:
499502
before = line[:index]
500503
if char == ':' and before.count('[') > before.count(']') and \
501504
before.rfind('{') < before.rfind('['):
502505
continue # Slice syntax, no space required
503-
if char == ',' and line[index + 1] == ')':
506+
if char == ',' and next_char == ')':
504507
continue # Allow tuple with only one element: (3,)
508+
if char == ':' and next_char == '=' and sys.version_info >= (3, 8):
509+
continue # Allow assignment expression
505510
yield index, "E231 missing whitespace after '%s'" % char
506511

507512

@@ -1141,7 +1146,9 @@ def compound_statements(logical_line):
11411146
update_counts(line[prev_found:found], counts)
11421147
if ((counts['{'] <= counts['}'] and # {'a': 1} (dict)
11431148
counts['['] <= counts[']'] and # [1:2] (slice)
1144-
counts['('] <= counts[')'])): # (annotation)
1149+
counts['('] <= counts[')']) and # (annotation)
1150+
not (sys.version_info >= (3, 8) and
1151+
line[found + 1] == '=')): # assignment expression
11451152
lambda_kw = LAMBDA_REGEX.search(line, 0, found)
11461153
if lambda_kw:
11471154
before = line[:lambda_kw.start()].rstrip()

testsuite/python38.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#: Okay
2+
if x := 1:
3+
print(x)
4+
if m and (token := m.group(1)):
5+
pass
6+
stuff = [[y := f(x), x / y] for x in range(5)]
7+
#: E225:1:5
8+
if x:= 1:
9+
pass
10+
#: E225:1:18
11+
if False or (x :=1):
12+
pass

tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# and then run "tox" from this directory.
55

66
[tox]
7-
envlist = py27, py34, py35, py36, py37, pypy, pypy3, jython
7+
envlist = py27, py34, py35, py36, py37, py38, pypy, pypy3, jython
88
skipsdist = True
99
skip_missing_interpreters = True
1010

0 commit comments

Comments
 (0)