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

W504: Fix positional-only / keyword-only mark being treated as a binary operator #1098

Open
wants to merge 3 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions pycodestyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,9 @@ def _break_around_binary_operators(tokens):
"""
line_break = False
unary_context = True
param_name_context = False
# only counted when inside param list, `-1` when not counting
enclosure_count = -1
# Previous non-newline token types and text
previous_token_type = None
previous_text = None
Expand All @@ -1301,11 +1304,30 @@ def _break_around_binary_operators(tokens):
line_break = True
else:
yield (token_type, text, previous_token_type, previous_text,
line_break, unary_context, start)
line_break, unary_context, param_name_context, start)
unary_context = text in '([{,;'
line_break = False
previous_token_type = token_type
previous_text = text
if enclosure_count != -1:
if token_type != tokenize.OP:
pass
elif text in '([{':
enclosure_count += 1
elif text in ')]}':
enclosure_count -= 1
if enclosure_count == 0:
# stop counting enclosures
enclosure_count = -1
elif token_type == tokenize.NAME and text == 'def':
# start counting enclosures
enclosure_count = 0
# check for enclosure count and last token to make sure that
# only the actual positional-only marker matches here:
# def f(
# x=4/2, y=(1, 4/2), /
# ):
param_name_context = text == ',' and enclosure_count == 1


@register_check
Expand All @@ -1330,9 +1352,10 @@ def break_before_binary_operator(logical_line, tokens):
"""
for context in _break_around_binary_operators(tokens):
(token_type, text, previous_token_type, previous_text,
line_break, unary_context, start) = context
line_break, unary_context, param_name_context, start) = context
if (_is_binary_operator(token_type, text) and line_break and
not unary_context and
not param_name_context and
not _is_binary_operator(previous_token_type,
previous_text)):
yield start, "W503 line break before binary operator"
Expand Down Expand Up @@ -1362,15 +1385,18 @@ def break_after_binary_operator(logical_line, tokens):
Okay: var = (1 +\n -1 +\n -2)
"""
prev_start = None
prev_param_name_context = False
for context in _break_around_binary_operators(tokens):
(token_type, text, previous_token_type, previous_text,
line_break, unary_context, start) = context
line_break, unary_context, param_name_context, start) = context
if (_is_binary_operator(previous_token_type, previous_text) and
line_break and
not unary_context and
not prev_param_name_context and
not _is_binary_operator(token_type, text)):
yield prev_start, "W504 line break after binary operator"
prev_start = start
prev_param_name_context = param_name_context


@register_check
Expand Down
52 changes: 52 additions & 0 deletions testsuite/python3.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,55 @@ def f(
x: str = ...
):
...
#: E203
def f(
x=4 / 2, y=(1, 4 / 2), *
, arg
):
...
#: E203 W504:4:14
def f(
x=4 * 2,
y=(
1, 4 *
2
),
*
, arg
):
...
#: E203 W504:2:9
def f(
x=4 *
2,
y=(1, 4 * 2),
*
, arg
):
...
#: E203
def f(
x=4 * 2, y=(1, 4 * 2), *
, arg
):
...
#: E203 W503:5:9
def f(
x=4 * 2,
y=(
1, 4
* 2
),
*
, arg
):
...
#: E203 W503:3:5
def f(
x=4
* 2,
y=(1, 4 * 2),
*
, arg
):
...
46 changes: 46 additions & 0 deletions testsuite/python38.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,49 @@ def f3(
#: E741
if (l := 1):
pass
#: Okay
def f(
x=4 / 2, y=(1, 4 / 2), /
):
...
#: W504:4:14
def f(
x=4 / 2,
y=(
1, 4 /
2
),
/
):
...
#: W504:2:9
def f(
x=4 /
2,
y=(1, 4 / 2),
/
):
...
#: Okay
def f(
x=4 / 2, y=(1, 4 / 2), /
):
...
#: W503:5:9
def f(
x=4 / 2,
y=(
1, 4
/ 2
),
/
):
...
#: W503:3:5
def f(
x=4
/ 2,
y=(1, 4 / 2),
/
):
...