From c8b9183f20c5da4ded3e8f2ee9c79d4a33b94f57 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 10 May 2025 06:44:47 -0700 Subject: [PATCH 1/4] Become robust to things being removed from typing --- CHANGELOG.md | 2 + src/test_typing_extensions.py | 9 ++++ src/typing_extensions.py | 91 ++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ba8e152..cfb45718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Unreleased - Drop support for Python 3.8 (including PyPy-3.8). Patch by [Victorien Plot](https://github.com/Viicos). +- Do not attempt to re-export names that have been removed from `typing`, + anticipating the removal of `typing.no_type_check_decorator` in Python 3.15. New features: diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index dc882f9f..333b4867 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -6827,6 +6827,15 @@ def test_typing_extensions_defers_when_possible(self): getattr(typing_extensions, item), getattr(typing, item)) + def test_alias_names_still_exist(self): + for name in typing_extensions._typing_names: + # If this fails, change _typing_names to conditionally add the name + # depending on the Python version. + self.assertTrue( + hasattr(typing_extensions, name), + f"{name} no longer exists in typing", + ) + def test_typing_extensions_compiles_with_opt(self): file_path = typing_extensions.__file__ try: diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 269ca650..4ffc46aa 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -4223,46 +4223,51 @@ def evaluate_forward_ref( # Aliases for items that are in typing in all supported versions. -# 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 -# in a future version of Python -AbstractSet = typing.AbstractSet -Annotated = typing.Annotated -AnyStr = typing.AnyStr -BinaryIO = typing.BinaryIO -Callable = typing.Callable -Collection = typing.Collection -Container = typing.Container -Dict = typing.Dict -ForwardRef = typing.ForwardRef -FrozenSet = typing.FrozenSet -Generic = typing.Generic -Hashable = typing.Hashable -IO = typing.IO -ItemsView = typing.ItemsView -Iterable = typing.Iterable -Iterator = typing.Iterator -KeysView = typing.KeysView -List = typing.List -Mapping = typing.Mapping -MappingView = typing.MappingView -Match = typing.Match -MutableMapping = typing.MutableMapping -MutableSequence = typing.MutableSequence -MutableSet = typing.MutableSet -Optional = typing.Optional -Pattern = typing.Pattern -Reversible = typing.Reversible -Sequence = typing.Sequence -Set = typing.Set -Sized = typing.Sized -TextIO = typing.TextIO -Tuple = typing.Tuple -Union = typing.Union -ValuesView = typing.ValuesView -cast = typing.cast -no_type_check = typing.no_type_check -no_type_check_decorator = typing.no_type_check_decorator -# This is private, but it was defined by typing_extensions for a long time -# and some users rely on it. -_AnnotatedAlias = typing._AnnotatedAlias +# We use hasattr() checks so this library will continue to import on +# future versions of Python that may remove these names. +_typing_names = [ + "AbstractSet", + "Annotated", + "AnyStr", + "BinaryIO", + "Callable", + "Collection", + "Container", + "Dict", + "ForwardRef", + "FrozenSet", + "Generic", + "Hashable", + "IO", + "ItemsView", + "Iterable", + "Iterator", + "KeysView", + "List", + "Mapping", + "MappingView", + "Match", + "MutableMapping", + "MutableSequence", + "MutableSet", + "Optional", + "Pattern", + "Reversible", + "Sequence", + "Set", + "Sized", + "TextIO", + "Tuple", + "Union", + "ValuesView", + "cast", + "no_type_check", + "no_type_check_decorator", + # This is private, but it was defined by typing_extensions for a long time + # and some users rely on it. + "_AnnotatedAlias", +] +for _name in _typing_names: + if hasattr(typing, _name): + globals()[_name] = getattr(typing, _name) +del _typing_names From d5f23fe0699304c2c3ca85e53af468cd2eab51a4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 10 May 2025 06:47:59 -0700 Subject: [PATCH 2/4] oops --- src/typing_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 4ffc46aa..17fbfa5c 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -4270,4 +4270,4 @@ def evaluate_forward_ref( for _name in _typing_names: if hasattr(typing, _name): globals()[_name] = getattr(typing, _name) -del _typing_names +del _name From d6694e32b4742f989bc1a628ba0e813571e19a50 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 10 May 2025 06:51:18 -0700 Subject: [PATCH 3/4] fix ruff --- pyproject.toml | 3 +++ src/typing_extensions.py | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 48e2f914..1140ef78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,9 @@ ignore = [ "RUF012", "RUF022", "RUF023", + # Ruff doesn't understand the globals() assignment; we test __all__ + # directly in test_all_names_in___all__. + "F822", ] [tool.ruff.lint.per-file-ignores] diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 17fbfa5c..d607c4cf 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -4227,16 +4227,13 @@ def evaluate_forward_ref( # future versions of Python that may remove these names. _typing_names = [ "AbstractSet", - "Annotated", "AnyStr", "BinaryIO", "Callable", "Collection", "Container", "Dict", - "ForwardRef", "FrozenSet", - "Generic", "Hashable", "IO", "ItemsView", @@ -4271,3 +4268,8 @@ def evaluate_forward_ref( if hasattr(typing, _name): globals()[_name] = getattr(typing, _name) del _name +# These are defined unconditionally because they are used in +# typing-extensions itself. +Generic = typing.Generic +ForwardRef = typing.ForwardRef +Annotated = typing.Annotated From 6671a372e69ee97f3c8bd3f7558c9eada6ddbec8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 10 May 2025 07:30:42 -0700 Subject: [PATCH 4/4] Update src/typing_extensions.py Co-authored-by: Alex Waygood --- src/typing_extensions.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/typing_extensions.py b/src/typing_extensions.py index d607c4cf..cf0427f3 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -4264,10 +4264,9 @@ def evaluate_forward_ref( # and some users rely on it. "_AnnotatedAlias", ] -for _name in _typing_names: - if hasattr(typing, _name): - globals()[_name] = getattr(typing, _name) -del _name +globals().update( + {name: getattr(typing, name) for name in _typing_names if hasattr(typing, name)} +) # These are defined unconditionally because they are used in # typing-extensions itself. Generic = typing.Generic