|
10 | 10 | import collections.abc as collections_abc |
11 | 11 | except ImportError: |
12 | 12 | import collections as collections_abc # Fallback for PY3.2. |
| 13 | +if sys.version_info[:2] >= (3, 6): |
| 14 | + import _collections_abc # Needed for private function _check_methods # noqa |
13 | 15 | try: |
14 | 16 | from types import WrapperDescriptorType, MethodWrapperType, MethodDescriptorType |
15 | 17 | except ImportError: |
|
37 | 39 | # for 'Generic' and ABCs below. |
38 | 40 | 'ByteString', |
39 | 41 | 'Container', |
| 42 | + 'ContextManager', |
40 | 43 | 'Hashable', |
41 | 44 | 'ItemsView', |
42 | 45 | 'Iterable', |
|
57 | 60 | # AsyncIterable, |
58 | 61 | # Coroutine, |
59 | 62 | # Collection, |
60 | | - # ContextManager, |
61 | 63 | # AsyncGenerator, |
| 64 | + # AsyncContextManager |
62 | 65 |
|
63 | 66 | # Structural checks, a.k.a. protocols. |
64 | 67 | 'Reversible', |
@@ -1949,7 +1952,61 @@ class ValuesView(MappingView[VT_co], extra=collections_abc.ValuesView): |
1949 | 1952 | if hasattr(contextlib, 'AbstractContextManager'): |
1950 | 1953 | class ContextManager(Generic[T_co], extra=contextlib.AbstractContextManager): |
1951 | 1954 | __slots__ = () |
1952 | | - __all__.append('ContextManager') |
| 1955 | +else: |
| 1956 | + class ContextManager(Generic[T_co]): |
| 1957 | + __slots__ = () |
| 1958 | + |
| 1959 | + def __enter__(self): |
| 1960 | + return self |
| 1961 | + |
| 1962 | + @abc.abstractmethod |
| 1963 | + def __exit__(self, exc_type, exc_value, traceback): |
| 1964 | + return None |
| 1965 | + |
| 1966 | + @classmethod |
| 1967 | + def __subclasshook__(cls, C): |
| 1968 | + if cls is ContextManager: |
| 1969 | + # In Python 3.6+, it is possible to set a method to None to |
| 1970 | + # explicitly indicate that the class does not implement an ABC |
| 1971 | + # (https://bugs.python.org/issue25958), but we do not support |
| 1972 | + # that pattern here because this fallback class is only used |
| 1973 | + # in Python 3.5 and earlier. |
| 1974 | + if (any("__enter__" in B.__dict__ for B in C.__mro__) and |
| 1975 | + any("__exit__" in B.__dict__ for B in C.__mro__)): |
| 1976 | + return True |
| 1977 | + return NotImplemented |
| 1978 | + |
| 1979 | + |
| 1980 | +if hasattr(contextlib, 'AbstractAsyncContextManager'): |
| 1981 | + class AsyncContextManager(Generic[T_co], |
| 1982 | + extra=contextlib.AbstractAsyncContextManager): |
| 1983 | + __slots__ = () |
| 1984 | + |
| 1985 | + __all__.append('AsyncContextManager') |
| 1986 | +elif sys.version_info[:2] >= (3, 5): |
| 1987 | + exec(""" |
| 1988 | +class AsyncContextManager(Generic[T_co]): |
| 1989 | + __slots__ = () |
| 1990 | +
|
| 1991 | + async def __aenter__(self): |
| 1992 | + return self |
| 1993 | +
|
| 1994 | + @abc.abstractmethod |
| 1995 | + async def __aexit__(self, exc_type, exc_value, traceback): |
| 1996 | + return None |
| 1997 | +
|
| 1998 | + @classmethod |
| 1999 | + def __subclasshook__(cls, C): |
| 2000 | + if cls is AsyncContextManager: |
| 2001 | + if sys.version_info[:2] >= (3, 6): |
| 2002 | + return _collections_abc._check_methods(C, "__aenter__", "__aexit__") |
| 2003 | + if (any("__aenter__" in B.__dict__ for B in C.__mro__) and |
| 2004 | + any("__aexit__" in B.__dict__ for B in C.__mro__)): |
| 2005 | + return True |
| 2006 | + return NotImplemented |
| 2007 | +
|
| 2008 | +__all__.append('AsyncContextManager') |
| 2009 | +""") |
1953 | 2010 |
|
1954 | 2011 |
|
1955 | 2012 | class Dict(dict, MutableMapping[KT, VT], extra=dict): |
|
0 commit comments