mirror of
https://github.com/pocketpy/pocketpy
synced 2026-02-04 06:30:17 +00:00
Problem: When an exception occurs in a WITH block, __exit__ was not called, preventing proper cleanup of context managers. Solution: 1. Wrap WITH block body in try-except structure 2. On normal exit: call __exit__(None, None, None) 3. On exception: call __exit__ with exception info before re-raising Changes: - compiler.c: Wrap WITH body in try-except, ensure __exit__ called in both paths - ceval.c: Update OP_WITH_EXIT to accept three arguments (exc_type, exc_val, exc_tb) - tests/520_context.py: Add test to verify __exit__ called on exceptions
56 lines
1.1 KiB
Python
56 lines
1.1 KiB
Python
path = []
|
|
|
|
class A:
|
|
def __init__(self, x):
|
|
self.x = x
|
|
self.path = []
|
|
|
|
def __enter__(self):
|
|
path.append('enter')
|
|
return self.x
|
|
|
|
def __exit__(self, *args):
|
|
path.append('exit')
|
|
|
|
|
|
with A(123):
|
|
assert path == ['enter']
|
|
assert path == ['enter', 'exit']
|
|
|
|
path.clear()
|
|
|
|
with A(123) as a:
|
|
assert path == ['enter']
|
|
assert a == 123
|
|
path.append('in')
|
|
assert path == ['enter', 'in', 'exit']
|
|
|
|
path.clear()
|
|
|
|
# Test that __exit__ is called even when an exception occurs
|
|
class B:
|
|
def __init__(self):
|
|
self.path = []
|
|
|
|
def __enter__(self):
|
|
path.append('enter')
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
path.append('exit')
|
|
if exc_type is not None:
|
|
path.append('exception')
|
|
return False # propagate exception
|
|
|
|
try:
|
|
with B():
|
|
path.append('before_raise')
|
|
raise ValueError('test')
|
|
path.append('after_raise') # should not be reached
|
|
except ValueError:
|
|
pass
|
|
|
|
assert path == ['enter', 'before_raise', 'exit', 'exception'], f"Expected ['enter', 'before_raise', 'exit', 'exception'], got {path}"
|
|
|
|
|