bpo-30241: implement contextlib.AbstractAsyncContextManager (#1412)

diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index c1f8a84..96c8c22 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -6,7 +6,8 @@
 from functools import wraps
 
 __all__ = ["asynccontextmanager", "contextmanager", "closing", "nullcontext",
-           "AbstractContextManager", "ContextDecorator", "ExitStack",
+           "AbstractContextManager", "AbstractAsyncContextManager",
+           "ContextDecorator", "ExitStack",
            "redirect_stdout", "redirect_stderr", "suppress"]
 
 
@@ -30,6 +31,27 @@
         return NotImplemented
 
 
+class AbstractAsyncContextManager(abc.ABC):
+
+    """An abstract base class for asynchronous context managers."""
+
+    async def __aenter__(self):
+        """Return `self` upon entering the runtime context."""
+        return self
+
+    @abc.abstractmethod
+    async def __aexit__(self, exc_type, exc_value, traceback):
+        """Raise any exception triggered within the runtime context."""
+        return None
+
+    @classmethod
+    def __subclasshook__(cls, C):
+        if cls is AbstractAsyncContextManager:
+            return _collections_abc._check_methods(C, "__aenter__",
+                                                   "__aexit__")
+        return NotImplemented
+
+
 class ContextDecorator(object):
     "A base class or mixin that enables context managers to work as decorators."
 
@@ -136,7 +158,8 @@
             raise RuntimeError("generator didn't stop after throw()")
 
 
-class _AsyncGeneratorContextManager(_GeneratorContextManagerBase):
+class _AsyncGeneratorContextManager(_GeneratorContextManagerBase,
+                                    AbstractAsyncContextManager):
     """Helper for @asynccontextmanager."""
 
     async def __aenter__(self):