Skip to content

Commit

Permalink
Fix crash with walrus + await + with (#3473)
Browse files Browse the repository at this point in the history
Fixes #3472
  • Loading branch information
JelleZijlstra authored Jan 18, 2023
1 parent 24469c9 commit 7e6d3fa
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
- Fix two crashes in preview style involving edge cases with docstrings (#3451)
- Exclude string type annotations from improved string processing; fix crash when the
return type annotation is stringified and spans across multiple lines (#3462)
- Fix several crashes in preview style with walrus operators used in `with` statements
or tuples (#3473)

### Configuration

Expand Down
4 changes: 4 additions & 0 deletions src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
is_rpar_token,
is_stub_body,
is_stub_suite,
is_tuple_containing_walrus,
is_vararg,
is_walrus_assignment,
is_yield,
Expand Down Expand Up @@ -1279,6 +1280,7 @@ def maybe_make_parens_invisible_in_atom(
not remove_brackets_around_comma
and max_delimiter_priority_in_atom(node) >= COMMA_PRIORITY
)
or is_tuple_containing_walrus(node)
):
return False

Expand All @@ -1290,9 +1292,11 @@ def maybe_make_parens_invisible_in_atom(
syms.return_stmt,
syms.except_clause,
syms.funcdef,
syms.with_stmt,
# these ones aren't useful to end users, but they do please fuzzers
syms.for_stmt,
syms.del_stmt,
syms.for_stmt,
]:
return False

Expand Down
11 changes: 11 additions & 0 deletions src/black/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,17 @@ def is_one_tuple(node: LN) -> bool:
)


def is_tuple_containing_walrus(node: LN) -> bool:
"""Return True if `node` holds a tuple that contains a walrus 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.namedexpr_test for child in gexp.children)


def is_one_sequence_between(
opening: Leaf,
closing: Leaf,
Expand Down
4 changes: 4 additions & 0 deletions tests/data/fast/pep_572_do_not_remove_parens.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@
@(please := stop)
def sigh():
pass


for (x := 3, y := 4) in y:
pass
40 changes: 40 additions & 0 deletions tests/data/py_38/pep_572_remove_parens.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ def a():
def this_is_so_dumb() -> (please := no):
pass

async def await_the_walrus():
with (x := y):
pass

with (x := y) as z, (a := b) as c:
pass

with (x := await y):
pass

with (x := await a, y := await b):
pass

# Ideally we should remove one set of parentheses
with ((x := await a, y := await b)):
pass

with (x := await a), (y := await b):
pass


# output
if foo := 0:
Expand Down Expand Up @@ -103,3 +123,23 @@ def a():
def this_is_so_dumb() -> (please := no):
pass


async def await_the_walrus():
with (x := y):
pass

with (x := y) as z, (a := b) as c:
pass

with (x := await y):
pass

with (x := await a, y := await b):
pass

# Ideally we should remove one set of parentheses
with ((x := await a, y := await b)):
pass

with (x := await a), (y := await b):
pass

0 comments on commit 7e6d3fa

Please sign in to comment.