]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-118660: Add second type parameter to (Async)ContextManager (#118681)
authorJelle Zijlstra <jelle.zijlstra@gmail.com>
Tue, 7 May 2024 14:16:05 +0000 (07:16 -0700)
committerGitHub <noreply@github.com>
Tue, 7 May 2024 14:16:05 +0000 (14:16 +0000)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Doc/library/typing.rst
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2024-05-06-18-13-02.gh-issue-118660.n01Vb7.rst [new file with mode: 0644]

index 652a3f1f70519c42f3815d61ea1a44aa15642c1b..f53080e0610cb1f0edc3ba0072a959cd9220a61a 100644 (file)
@@ -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
 ======================================
 
index 012613302d1b532618168d77d093202e0edd4860..bd116bb1ab721340c44f542299d3f3770e66d321 100644 (file)
@@ -7511,6 +7511,15 @@ class OtherABCTests(BaseTestCase):
         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 @@ class OtherABCTests(BaseTestCase):
 
         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 @@ class SpecialAttrsTests(BaseTestCase):
             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 @@ class SpecialAttrsTests(BaseTestCase):
             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',
index e48583673a7be226a5f5ced552f1baa7d3458a27..8e61f50477bcc21945ad086daf36ff7498e5b718 100644 (file)
@@ -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 (file)
index 0000000..846a7ac
--- /dev/null
@@ -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``.