diff --git a/CHANGELOG.md b/CHANGELOG.md index f35c4827..ee8d10dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Fix setting of `__required_keys__` and `__optional_keys__` when inheriting keys with the same name. +- Add support for `AsyncIterator`, `io.Reader`, `io.Writer` and `os.PathLike` protocols + as bases for other protocls. - 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 c7025321..94082c2d 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 @@ -3870,9 +3871,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 @@ -7110,13 +7117,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 05d4522c..bc8299d3 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -677,10 +677,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'], } @@ -704,8 +707,10 @@ def _get_protocol_attrs(cls): # `__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):