summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdemeyer <jdemeyer@cage.ugent.be>2018-04-13 12:22:46 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2018-04-13 12:22:46 (GMT)
commit23ab5ee667a9b29014f6f7f01797c611f63ff743 (patch)
tree9e55defd8958fab8dad3a865d70447eca9633fc5
parentffa2c3e2c40acae07aca5b77f2c0e8c14a00438d (diff)
downloadcpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.zip
cpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.tar.gz
cpython-23ab5ee667a9b29014f6f7f01797c611f63ff743.tar.bz2
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.
-rw-r--r--Lib/contextlib.py11
-rw-r--r--Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst2
2 files changed, 5 insertions, 8 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 1ff8cdf..1a58b50 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -4,6 +4,7 @@ import sys
import _collections_abc
from collections import deque
from functools import wraps
+from types import MethodType
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
"AbstractContextManager", "AbstractAsyncContextManager",
@@ -373,9 +374,7 @@ class _BaseExitStack:
@staticmethod
def _create_exit_wrapper(cm, cm_exit):
- def _exit_wrapper(exc_type, exc, tb):
- return cm_exit(cm, exc_type, exc, tb)
- return _exit_wrapper
+ return MethodType(cm_exit, cm)
@staticmethod
def _create_cb_wrapper(callback, *args, **kwds):
@@ -443,7 +442,6 @@ class _BaseExitStack:
def _push_cm_exit(self, cm, cm_exit):
"""Helper to correctly register callbacks to __exit__ methods."""
_exit_wrapper = self._create_exit_wrapper(cm, cm_exit)
- _exit_wrapper.__self__ = cm
self._push_exit_callback(_exit_wrapper, True)
def _push_exit_callback(self, callback, is_sync=True):
@@ -535,9 +533,7 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
@staticmethod
def _create_async_exit_wrapper(cm, cm_exit):
- async def _exit_wrapper(exc_type, exc, tb):
- return await cm_exit(cm, exc_type, exc, tb)
- return _exit_wrapper
+ return MethodType(cm_exit, cm)
@staticmethod
def _create_async_cb_wrapper(callback, *args, **kwds):
@@ -596,7 +592,6 @@ class AsyncExitStack(_BaseExitStack, AbstractAsyncContextManager):
"""Helper to correctly register coroutine function to __aexit__
method."""
_exit_wrapper = self._create_async_exit_wrapper(cm, cm_exit)
- _exit_wrapper.__self__ = cm
self._push_exit_callback(_exit_wrapper, False)
async def __aenter__(self):
diff --git a/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst b/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst
new file mode 100644
index 0000000..523ceb9
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-04-13-08-12-50.bpo-33265.KPQRk0.rst
@@ -0,0 +1,2 @@
+``contextlib.ExitStack`` and ``contextlib.AsyncExitStack`` now use a method
+instead of a wrapper function for exit callbacks.