diff --git a/CHANGELOG.md b/CHANGELOG.md index e0a633bd..783821fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ signifies the return type of the `__(a)exit__` method, matching `typing.ContextManager` and `typing.AsyncContextManager` on Python 3.13+. +- Backport `types.CapsuleType` from Python 3.13. # Release 4.11.0 (April 5, 2024) diff --git a/doc/index.rst b/doc/index.rst index 5863fe4c..be4b4ae3 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -882,6 +882,20 @@ Annotation metadata The documentation string passed to :class:`Doc`. +Capsule objects +~~~~~~~~~~~~~~~ + +.. class:: CapsuleType + + The type of :py:ref:`capsule objects `. + See :py:class:`types.CapsuleType`, where it has existed since Python 3.13. + + Note that this may not exist on all implementations of Python; it is only + guaranteed to exist on CPython. + + .. versionadded:: 4.12.0 + + Pure aliases ~~~~~~~~~~~~ diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index f3bfae1c..c031cf32 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -6765,5 +6765,15 @@ def test_pickle(self): self.assertEqual(doc_info, pickle.loads(pickled)) +@skipUnless( + hasattr(typing_extensions, "CapsuleType"), + "CapsuleType is not available on all Python implementations" +) +class CapsuleTypeTests(BaseTestCase): + def test_capsule_type(self): + import _datetime + self.assertIsInstance(_datetime.datetime_CAPI, typing_extensions.CapsuleType) + + if __name__ == '__main__': main() diff --git a/src/typing_extensions.py b/src/typing_extensions.py index b4ca1bc2..c1c3c63a 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -3411,6 +3411,23 @@ def __eq__(self, other: object) -> bool: return self.documentation == other.documentation +_CapsuleType = getattr(_types, "CapsuleType", None) + +if _CapsuleType is None: + try: + import _socket + except ImportError: + pass + else: + _CAPI = getattr(_socket, "CAPI", None) + if _CAPI is not None: + _CapsuleType = type(_CAPI) + +if _CapsuleType is not None: + CapsuleType = _CapsuleType + __all__.append("CapsuleType") + + # Aliases for items that have always been in typing. # Explicitly assign these (rather than using `from typing import *` at the top), # so that we get a CI error if one of these is deleted from typing.py