Skip to content

Commit

Permalink
Fix crash on formatting certain with statements (#4538)
Browse files Browse the repository at this point in the history
Fixes #3678
  • Loading branch information
MeGaGiGaGon authored Dec 24, 2024
1 parent 0aabac4 commit 3b00112
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
- Fix formatting cells in IPython notebooks with magic methods and starting or trailing
empty lines (#4484)

- Fix crash when formatting `with` statements containing tuple generators/unpacking
(#4538)

### Preview style

<!-- Changes that affect Black's preview style -->
Expand Down
4 changes: 4 additions & 0 deletions src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
is_atom_with_invisible_parens,
is_docstring,
is_empty_tuple,
is_generator,
is_lpar_token,
is_multiline_string,
is_name_token,
Expand All @@ -55,6 +56,7 @@
is_rpar_token,
is_stub_body,
is_stub_suite,
is_tuple_containing_star,
is_tuple_containing_walrus,
is_type_ignore_comment_string,
is_vararg,
Expand Down Expand Up @@ -1628,6 +1630,8 @@ def maybe_make_parens_invisible_in_atom(
and max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
)
or is_tuple_containing_walrus(node)
or is_tuple_containing_star(node)
or is_generator(node)
):
return False

Expand Down
22 changes: 22 additions & 0 deletions src/black/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,28 @@ def is_tuple_containing_walrus(node: LN) -> bool:
return any(child.type == syms.namedexpr_test for child in gexp.children)


def is_tuple_containing_star(node: LN) -> bool:
"""Return True if `node` holds a tuple that contains a star operator."""
if node.type != syms.atom:
return False
gexp = unwrap_singleton_parenthesis(node)
if gexp is None or gexp.type != syms.testlist_gexp:
return False

return any(child.type == syms.star_expr for child in gexp.children)


def is_generator(node: LN) -> bool:
"""Return True if `node` holds a generator."""
if node.type != syms.atom:
return False
gexp = unwrap_singleton_parenthesis(node)
if gexp is None or gexp.type != syms.testlist_gexp:
return False

return any(child.type == syms.old_comp_for for child in gexp.children)


def is_one_sequence_between(
opening: Leaf,
closing: Leaf,
Expand Down
26 changes: 26 additions & 0 deletions tests/data/cases/remove_with_brackets.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@
with ((((CtxManager1()))) as example1, (((CtxManager2()))) as example2):
...

# regression tests for #3678
with (a, *b):
pass

with (a, (b, *c)):
pass

with (a for b in c):
pass

with (a, (b for c in d)):
pass

# output
with open("bla.txt"):
pass
Expand Down Expand Up @@ -117,3 +130,16 @@

with CtxManager1() as example1, CtxManager2() as example2:
...

# regression tests for #3678
with (a, *b):
pass

with a, (b, *c):
pass

with (a for b in c):
pass

with a, (b for c in d):
pass

0 comments on commit 3b00112

Please sign in to comment.