Skip to content
New issue

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

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

Already on GitHub? # to your account

Fix necessary parentheses in multi-line unpacking #16

Merged
merged 7 commits into from
Sep 22, 2022
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/setup-python@v4
- run: pip install -r requirements.txt
- uses: pre-commit/action@v3.0.0
build:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

## 0.1.1
***
**🔧 Fixes**
* Fix complaining about necessary parentheses in multi-line unpacking
assignments
([#16](https://github.com/robsdedude/flake8-picky-parentheses/pull/16)).

## 0.1.0
***
**🎉 Initial release**
72 changes: 35 additions & 37 deletions flake8_picky_parentheses/_redundant_parentheses.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ def _check_parens_is_tuple(node, parens_coords):
)

def checked_parentheses(self, coords) -> bool:
if coords in self.exceptions or coords[0] in self.problems:
return True
return False
return coords in self.exceptions or coords[0] in self.problems

def check(self) -> None:
msg = "PAR001: Too many parentheses"
Expand All @@ -93,7 +91,7 @@ def check(self) -> None:
ast.BinOp, ast.BoolOp, ast.UnaryOp, ast.Compare, ast.Await
)
for node in ast.walk(self.tree):
breaker = None
breaker = False
if isinstance(node, ast.Slice):
for child in ast.iter_child_nodes(node):
for coords in self.parens_coords:
Expand All @@ -103,11 +101,11 @@ def check(self) -> None:
== (child.lineno, child.col_offset)
and isinstance(child,
special_ops_pair_exceptions)):
breaker = 1
breaker = True
self.exceptions.append(coords)
if breaker:
break
if isinstance(node, special_ops_pair_exceptions):
elif isinstance(node, special_ops_pair_exceptions):
for child in ast.iter_child_nodes(node):
if not isinstance(child, special_ops_pair_exceptions):
continue
Expand All @@ -117,53 +115,53 @@ def check(self) -> None:
continue
if self._node_in_parens(child, coords):
self.exceptions.append(coords)
breaker = 1
breaker = True
break
if breaker:
break

if isinstance(node, ast.Assign):
elif isinstance(node, ast.Assign):
for target in node.targets:
if not isinstance(target, ast.Tuple):
continue
for elts in target.elts:
tuple_coords = (target.lineno, target.col_offset)
elts_coords = (elts.lineno, elts.col_offset)
if tuple_coords > elts_coords:
if not target.elts:
continue
elt = target.elts[0]
elt_coords = (elt.lineno, elt.col_offset)
matching_parens = None
for coords in self.parens_coords:
if self.checked_parentheses(coords):
continue
for coords in self.parens_coords:
if self.checked_parentheses(coords):
continue
if (coords[0][1] <= tuple_coords[1]
and coords[0][0] == tuple_coords[0]):
self.exceptions.append(coords)
breaker = 1
break
if not any(
self.file_tokens_nn[token].start == elts_coords
and self.file_tokens_nn[token - 1].string
== "("
for token in range(len(self.file_tokens_nn))
):
if self._node_in_parens(elt, coords):
matching_parens = coords
break
self.problems.append((
node.lineno, node.col_offset,
"PAR002: Dont use parentheses for "
"unpacking"
))
break
if breaker:
if not matching_parens:
continue
if not any(
self.file_tokens_nn[token].start == elt_coords
and self.file_tokens_nn[token - 1].string
== "("
for token in range(len(self.file_tokens_nn))
):
break

if isinstance(node, ast.Tuple):
self.problems.append((
node.lineno, node.col_offset,
"PAR002: Dont use parentheses for "
"unpacking"
))
# no need to treat them again later
self.exceptions.append(matching_parens)
break

elif isinstance(node, ast.Tuple):
for coords in self.parens_coords:
if self.checked_parentheses(coords):
continue
if self._check_parens_is_tuple(node, coords):
self.exceptions.append(coords)
break

if isinstance(node, ast.comprehension):
elif isinstance(node, ast.comprehension):
for coords in self.parens_coords:
if self.checked_parentheses(coords):
continue
Expand All @@ -172,7 +170,7 @@ def check(self) -> None:
break
if coords.open_[0] != coords.close[0]:
self.exceptions.append(coords)
breaker = 1
breaker = True
break
if breaker:
break
Expand Down
16 changes: 16 additions & 0 deletions tests/test_redundant_parentheses.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,22 @@ def test_ugly_multiline_unpacking(plugin):
assert len(plugin(s)) == 1


# GOOD (unpacking with line break)
def test_multiline_unpacking_implicit_tuple_literal(plugin):
s = """(
a, b
) = 1, 2"""
assert not plugin(s)


# GOOD (unpacking with line break)
def test_multiline_unpacking_explicit_tuple_literal(plugin):
s = """(
a, b
) = (1, 2)"""
assert not plugin(s)


# GOOD (parentheses for tuple literal are optional)
def test_tuple_literal_unpacking_in_if(plugin):
s = """if foo:
Expand Down