Remove unnecessary parentheses from tuple unpacking in for loops (#2945)

This commit is contained in:
Joe Young 2022-03-24 14:59:54 +00:00 committed by GitHub
parent 3800ebd81d
commit 14e5ce5412
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 11 deletions

View File

@ -15,6 +15,7 @@
<!-- Changes that affect Black's preview style --> <!-- Changes that affect Black's preview style -->
- Code cell separators `#%%` are now standardised to `# %%` (#2919) - Code cell separators `#%%` are now standardised to `# %%` (#2919)
- Remove unnecessary parentheses from tuple unpacking in `for` loops (#2945)
- Avoid magic-trailing-comma in single-element subscripts (#2942) - Avoid magic-trailing-comma in single-element subscripts (#2942)
### _Blackd_ ### _Blackd_

View File

@ -841,7 +841,11 @@ def normalize_invisible_parens(
if check_lpar: if check_lpar:
if child.type == syms.atom: if child.type == syms.atom:
if maybe_make_parens_invisible_in_atom(child, parent=node): if maybe_make_parens_invisible_in_atom(
child,
parent=node,
preview=preview,
):
wrap_in_parentheses(node, child, visible=False) wrap_in_parentheses(node, child, visible=False)
elif is_one_tuple(child): elif is_one_tuple(child):
wrap_in_parentheses(node, child, visible=True) wrap_in_parentheses(node, child, visible=True)
@ -865,7 +869,11 @@ def normalize_invisible_parens(
check_lpar = isinstance(child, Leaf) and child.value in parens_after check_lpar = isinstance(child, Leaf) and child.value in parens_after
def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool: def maybe_make_parens_invisible_in_atom(
node: LN,
parent: LN,
preview: bool = False,
) -> bool:
"""If it's safe, make the parens in the atom `node` invisible, recursively. """If it's safe, make the parens in the atom `node` invisible, recursively.
Additionally, remove repeated, adjacent invisible parens from the atom `node` Additionally, remove repeated, adjacent invisible parens from the atom `node`
as they are redundant. as they are redundant.
@ -873,13 +881,23 @@ def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool:
Returns whether the node should itself be wrapped in invisible parentheses. Returns whether the node should itself be wrapped in invisible parentheses.
""" """
if (
preview
and parent.type == syms.for_stmt
and isinstance(node.prev_sibling, Leaf)
and node.prev_sibling.type == token.NAME
and node.prev_sibling.value == "for"
):
for_stmt_check = False
else:
for_stmt_check = True
if ( if (
node.type != syms.atom node.type != syms.atom
or is_empty_tuple(node) or is_empty_tuple(node)
or is_one_tuple(node) or is_one_tuple(node)
or (is_yield(node) and parent.type != syms.expr_stmt) or (is_yield(node) and parent.type != syms.expr_stmt)
or max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY or (max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY and for_stmt_check)
): ):
return False return False
@ -902,7 +920,7 @@ def maybe_make_parens_invisible_in_atom(node: LN, parent: LN) -> bool:
# make parentheses invisible # make parentheses invisible
first.value = "" first.value = ""
last.value = "" last.value = ""
maybe_make_parens_invisible_in_atom(middle, parent=parent) maybe_make_parens_invisible_in_atom(middle, parent=parent, preview=preview)
if is_atom_with_invisible_parens(middle): if is_atom_with_invisible_parens(middle):
# Strip the invisible parens from `middle` by replacing # Strip the invisible parens from `middle` by replacing

View File

@ -127,6 +127,7 @@ class Preview(Enum):
"""Individual preview style features.""" """Individual preview style features."""
string_processing = auto() string_processing = auto()
remove_redundant_parens = auto()
one_element_subscript = auto() one_element_subscript = auto()

View File

@ -365,7 +365,7 @@ def do_match(self, line: Line) -> TMatchResult:
is_valid_index = is_valid_index_factory(LL) is_valid_index = is_valid_index_factory(LL)
for (i, leaf) in enumerate(LL): for i, leaf in enumerate(LL):
if ( if (
leaf.type == token.STRING leaf.type == token.STRING
and is_valid_index(i + 1) and is_valid_index(i + 1)
@ -570,7 +570,7 @@ def make_naked(string: str, string_prefix: str) -> str:
# Build the final line ('new_line') that this method will later return. # Build the final line ('new_line') that this method will later return.
new_line = line.clone() new_line = line.clone()
for (i, leaf) in enumerate(LL): for i, leaf in enumerate(LL):
if i == string_idx: if i == string_idx:
new_line.append(string_leaf) new_line.append(string_leaf)
@ -691,7 +691,7 @@ def do_match(self, line: Line) -> TMatchResult:
is_valid_index = is_valid_index_factory(LL) is_valid_index = is_valid_index_factory(LL)
for (idx, leaf) in enumerate(LL): for idx, leaf in enumerate(LL):
# Should be a string... # Should be a string...
if leaf.type != token.STRING: if leaf.type != token.STRING:
continue continue
@ -1713,7 +1713,7 @@ def _assert_match(LL: List[Leaf]) -> Optional[int]:
if parent_type(LL[0]) == syms.assert_stmt and LL[0].value == "assert": if parent_type(LL[0]) == syms.assert_stmt and LL[0].value == "assert":
is_valid_index = is_valid_index_factory(LL) is_valid_index = is_valid_index_factory(LL)
for (i, leaf) in enumerate(LL): for i, leaf in enumerate(LL):
# We MUST find a comma... # We MUST find a comma...
if leaf.type == token.COMMA: if leaf.type == token.COMMA:
idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1
@ -1751,7 +1751,7 @@ def _assign_match(LL: List[Leaf]) -> Optional[int]:
): ):
is_valid_index = is_valid_index_factory(LL) is_valid_index = is_valid_index_factory(LL)
for (i, leaf) in enumerate(LL): for i, leaf in enumerate(LL):
# We MUST find either an '=' or '+=' symbol... # We MUST find either an '=' or '+=' symbol...
if leaf.type in [token.EQUAL, token.PLUSEQUAL]: if leaf.type in [token.EQUAL, token.PLUSEQUAL]:
idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1
@ -1794,7 +1794,7 @@ def _dict_match(LL: List[Leaf]) -> Optional[int]:
if syms.dictsetmaker in [parent_type(LL[0]), parent_type(LL[0].parent)]: if syms.dictsetmaker in [parent_type(LL[0]), parent_type(LL[0].parent)]:
is_valid_index = is_valid_index_factory(LL) is_valid_index = is_valid_index_factory(LL)
for (i, leaf) in enumerate(LL): for i, leaf in enumerate(LL):
# We MUST find a colon... # We MUST find a colon...
if leaf.type == token.COLON: if leaf.type == token.COLON:
idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1 idx = i + 2 if is_empty_par(LL[i + 1]) else i + 1

View File

@ -599,7 +599,7 @@ def foo():
def foo(xxxx): def foo(xxxx):
for (xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx) in xxxx: for xxx_xxxx, _xxx_xxx, _xxx_xxxxx, xxx_xxxx in xxxx:
for xxx in xxx_xxxx: for xxx in xxx_xxxx:
assert ("x" in xxx) or (xxx in xxx_xxx_xxxxx), ( assert ("x" in xxx) or (xxx in xxx_xxx_xxxxx), (
"{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}" "{0} xxxxxxx xx {1}, xxx {1} xx xxx xx xxxx xx xxx xxxx: xxx xxxx {2}"

View File

@ -0,0 +1,40 @@
# Only remove tuple brackets after `for`
for (k, v) in d.items():
print(k, v)
# Don't touch tuple brackets after `in`
for module in (core, _unicodefun):
if hasattr(module, "_verify_python3_env"):
module._verify_python3_env = lambda: None
# Brackets remain for long for loop lines
for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items():
print(k, v)
for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
print(k, v)
# output
# Only remove tuple brackets after `for`
for k, v in d.items():
print(k, v)
# Don't touch tuple brackets after `in`
for module in (core, _unicodefun):
if hasattr(module, "_verify_python3_env"):
module._verify_python3_env = lambda: None
# Brackets remain for long for loop lines
for (
why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long,
i_dont_know_but_we_should_still_check_the_behaviour_if_they_do,
) in d.items():
print(k, v)
for (
k,
v,
) in (
dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items()
):
print(k, v)

View File

@ -80,6 +80,7 @@
"long_strings__edge_case", "long_strings__edge_case",
"long_strings__regression", "long_strings__regression",
"percent_precedence", "percent_precedence",
"remove_for_brackets",
"one_element_subscript", "one_element_subscript",
] ]