Skip to content

Commit 23ab5ee

Browse files
jdemeyerncoghlan
authored andcommitted
bpo-33265: use an actual method instead of a method-like function in ExitStack (GH-6456)
`MethodType` has the exact semantics that `ExitStack` needs, so we can avoid creating a Python level closure.
1 parent ffa2c3e commit 23ab5ee

File tree

2 files changed

+5
-8
lines changed

2 files changed

+5
-8
lines changed

Lib/contextlib.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import _collections_abc
55
from collections import deque
66
from functools import wraps
7+
from types import MethodType
78

89
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
910
"AbstractContextManager", "AbstractAsyncContextManager",
@@ -373,9 +374,7 @@ class _BaseExitStack:
373374

374375
@staticmethod
375376
def _create_exit_wrapper(cm, cm_exit):
376-
def _exit_wrapper(exc_type, exc, tb):
377-
return cm_exit(cm, exc_type, exc, tb)
378-
return _exit_wrapper
377+
return MethodType(cm_exit, cm)
379378

380379
@staticmethod
381380
def _create_cb_wrapper(callback, *args, **kwds):
@@ -443,7 +442,6 @@ def callback(self, callback, *args, **kwds):
443442
def _push_cm_exit(self, cm, cm_exit):
444443
"""Helper to correctly register callbacks to __exit__ methods."""
445444
_exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
446-
_exit_wrapper.__self__ = cm
447445
self._push_exit_callback(_exit_wrapper, True)
448446

449447
def _push_exit_callback(self, callback, is_sync=True):
@@ -535,9 +533,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
535533

536534
@staticmethod
537535
def _create_async_exit_wrapper(cm, cm_exit):
538-
async def _exit_wrapper(exc_type, exc, tb):
539-
return await cm_exit(cm, exc_type, exc, tb)
540-
return _exit_wrapper
536+
return MethodType(cm_exit, cm)
541537

542538
@staticmethod
543539
def _create_async_cb_wrapper(callback, *args, **kwds):
@@ -596,7 +592,6 @@ def _push_async_cm_exit(self, cm, cm_exit):
596592
"""Helper to correctly register coroutine function to __aexit__
597593
method."""
598594
_exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
599-
_exit_wrapper.__self__ = cm
600595
self._push_exit_callback(_exit_wrapper, False)
601596

602597
async def __aenter__(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
``contextlib.ExitStack`` and ``contextlib.AsyncExitStack`` now use a method
2+
instead of a wrapper function for exit callbacks.

0 commit comments

Comments
 (0)