Fix crash when a tuple is used as a ContextManager (#4646)
This commit is contained in:
parent
a41dc89f1f
commit
d0ff3bd6cb
@ -15,6 +15,7 @@
|
|||||||
- Handle `# fmt: skip` followed by a comment at the end of file (#4635)
|
- Handle `# fmt: skip` followed by a comment at the end of file (#4635)
|
||||||
- Fix crash when a tuple appears in the `as` clause of a `with` statement
|
- Fix crash when a tuple appears in the `as` clause of a `with` statement
|
||||||
(#4634)
|
(#4634)
|
||||||
|
- Fix crash when tuple is used as a context manager inside a `with` statement (#4646)
|
||||||
|
|
||||||
### Preview style
|
### Preview style
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
ensure_visible,
|
ensure_visible,
|
||||||
fstring_to_string,
|
fstring_to_string,
|
||||||
get_annotation_type,
|
get_annotation_type,
|
||||||
|
has_sibling_with_type,
|
||||||
is_arith_like,
|
is_arith_like,
|
||||||
is_async_stmt_or_funcdef,
|
is_async_stmt_or_funcdef,
|
||||||
is_atom_with_invisible_parens,
|
is_atom_with_invisible_parens,
|
||||||
@ -1628,6 +1629,11 @@ def maybe_make_parens_invisible_in_atom(
|
|||||||
or is_empty_tuple(node)
|
or is_empty_tuple(node)
|
||||||
or is_one_tuple(node)
|
or is_one_tuple(node)
|
||||||
or (is_tuple(node) and parent.type == syms.asexpr_test)
|
or (is_tuple(node) and parent.type == syms.asexpr_test)
|
||||||
|
or (
|
||||||
|
is_tuple(node)
|
||||||
|
and parent.type == syms.with_stmt
|
||||||
|
and has_sibling_with_type(node, token.COMMA)
|
||||||
|
)
|
||||||
or (is_yield(node) and parent.type != syms.expr_stmt)
|
or (is_yield(node) and parent.type != syms.expr_stmt)
|
||||||
or (
|
or (
|
||||||
# This condition tries to prevent removing non-optional brackets
|
# This condition tries to prevent removing non-optional brackets
|
||||||
|
@ -1058,3 +1058,21 @@ def furthest_ancestor_with_last_leaf(leaf: Leaf) -> LN:
|
|||||||
while node.parent and node.parent.children and node is node.parent.children[-1]:
|
while node.parent and node.parent.children and node is node.parent.children[-1]:
|
||||||
node = node.parent
|
node = node.parent
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
def has_sibling_with_type(node: LN, type: int) -> bool:
|
||||||
|
# Check previous siblings
|
||||||
|
sibling = node.prev_sibling
|
||||||
|
while sibling is not None:
|
||||||
|
if sibling.type == type:
|
||||||
|
return True
|
||||||
|
sibling = sibling.prev_sibling
|
||||||
|
|
||||||
|
# Check next siblings
|
||||||
|
sibling = node.next_sibling
|
||||||
|
while sibling is not None:
|
||||||
|
if sibling.type == type:
|
||||||
|
return True
|
||||||
|
sibling = sibling.next_sibling
|
||||||
|
|
||||||
|
return False
|
||||||
|
@ -89,6 +89,26 @@ async def func():
|
|||||||
with (x, y) as z:
|
with (x, y) as z:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# don't remove the brackets here, it changes the meaning of the code.
|
||||||
|
# even though the code will always trigger a runtime error
|
||||||
|
with (name_5, name_4), name_5:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_tuple_as_contextmanager():
|
||||||
|
from contextlib import nullcontext
|
||||||
|
|
||||||
|
try:
|
||||||
|
with (nullcontext(),nullcontext()),nullcontext():
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# test passed
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# this should be a type error
|
||||||
|
assert False
|
||||||
|
|
||||||
# output
|
# output
|
||||||
|
|
||||||
|
|
||||||
@ -182,3 +202,23 @@ async def func():
|
|||||||
# don't remove the brackets here, it changes the meaning of the code.
|
# don't remove the brackets here, it changes the meaning of the code.
|
||||||
with (x, y) as z:
|
with (x, y) as z:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# don't remove the brackets here, it changes the meaning of the code.
|
||||||
|
# even though the code will always trigger a runtime error
|
||||||
|
with (name_5, name_4), name_5:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_tuple_as_contextmanager():
|
||||||
|
from contextlib import nullcontext
|
||||||
|
|
||||||
|
try:
|
||||||
|
with (nullcontext(), nullcontext()), nullcontext():
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# test passed
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# this should be a type error
|
||||||
|
assert False
|
||||||
|
Loading…
Reference in New Issue
Block a user