From c31425e434a7e4f8b3e38ba344f940326787bd93 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 25 Dec 2022 06:46:43 -0800 Subject: [PATCH 1/4] Fix crash with walrus + await + with Fixes #3472 --- CHANGES.md | 1 + src/black/linegen.py | 1 + tests/data/py_38/pep_572_remove_parens.py | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 587ca8a2a0d..f6129363aef 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,6 +33,7 @@ string lambda values are now wrapped in parentheses (#3440) - Exclude string type annotations from improved string processing; fix crash when the return type annotation is stringified and spans across multiple lines (#3462) +- Fix a crash in preview style with walrus operators used in `await` statements (#3473) ### Configuration diff --git a/src/black/linegen.py b/src/black/linegen.py index 2e75bc94506..ce003f0c2f9 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -1270,6 +1270,7 @@ 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, diff --git a/tests/data/py_38/pep_572_remove_parens.py b/tests/data/py_38/pep_572_remove_parens.py index 9718d95b499..4bf753952ba 100644 --- a/tests/data/py_38/pep_572_remove_parens.py +++ b/tests/data/py_38/pep_572_remove_parens.py @@ -49,6 +49,9 @@ def a(): def this_is_so_dumb() -> (please := no): pass +async def await_the_walrus(): + with (x := await y): + pass # output if foo := 0: @@ -103,3 +106,7 @@ def a(): def this_is_so_dumb() -> (please := no): pass + +async def await_the_walrus(): + with (x := await y): + pass From e27cc3a1d997024cbb659367e04d7778731377c9 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 25 Dec 2022 07:23:41 -0800 Subject: [PATCH 2/4] Fix more crashes --- CHANGES.md | 3 ++- src/black/linegen.py | 3 +++ src/black/nodes.py | 14 ++++++++++++++ .../data/fast/pep_572_do_not_remove_parens.py | 4 ++++ tests/data/py_38/pep_572_remove_parens.py | 19 +++++++++++++++++++ 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index f6129363aef..2cbfc977a85 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -33,7 +33,8 @@ string lambda values are now wrapped in parentheses (#3440) - Exclude string type annotations from improved string processing; fix crash when the return type annotation is stringified and spans across multiple lines (#3462) -- Fix a crash in preview style with walrus operators used in `await` statements (#3473) +- Fix several crashes in preview style with walrus operators used in `with` statements + or tuples (#3473) ### Configuration diff --git a/src/black/linegen.py b/src/black/linegen.py index ce003f0c2f9..b2a6d00bc0c 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -46,6 +46,7 @@ is_rpar_token, is_stub_body, is_stub_suite, + is_tuple_containing_walrus, is_vararg, is_walrus_assignment, is_yield, @@ -1259,6 +1260,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 @@ -1274,6 +1276,7 @@ def maybe_make_parens_invisible_in_atom( # these ones aren't useful to end users, but they do please fuzzers syms.for_stmt, syms.del_stmt, + syms.for_stmt, ]: return False diff --git a/src/black/nodes.py b/src/black/nodes.py index a11fb7cc071..3b3c85b955b 100644 --- a/src/black/nodes.py +++ b/src/black/nodes.py @@ -563,6 +563,20 @@ 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, diff --git a/tests/data/fast/pep_572_do_not_remove_parens.py b/tests/data/fast/pep_572_do_not_remove_parens.py index 20e80a69377..05619ddcc2b 100644 --- a/tests/data/fast/pep_572_do_not_remove_parens.py +++ b/tests/data/fast/pep_572_do_not_remove_parens.py @@ -19,3 +19,7 @@ @(please := stop) def sigh(): pass + + +for (x := 3, y := 4) in y: + pass diff --git a/tests/data/py_38/pep_572_remove_parens.py b/tests/data/py_38/pep_572_remove_parens.py index 4bf753952ba..c1d79336404 100644 --- a/tests/data/py_38/pep_572_remove_parens.py +++ b/tests/data/py_38/pep_572_remove_parens.py @@ -53,6 +53,16 @@ async def await_the_walrus(): with (x := await y): pass + with (x := await a, y := await b): + pass + + with ((x := await a, y := await b)): + pass + + with (x := await a), (y := await b): + pass + + # output if foo := 0: pass @@ -110,3 +120,12 @@ def this_is_so_dumb() -> (please := no): async def await_the_walrus(): with (x := await y): pass + + with (x := await a, y := await b): + pass + + with ((x := await a, y := await b)): + pass + + with (x := await a), (y := await b): + pass From c6e09d0b9329424acb71a97ca991f5266210d596 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 25 Dec 2022 07:48:45 -0800 Subject: [PATCH 3/4] format self --- src/black/nodes.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/black/nodes.py b/src/black/nodes.py index 3b3c85b955b..a588077f4de 100644 --- a/src/black/nodes.py +++ b/src/black/nodes.py @@ -571,10 +571,7 @@ def is_tuple_containing_walrus(node: LN) -> bool: if gexp is None or gexp.type != syms.testlist_gexp: return False - return any( - child.type == syms.namedexpr_test - for child in gexp.children - ) + return any(child.type == syms.namedexpr_test for child in gexp.children) def is_one_sequence_between( From 46f7e55690a3f08fe95f8246d724df5ee6f9d21c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 25 Dec 2022 18:47:03 -0800 Subject: [PATCH 4/4] add a few more cases --- tests/data/py_38/pep_572_remove_parens.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/data/py_38/pep_572_remove_parens.py b/tests/data/py_38/pep_572_remove_parens.py index c1d79336404..4e95fb07f3a 100644 --- a/tests/data/py_38/pep_572_remove_parens.py +++ b/tests/data/py_38/pep_572_remove_parens.py @@ -50,12 +50,19 @@ 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 @@ -118,12 +125,19 @@ def this_is_so_dumb() -> (please := no): 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