8000 Drop support for Python 3.8 (#585) · python/typing_extensions@7cfb2c0 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7cfb2c0

Browse files
authored
Drop support for Python 3.8 (#585)
1 parent 4525e9d commit 7cfb2c0

File tree

6 files changed

+86
-573
lines changed

6 files changed

+86
-573
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ jobs:
3838
# For available versions, see:
3939
# https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
4040
python-version:
41-
- "3.8"
4241
- "3.9"
4342
- "3.9.12"
4443
- "3.10"
@@ -49,7 +48,6 @@ jobs:
4948
- "3.12.0"
5049
- "3.13"
5150
- "3.13.0"
52-
- "pypy3.8"
5351
- "pypy3.9"
5452
- "pypy3.10"
5553

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Unreleased
2+
3+
- Drop support for Python 3.8 (including PyPy-3.8). Patch by [Victorien Plot](https://github.com/Viicos).
4+
15
# Release 4.13.2 (April 10, 2025)
26

37
- Fix `TypeError` when taking the union of `typing_extensions.TypeAliasType` and a

doc/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Example usage::
139139
Python version support
140140
----------------------
141141

142-
``typing_extensions`` currently supports Python versions 3.8 and higher. In the future,
142+
``typing_extensions`` currently supports Python versions 3.9 and higher. In the future,
143143
support for older Python versions will be dropped some time after that version
144144
reaches end of life.
145145

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ build-backend = "flit_core.buildapi"
77
[project]
88
name = "typing_extensions"
99
version = "4.13.2"
10-
description = "Backported and Experimental Type Hints for Python 3.8+"
10+
description = "Backported and Experimental Type Hints for Python 3.9+"
1111
readme = "README.md"
12-
requires-python = ">=3.8"
12+
requires-python = ">=3.9"
1313
license = "PSF-2.0"
1414
license-files = ["LICENSE"]
1515
keywords = [
@@ -34,7 +34,6 @@ classifiers = [
3434
"Operating System :: OS Independent",
3535
"Programming Language :: Python :: 3",
3636
"Programming Language :: Python :: 3 :: Only",
37-
"Programming Language :: Python :: 3.8",
3837
"Programming Language :: Python :: 3.9",
3938
"Programming Language :: Python :: 3.10",
4039
"Programming Language :: Python :: 3.11",
@@ -63,7 +62,7 @@ exclude = []
6362

6463
[tool.ruff]
6564
line-length = 90
66-
target-version = "py38"
65+
target-version = "py39"
6766

6867
[tool.ruff.lint]
6968
select = [

src/test_typing_extensions.py

Lines changed: 29 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@
110110

111111
# Flags used to mark tests that only apply after a specific
112112
# version of the typing module.
113-
TYPING_3_9_0 = sys.version_info[:3] >= (3, 9, 0)
114113
TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0)
115114

116115
# 3.11 makes runtime type checks (_type_check) more lenient.
@@ -1779,8 +1778,7 @@ class C(Generic[T]): pass
17791778
self.assertIs(get_origin(List), list)
17801779
self.assertIs(get_origin(Tuple), tuple)
17811780
self.assertIs(get_origin(Callable), collections.abc.Callable)
1782-
if sys.version_info >= (3, 9):
1783-
self.assertIs(get_origin(list[int]), list)
1781+
self.assertIs(get_origin(list[int]), list)
17841782
self.assertIs(get_origin(list), None)
17851783
self.assertIs(get_origin(P.args), P)
17861784
self.assertIs(get_origin(P.kwargs), P)
@@ -1817,20 +1815,18 @@ class C(Generic[T]): pass
18171815
self.assertEqual(get_args(List), ())
18181816
self.assertEqual(get_args(Tuple), ())
18191817
self.assertEqual(get_args(Callable), ())
1820-
if sys.version_info >= (3, 9):
1821-
self.assertEqual(get_args(list[int]), (int,))
1818+
self.assertEqual(get_args(list[int]), (int,))
18221819
self.assertEqual(get_args(list), ())
1823-
if sys.version_info >= (3, 9):
1824-
# Support Python versions with and without the fix for
1825-
# https://bugs.python.org/issue42195
1826-
# The first variant is for 3.9.2+, the second for 3.9.0 and 1
1827-
self.assertIn(get_args(collections.abc.Callable[[int], str]),
1828-
(([int], str), ([[int]], str)))
1829-
self.assertIn(get_args(collections.abc.Callable[[], str]),
1830-
(([], str), ([[]], str)))
1831-
self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str))
1820+
# Support Python versions with and without the fix for
1821+
# https://bugs.python.org/issue42195
1822+
# The first variant is for 3.9.2+, the second for 3.9.0 and 1
1823+
self.assertIn(get_args(collections.abc.Callable[[int], str]),
1824+
(([int], str), ([[int]], str)))
1825+
self.assertIn(get_args(collections.abc.Callable[[], str]),
1826+
(([], str), ([[]], str)))
1827+
self.assertEqual(get_args(collections.abc.Callable[..., str]), (..., str))
18321828
P = ParamSpec('P')
1833-
# In 3.9 and lower we use typing_extensions's hacky implementation
1829+
# In 3.9 we use typing_extensions's hacky implementation
18341830
# of ParamSpec, which gets incorrectly wrapped in a list
18351831
self.assertIn(get_args(Callable[P, int]), [(P, int), ([P], int)])
18361832
self.assertEqual(get_args(Required[int]), (int,))
@@ -3808,7 +3804,7 @@ def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: ...
38083804
MemoizedFunc[[int, str, str]]
38093805

38103806
if sys.version_info >= (3, 10):
3811-
# These unfortunately don't pass on <=3.9,
3807+
# These unfortunately don't pass on 3.9,
38123808
# due to typing._type_check on older Python versions
38133809
X = MemoizedFunc[[int, str, str], T, T2]
38143810
self.assertEqual(X.__parameters__, (T, T2))
@@ -4553,7 +4549,7 @@ class PointDict3D(PointDict2D, total=False):
45534549
assert is_typeddict(PointDict2D) is True
45544550
assert is_typeddict(PointDict3D) is True
45554551

4556-
@skipUnless(HAS_FORWARD_MODULE, "ForwardRef.__forward_module__ was added in 3.9")
4552+
@skipUnless(HAS_FORWARD_MODULE, "ForwardRef.__forward_module__ was added in 3.9.7")
45574553
def test_get_type_hints_cross_module_subclass(self):
45584554
self.assertNotIn("_DoNotImport", globals())
45594555
self.assertEqual(
@@ -4696,11 +4692,9 @@ class WithImplicitAny(B):
46964692
with self.assertRaises(TypeError):
46974693
WithImplicitAny[str]
46984694

4699-
@skipUnless(TYPING_3_9_0, "Was changed in 3.9")
47004695
def test_non_generic_subscript(self):
47014696
# For backward compatibility, subscription works
47024697
# on arbitrary TypedDict types.
4703-
# (But we don't attempt to backport this misfeature onto 3.8.)
47044698
class TD(TypedDict):
47054699
a: T
47064700
A = TD[int]
@@ -5163,7 +5157,7 @@ class C:
51635157
A.x = 5
51645158
self.assertEqual(C.x, 5)
51655159

5166-
@skipIf(sys.version_info[:2] in ((3, 9), (3, 10)), "Waiting for bpo-46491 bugfix.")
5160+
@skipIf(sys.version_info[:2] == (3, 10), "Waiting for https://github.com/python/cpython/issues/90649 bugfix.")
51675161
def test_special_form_containment(self):
51685162
class C:
51695163
classvar: Annotated[ClassVar[int], "a decoration"] = 4
@@ -5475,21 +5469,20 @@ def test_valid_uses(self):
54755469
self.assertEqual(C2.__parameters__, (P, T))
54765470

54775471
# Test collections.abc.Callable too.
5478-
if sys.version_info[:2] >= (3, 9):
5479-
# Note: no tests for Callable.__parameters__ here
5480-
# because types.GenericAlias Callable is hardcoded to search
5481-
# for tp_name "TypeVar" in C. This was changed in 3.10.
5482-
C3 = collections.abc.Callable[P, int]
5483-
self.assertEqual(C3.__args__, (P, int))
5484-
C4 = collections.abc.Callable[P, T]
5485-
self.assertEqual(C4.__args__, (P, T))
5472+
# Note: no tests for Callable.__parameters__ here
5473+
# because types.GenericAlias Callable is hardcoded to search
5474+
# for tp_name "TypeVar" in C. This was changed in 3.10.
5475+
C3 = collections.abc.Callable[P, int]
5476+
self.assertEqual(C3.__args__, (P, int))
5477+
C4 = collections.abc.Callable[P, T]
5478+
self.assertEqual(C4.__args__, (P, T))
54865479

54875480
# ParamSpec instances should also have args and kwargs attributes.
54885481
# Note: not in dir(P) because of __class__ hacks
54895482
self.assertTrue(hasattr(P, 'args'))
54905483
self.assertTrue(hasattr(P, 'kwargs'))
54915484

5492-
@skipIf((3, 10, 0) <= sys.version_info[:3] <= (3, 10, 2), "Needs bpo-46676.")
5485+
@skipIf((3, 10, 0) <= sys.version_info[:3] <= (3, 10, 2), "Needs https://github.com/python/cpython/issues/90834.")
54935486
def test_args_kwargs(self):
54945487
P = ParamSpec('P')
54955488
P_2 = ParamSpec('P_2')
@@ -5649,8 +5642,6 @@ class ProtoZ(Protocol[P]):
56495642
G10 = klass[int, Concatenate[str, P]]
56505643
with self.subTest("Check invalid form substitution"):
56515644
self.assertEqual(G10.__parameters__, (P, ))
5652-
if sys.version_info < (3, 9):
5653-
self.skipTest("3.8 typing._type_subst does not support this substitution process")
56545645
H10 = G10[int]
56555646
if (3, 10) <= sys.version_info < (3, 11, 3):
56565647
self.skipTest("3.10-3.11.2 does not substitute Concatenate here")
@@ -5780,9 +5771,6 @@ def test_valid_uses(self):
57805771
T = TypeVar('T')
57815772
for callable_variant in (Callable, collections.abc.Callable):
57825773
with self.subTest(callable_variant=callable_variant):
5783-
if not TYPING_3_9_0 and callable_variant is collections.abc.Callable:
5784-
self.skipTest("Needs PEP 585")
5785-
57865774
C1 = callable_variant[Concatenate[int, P], int]
57875775
C2 = callable_variant[Concatenate[int, T, P], T]
57885776
self.assertEqual(C1.__origin__, C2.__origin__)
@@ -5830,7 +5818,7 @@ def test_invalid_uses(self):
58305818
):
58315819
Concatenate[(str,), P]
58325820

5833-
@skipUnless(TYPING_3_10_0, "Missing backport to <=3.9. See issue #48")
5821+
@skipUnless(TYPING_3_10_0, "Missing backport to 3.9. See issue #48")
58345822
def test_alias_subscription_with_ellipsis(self):
58355823
P = ParamSpec('P')
58365824
X = Callable[Concatenate[int, P], Any]
@@ -6813,7 +6801,6 @@ class Y(Generic[T], NamedTuple):
68136801
with self.assertRaisesRegex(TypeError, f'Too many {things}'):
68146802
G[int, str]
68156803

6816-
@skipUnless(TYPING_3_9_0, "tuple.__class_getitem__ was added in 3.9")
68176804
def test_non_generic_subscript_py39_plus(self):
68186805
# For backward compatibility, subscription works
68196806
# on arbitrary NamedTuple types.
@@ -6828,19 +6815,6 @@ class Group(NamedTuple):
68286815
self.assertIs(type(a), Group)
68296816
self.assertEqual(a, (1, [2]))
68306817

6831-
@skipIf(TYPING_3_9_0, "Test isn't relevant to 3.9+")
6832-
def test_non_generic_subscript_error_message_py38(self):
6833-
class Group(NamedTuple):
6834-
key: T
6835-
group: List[T]
6836-
6837-
with self.assertRaisesRegex(TypeError, 'not subscriptable'):
6838-
Group[int]
6839-
6840-
for attr in ('__args__', '__origin__', '__parameters__'):
6841-
with self.subTest(attr=attr):
6842-
self.assertFalse(hasattr(Group, attr))
6843-
68446818
def test_namedtuple_keyword_usage(self):
68456819
with self.assertWarnsRegex(
68466820
DeprecationWarning,
@@ -6959,21 +6933,13 @@ def test_copy_and_pickle(self):
69596933
def test_docstring(self):
69606934
self.assertIsInstance(NamedTuple.__doc__, str)
69616935

6962-
@skipUnless(TYPING_3_9_0, "NamedTuple was a class on 3.8 and lower")
6963-
def test_same_as_typing_NamedTuple_39_plus(self):
6936+
def test_same_as_typing_NamedTuple(self):
69646937
self.assertEqual(
69656938
set(dir(NamedTuple)) - {"__text_signature__"},
69666939
set(dir(typing.NamedTuple))
69676940
)
69686941
self.assertIs(type(NamedTuple), type(typing.NamedTuple))
69696942

6970-
@skipIf(TYPING_3_9_0, "tests are only relevant to <=3.8")
6971-
def test_same_as_typing_NamedTuple_38_minus(self):
6972-
self.assertEqual(
6973-
self.NestedEmployee.__annotations__,
6974-
self.NestedEmployee._field_types
6975-
)
6976-
69776943
def test_orig_bases(self):
69786944
T = TypeVar('T')
69796945

@@ -7235,11 +7201,8 @@ def test_bound_errors(self):
72357201
r"Bound must be a type\. Got \(1, 2\)\."):
72367202
TypeVar('X', bound=(1, 2))
72377203

7238-
# Technically we could run it on later versions of 3.8,
7239-
# but that's not worth the effort.
7240-
@skipUnless(TYPING_3_9_0, "Fix was not backported")
72417204
def test_missing__name__(self):
7242-
# See bpo-39942
7205+
# See https://github.com/python/cpython/issues/84123
72437206
code = ("import typing\n"
72447207
"T = typing.TypeVar('T')\n"
72457208
)
@@ -7420,9 +7383,8 @@ def test_allow_default_after_non_default_in_alias(self):
74207383
a1 = Callable[[T_default], T]
74217384
self.assertEqual(a1.__args__, (T_default, T))
74227385

7423-
if sys.version_info >= (3, 9):
7424-
a2 = dict[T_default, T]
7425-
self.assertEqual(a2.__args__, (T_default, T))
7386+
a2 = dict[T_default, T]
7387+
self.assertEqual(a2.__args__, (T_default, T))
74267388

74277389
a3 = typing.Dict[T_default, T]
74287390
self.assertEqual(a3.__args__, (T_default, T))
@@ -7602,7 +7564,6 @@ class D(B[str], float): pass
76027564
with self.assertRaisesRegex(TypeError, "Expected an instance of type"):
76037565
get_original_bases(object())
76047566

7605-
@skipUnless(TYPING_3_9_0, "PEP 585 is yet to be")
76067567
def test_builtin_generics(self):
76077568
class E(list[T]): pass
76087569
class F(list[int]): pass
@@ -8848,7 +8809,6 @@ def test_fwdref_value_is_cached(self):
88488809
self.assertIs(evaluate_forward_ref(fr, globals={"hello": str}), str)
88498810
self.assertIs(evaluate_forward_ref(fr), str)
88508811

8851-
@skipUnless(TYPING_3_9_0, "Needs PEP 585 support")
88528812
def test_fwdref_with_owner(self):
88538813
self.assertEqual(
88548814
evaluate_forward_ref(typing.ForwardRef("Counter[int]"), owner=collections),
@@ -8894,16 +8854,14 @@ class Y(Generic[Tx]):
88948854
with self.subTest("nested string of TypeVar"):
88958855
evaluated_ref2 = evaluate_forward_ref(typing.ForwardRef("""Y["Y['Tx']"]"""), locals={"Y": Y})
88968856
self.assertEqual(get_origin(evaluated_ref2), Y)
8897-
if not TYPING_3_9_0:
8898-
self.skipTest("Nested string 'Tx' stays ForwardRef in 3.8")
88998857
self.assertEqual(get_args(evaluated_ref2), (Y[Tx],))
89008858

89018859
with self.subTest("nested string of TypeAliasType and alias"):
89028860
# NOTE: Using Y here works for 3.10
89038861
evaluated_ref3 = evaluate_forward_ref(typing.ForwardRef("""Y['Z["StrAlias"]']"""), locals={"Y": Y, "Z": Z, "StrAlias": str})
89048862
self.assertEqual(get_origin(evaluated_ref3), Y)
8905-
if sys.version_info[:2] in ((3,8), (3, 10)):
8906-
self.skipTest("Nested string 'StrAlias' is not resolved in 3.8 and 3.10")
8863+
if sys.version_info[:2] == (3, 10):
8864+
self.skipTest("Nested string 'StrAlias' is not resolved in 3.10")
89078865
self.assertEqual(get_args(evaluated_ref3), (Z[str],))
89088866

89098867
def test_invalid_special_forms(self):

0 commit comments

Comments
 (0)
0