Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion mypyc/irbuild/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,13 @@ def transform_with(
if not is_async and mgr_v.type == lock_rprimitive:
transform_with_lock(builder, mgr_v, target, body, line)
return
is_native = isinstance(mgr_v.type, RInstance)
# The methods may be inherited from a non-native class, and then they can't be
# called natively.
is_native = (
isinstance(mgr_v.type, RInstance)
and mgr_v.type.class_ir.has_method(f"__{al}enter__")
and mgr_v.type.class_ir.has_method(f"__{al}exit__")
)
if is_native:
value = builder.add(MethodCall(mgr_v, f"__{al}enter__", args=[], line=line))
exit_ = None
Expand Down
46 changes: 46 additions & 0 deletions mypyc/test-data/run-misc.test
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,8 @@ def test_redefinition() -> None:
assert i == b"foo"

[case testWithNative]
from base import Base, EnterBase

class DummyContext:
def __init__(self):
self.c = 0
Expand All @@ -1162,6 +1164,50 @@ def test_dummy_context() -> None:
assert c.c == 1
assert c.c == 0

class InheritsEnter(EnterBase):
def __init__(self) -> None:
self.log: list[str] = []

def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None:
self.log.append("exit")

class InheritsExit(Base):
def __enter__(self) -> str:
return "enter"

class InheritsBoth(Base):
pass

def test_inherited_enter() -> None:
c = InheritsEnter()
with c as x:
assert x is c
c.log.append("body")
assert c.log == ["body", "exit"]

def test_inherited_exit() -> None:
with InheritsExit() as x:
assert x == "enter"
with InheritsExit():
# Base.__exit__ suppresses the exception
raise ValueError()

def test_inherited_both() -> None:
with InheritsBoth() as x:
assert x == "base"

[file base.py]
class EnterBase:
def __enter__(self) -> "EnterBase":
return self

class Base:
def __enter__(self) -> str:
return "base"

def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> bool:
return True

[case testWithNativeVarArgs]
class DummyContext:
def __init__(self):
Expand Down
Loading