contextlib2/dev/py3_10_contextlib_to_contextlib2.patch

148 lines
5.2 KiB
Diff
Raw Normal View History

--- ../cpython/Lib/contextlib.py 2021-06-26 16:28:03.835372955 +1000
+++ contextlib2.py 2021-06-26 17:40:30.047079570 +1000
@@ -1,19 +1,32 @@
-"""Utilities for with-statement contexts. See PEP 343."""
+"""contextlib2 - backports and enhancements to the contextlib module"""
+
import abc
import sys
+import warnings
import _collections_abc
from collections import deque
from functools import wraps
-from types import MethodType, GenericAlias
+from types import MethodType
+
+# Python 3.6/3.7/3.8 compatibility: GenericAlias may not be defined
+try:
+ from types import GenericAlias
+except ImportError:
+ # If the real GenericAlias type doesn't exist, __class_getitem__ won't be used,
+ # so the fallback placeholder doesn't need to provide any meaningful behaviour
+ class GenericAlias:
+ pass
+
__all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
"AbstractContextManager", "AbstractAsyncContextManager",
"AsyncExitStack", "ContextDecorator", "ExitStack",
"redirect_stdout", "redirect_stderr", "suppress", "aclosing"]
+# Backwards compatibility
+__all__ += ["ContextStack"]
class AbstractContextManager(abc.ABC):
-
"""An abstract base class for context managers."""
__class_getitem__ = classmethod(GenericAlias)
@@ -60,6 +73,23 @@
class ContextDecorator(object):
"A base class or mixin that enables context managers to work as decorators."
+ def refresh_cm(self):
+ """Returns the context manager used to actually wrap the call to the
+ decorated function.
+
+ The default implementation just returns *self*.
+
+ Overriding this method allows otherwise one-shot context managers
+ like _GeneratorContextManager to support use as decorators via
+ implicit recreation.
+
+ DEPRECATED: refresh_cm was never added to the standard library's
+ ContextDecorator API
+ """
+ warnings.warn("refresh_cm was never added to the standard library",
+ DeprecationWarning)
+ return self._recreate_cm()
+
def _recreate_cm(self):
"""Return a recreated instance of self.
@@ -430,7 +460,9 @@
return MethodType(cm_exit, cm)
@staticmethod
- def _create_cb_wrapper(callback, /, *args, **kwds):
+ def _create_cb_wrapper(*args, **kwds):
+ # Python 3.6/3.7 compatibility: no native positional-only args syntax
+ callback, *args = args
def _exit_wrapper(exc_type, exc, tb):
callback(*args, **kwds)
return _exit_wrapper
@@ -479,11 +511,18 @@
self._push_cm_exit(cm, _exit)
return result
- def callback(self, callback, /, *args, **kwds):
+ def callback(*args, **kwds):
"""Registers an arbitrary callback and arguments.
Cannot suppress exceptions.
"""
+ # Python 3.6/3.7 compatibility: no native positional-only args syntax
+ try:
+ self, callback, *args = args
+ except ValueError as exc:
+ exc_details = str(exc).partition("(")[2]
+ msg = "Not enough positional arguments {}".format(exc_details)
+ raise TypeError(msg) from None
_exit_wrapper = self._create_cb_wrapper(callback, *args, **kwds)
# We changed the signature, so using @wraps is not appropriate, but
@@ -589,7 +628,9 @@
return MethodType(cm_exit, cm)
@staticmethod
- def _create_async_cb_wrapper(callback, /, *args, **kwds):
+ def _create_async_cb_wrapper(*args, **kwds):
+ # Python 3.6/3.7 compatibility: no native positional-only args syntax
+ callback, *args = args
async def _exit_wrapper(exc_type, exc, tb):
await callback(*args, **kwds)
return _exit_wrapper
@@ -624,11 +665,18 @@
self._push_async_cm_exit(exit, exit_method)
return exit # Allow use as a decorator
- def push_async_callback(self, callback, /, *args, **kwds):
+ def push_async_callback(*args, **kwds):
"""Registers an arbitrary coroutine function and arguments.
Cannot suppress exceptions.
"""
+ # Python 3.6/3.7 compatibility: no native positional-only args syntax
+ try:
+ self, callback, *args = args
+ except ValueError as exc:
+ exc_details = str(exc).partition("(")[2]
+ msg = "Not enough positional arguments {}".format(exc_details)
+ raise TypeError(msg) from None
_exit_wrapper = self._create_async_cb_wrapper(callback, *args, **kwds)
# We changed the signature, so using @wraps is not appropriate, but
@@ -729,3 +777,22 @@
async def __aexit__(self, *excinfo):
pass
+
+
+# Preserve backwards compatibility
+class ContextStack(ExitStack):
+ """Backwards compatibility alias for ExitStack"""
+
+ def __init__(self):
+ warnings.warn("ContextStack has been renamed to ExitStack",
+ DeprecationWarning)
+ super(ContextStack, self).__init__()
+
+ def register_exit(self, callback):
+ return self.push(callback)
+
+ def register(self, callback, *args, **kwds):
+ return self.callback(callback, *args, **kwds)
+
+ def preserve(self):
+ return self.pop_all()