diff --git a/CHANGELOG.md b/CHANGELOG.md index 733505a5..c6a4d5ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Add support for `AsyncIterator`, `io.Reader`, `io.Writer` and `os.PathLike` protocols. - Fix incorrect behaviour on Python 3.9 and Python 3.10 that meant that calling `isinstance` with `typing_extensions.Concatenate[...]` or `typing_extensions.Unpack[...]` as the first argument could have a different diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 88fa699e..47985e52 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -10,6 +10,7 @@ import inspect import io import itertools +import os import pickle import re import subprocess @@ -3869,9 +3870,15 @@ def test_builtin_protocol_allowlist(self): class CustomProtocol(TestCase, Protocol): pass + class CustomPathLikeProtocol(os.PathLike, Protocol): + pass + class CustomContextManager(typing.ContextManager, Protocol): pass + class CustomAsyncIterator(typing.AsyncIterator, Protocol): + pass + @skip_if_py312b1 def test_typing_extensions_protocol_allowlist(self): @runtime_checkable @@ -7064,13 +7071,13 @@ def test_typing_extensions_defers_when_possible(self): } if sys.version_info < (3, 13): exclude |= { - 'NamedTuple', 'Protocol', 'runtime_checkable', 'Generator', + 'NamedTuple', 'runtime_checkable', 'Generator', 'AsyncGenerator', 'ContextManager', 'AsyncContextManager', 'ParamSpec', 'TypeVar', 'TypeVarTuple', 'get_type_hints', } if sys.version_info < (3, 14): exclude |= { - 'TypeAliasType' + 'TypeAliasType', 'Protocol' } if not typing_extensions._PEP_728_IMPLEMENTED: exclude |= {'TypedDict', 'is_typeddict'} diff --git a/src/typing_extensions.py b/src/typing_extensions.py index bd67a80a..885fd7ce 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -614,10 +614,13 @@ def __getitem__(self, params): _PROTO_ALLOWLIST = { 'collections.abc': [ 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', - 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', + 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', + 'Reversible', 'Buffer', ], 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'io': ['Reader', 'Writer'], 'typing_extensions': ['Buffer'], + 'os': ['PathLike'], } @@ -653,8 +656,10 @@ def _caller(depth=1, default='__main__'): # `__match_args__` attribute was removed from protocol members in 3.13, # we want to backport this change to older Python versions. -# Breakpoint: https://github.com/python/cpython/pull/110683 -if sys.version_info >= (3, 13): +# 3.14 additionally added `io.Reader`, `io.Writer` and `os.PathLike` to +# the list of allowed protocol allowlist. +# https://github.com/python/cpython/issues/127647 +if sys.version_info >= (3, 14): Protocol = typing.Protocol else: def _allow_reckless_class_checks(depth=2):