Commit 23ab5ee6 authored by jdemeyer's avatar jdemeyer Committed by Nick Coghlan

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.
parent ffa2c3e2
...@@ -4,6 +4,7 @@ import sys ...@@ -4,6 +4,7 @@ import sys
import _collections_abc import _collections_abc
from collections import deque from collections import deque
from functools import wraps from functools import wraps
from types import MethodType
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext", __all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
"AbstractContextManager", "AbstractAsyncContextManager", "AbstractContextManager", "AbstractAsyncContextManager",
...@@ -373,9 +374,7 @@ class _BaseExitStack: ...@@ -373,9 +374,7 @@ class _BaseExitStack:
@staticmethod @staticmethod
def _create_exit_wrapper(cm, cm_exit): def _create_exit_wrapper(cm, cm_exit):
def _exit_wrapper(exc_type, exc, tb): return MethodType(cm_exit, cm)
return cm_exit(cm, exc_type, exc, tb)
return _exit_wrapper
@staticmethod @staticmethod
def _create_cb_wrapper(callback, *args, **kwds): def _create_cb_wrapper(callback, *args, **kwds):
...@@ -443,7 +442,6 @@ class _BaseExitStack: ...@@ -443,7 +442,6 @@ class _BaseExitStack:
def _push_cm_exit(self, cm, cm_exit): def _push_cm_exit(self, cm, cm_exit):
"""Helper to correctly register callbacks to __exit__ methods.""" """Helper to correctly register callbacks to __exit__ methods."""
_exit_wrapper = self._create_exit_wrapper(cm, cm_exit) _exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
_exit_wrapper.__self__ = cm
self._push_exit_callback(_exit_wrapper, True) self._push_exit_callback(_exit_wrapper, True)
def _push_exit_callback(self, callback, is_sync=True): def _push_exit_callback(self, callback, is_sync=True):
...@@ -535,9 +533,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager): ...@@ -535,9 +533,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
@staticmethod @staticmethod
def _create_async_exit_wrapper(cm, cm_exit): def _create_async_exit_wrapper(cm, cm_exit):
async def _exit_wrapper(exc_type, exc, tb): return MethodType(cm_exit, cm)
return await cm_exit(cm, exc_type, exc, tb)
return _exit_wrapper
@staticmethod @staticmethod
def _create_async_cb_wrapper(callback, *args, **kwds): def _create_async_cb_wrapper(callback, *args, **kwds):
...@@ -596,7 +592,6 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager): ...@@ -596,7 +592,6 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
"""Helper to correctly register coroutine function to __aexit__ """Helper to correctly register coroutine function to __aexit__
method.""" method."""
_exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit) _exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
_exit_wrapper.__self__ = cm
self._push_exit_callback(_exit_wrapper, False) self._push_exit_callback(_exit_wrapper, False)
async def __aenter__(self): async def __aenter__(self):
......
``contextlib.ExitStack`` and ``contextlib.AsyncExitStack`` now use a method
instead of a wrapper function for exit callbacks.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment