https://github.com/python/cpython/commit/71080b8a0fe5da46fb97659060db76fd95a3fb61
commit: 71080b8a0fe5da46fb97659060db76fd95a3fb61
branch: main
author: Jelle Zijlstra <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2024-05-07T14:16:05Z
summary:

gh-118660: Add second type parameter to (Async)ContextManager (#118681)

Co-authored-by: Alex Waygood <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-05-06-18-13-02.gh-issue-118660.n01Vb7.rst
M Doc/library/typing.rst
M Lib/test/test_typing.py
M Lib/typing.py

diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 652a3f1f70519c..f53080e0610cb1 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -3819,10 +3819,15 @@ Aliases to other ABCs in :mod:`collections.abc`
 Aliases to :mod:`contextlib` ABCs
 """""""""""""""""""""""""""""""""
 
-.. class:: ContextManager(Generic[T_co])
+.. class:: ContextManager(Generic[T_co, ExitT_co])
 
    Deprecated alias to :class:`contextlib.AbstractContextManager`.
 
+   The first type parameter, ``T_co``, represents the type returned by
+   the :meth:`~object.__enter__` method. The optional second type parameter, 
``ExitT_co``,
+   which defaults to ``bool | None``, represents the type returned by the
+   :meth:`~object.__exit__` method.
+
    .. versionadded:: 3.5.4
 
    .. deprecated:: 3.9
@@ -3830,10 +3835,18 @@ Aliases to :mod:`contextlib` ABCs
       now supports subscripting (``[]``).
       See :pep:`585` and :ref:`types-genericalias`.
 
-.. class:: AsyncContextManager(Generic[T_co])
+   .. versionchanged:: 3.13
+      Added the optional second type parameter, ``ExitT_co``.
+
+.. class:: AsyncContextManager(Generic[T_co, AExitT_co])
 
    Deprecated alias to :class:`contextlib.AbstractAsyncContextManager`.
 
+   The first type parameter, ``T_co``, represents the type returned by
+   the :meth:`~object.__aenter__` method. The optional second type parameter, 
``AExitT_co``,
+   which defaults to ``bool | None``, represents the type returned by the
+   :meth:`~object.__aexit__` method.
+
    .. versionadded:: 3.6.2
 
    .. deprecated:: 3.9
@@ -3841,6 +3854,9 @@ Aliases to :mod:`contextlib` ABCs
       now supports subscripting (``[]``).
       See :pep:`585` and :ref:`types-genericalias`.
 
+   .. versionchanged:: 3.13
+      Added the optional second type parameter, ``AExitT_co``.
+
 Deprecation Timeline of Major Features
 ======================================
 
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 012613302d1b53..bd116bb1ab7213 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -7511,6 +7511,15 @@ def manager():
         self.assertIsInstance(cm, typing.ContextManager)
         self.assertNotIsInstance(42, typing.ContextManager)
 
+    def test_contextmanager_type_params(self):
+        cm1 = typing.ContextManager[int]
+        self.assertEqual(get_args(cm1), (int, bool | None))
+        cm2 = typing.ContextManager[int, None]
+        self.assertEqual(get_args(cm2), (int, types.NoneType))
+
+        type gen_cm[T1, T2] = typing.ContextManager[T1, T2]
+        self.assertEqual(get_args(gen_cm.__value__[int, None]), (int, 
types.NoneType))
+
     def test_async_contextmanager(self):
         class NotACM:
             pass
@@ -7522,11 +7531,17 @@ def manager():
 
         cm = manager()
         self.assertNotIsInstance(cm, typing.AsyncContextManager)
-        self.assertEqual(typing.AsyncContextManager[int].__args__, (int,))
+        self.assertEqual(typing.AsyncContextManager[int].__args__, (int, bool 
| None))
         with self.assertRaises(TypeError):
             isinstance(42, typing.AsyncContextManager[int])
         with self.assertRaises(TypeError):
-            typing.AsyncContextManager[int, str]
+            typing.AsyncContextManager[int, str, float]
+
+    def test_asynccontextmanager_type_params(self):
+        cm1 = typing.AsyncContextManager[int]
+        self.assertEqual(get_args(cm1), (int, bool | None))
+        cm2 = typing.AsyncContextManager[int, None]
+        self.assertEqual(get_args(cm2), (int, types.NoneType))
 
 
 class TypeTests(BaseTestCase):
@@ -9953,7 +9968,7 @@ def test_special_attrs(self):
             typing.ValuesView: 'ValuesView',
             # Subscribed ABC classes
             typing.AbstractSet[Any]: 'AbstractSet',
-            typing.AsyncContextManager[Any]: 'AsyncContextManager',
+            typing.AsyncContextManager[Any, Any]: 'AsyncContextManager',
             typing.AsyncGenerator[Any, Any]: 'AsyncGenerator',
             typing.AsyncIterable[Any]: 'AsyncIterable',
             typing.AsyncIterator[Any]: 'AsyncIterator',
@@ -9963,7 +9978,7 @@ def test_special_attrs(self):
             typing.ChainMap[Any, Any]: 'ChainMap',
             typing.Collection[Any]: 'Collection',
             typing.Container[Any]: 'Container',
-            typing.ContextManager[Any]: 'ContextManager',
+            typing.ContextManager[Any, Any]: 'ContextManager',
             typing.Coroutine[Any, Any, Any]: 'Coroutine',
             typing.Counter[Any]: 'Counter',
             typing.DefaultDict[Any, Any]: 'DefaultDict',
diff --git a/Lib/typing.py b/Lib/typing.py
index e48583673a7be2..8e61f50477bcc2 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -3783,7 +3783,7 @@ def __getattr__(attr):
         obj = _alias(getattr(re, attr), 1)
     elif attr in {"ContextManager", "AsyncContextManager"}:
         import contextlib
-        obj = _alias(getattr(contextlib, f"Abstract{attr}"), 1, name=attr)
+        obj = _alias(getattr(contextlib, f"Abstract{attr}"), 2, name=attr, 
defaults=(bool | None,))
     else:
         raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
     globals()[attr] = obj
diff --git 
a/Misc/NEWS.d/next/Library/2024-05-06-18-13-02.gh-issue-118660.n01Vb7.rst 
b/Misc/NEWS.d/next/Library/2024-05-06-18-13-02.gh-issue-118660.n01Vb7.rst
new file mode 100644
index 00000000000000..846a7acb6999b8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-06-18-13-02.gh-issue-118660.n01Vb7.rst
@@ -0,0 +1,4 @@
+Add an optional second type parameter to :class:`typing.ContextManager` and
+:class:`typing.AsyncContextManager`, representing the return types of
+:meth:`~object.__exit__` and :meth:`~object.__aexit__` respectively.
+This parameter defaults to ``bool | None``.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to