Skip to content

Commit 8860c6a

Browse files
authored
Drop support for Python 3.7 (#267)
1 parent b518f6a commit 8860c6a

File tree

9 files changed

+144
-416
lines changed

9 files changed

+144
-416
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ jobs:
4242
# For available versions, see:
4343
# https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
4444
python-version:
45-
- "3.7"
46-
- "3.7.1"
4745
- "3.8"
4846
- "3.8.0"
4947
- "3.9"
@@ -53,7 +51,6 @@ jobs:
5351
- "3.11"
5452
- "3.11.0"
5553
- "3.12"
56-
- "pypy3.7"
5754
- "pypy3.8"
5855
- "pypy3.9"
5956
- "pypy3.10"

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Release 4.8.0 (???)
2+
3+
- Drop support for Python 3.7 (including PyPy-3.7). Patch by Alex Waygood.
4+
15
# Release 4.7.1 (July 2, 2023)
26

37
- Fix support for `TypedDict`, `NamedTuple` and `is_protocol` on PyPy-3.7 and

CONTRIBUTING.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ standard library, so that users can experiment with them before they are added t
1818
standard library. Such features should already be specified in a PEP or merged into
1919
CPython's `main` branch.
2020

21-
`typing_extensions` supports Python versions 3.7 and up.
22-
2321
# Versioning scheme
2422

2523
Starting with version 4.0.0, `typing_extensions` uses

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ Therefore, it's safe to depend
2626
on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`,
2727
where `x.y` is the first version that includes all features you need.
2828

29-
`typing_extensions` supports Python versions 3.7 and higher.
30-
3129
## Included items
3230

3331
See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a

doc/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Example usage::
135135
Python version support
136136
----------------------
137137

138-
``typing_extensions`` currently supports Python versions 3.7 and higher. In the future,
138+
``typing_extensions`` currently supports Python versions 3.8 and higher. In the future,
139139
support for older Python versions will be dropped some time after that version
140140
reaches end of life.
141141

pyproject.toml

Lines changed: 2 additions & 3 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.7.1"
10-
description = "Backported and Experimental Type Hints for Python 3.7+"
10+
description = "Backported and Experimental Type Hints for Python 3.8+"
1111
readme = "README.md"
12-
requires-python = ">=3.7"
12+
requires-python = ">=3.8"
1313
license = { file = "LICENSE" }
1414
keywords = [
1515
"annotations",
@@ -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.7",
3837
"Programming Language :: Python :: 3.8",
3938
"Programming Language :: Python :: 3.9",
4039
"Programming Language :: Python :: 3.10",

src/test_typing_extensions.py

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
# Flags used to mark tests that only apply after a specific
4444
# version of the typing module.
45-
TYPING_3_8_0 = sys.version_info[:3] >= (3, 8, 0)
4645
TYPING_3_9_0 = sys.version_info[:3] >= (3, 9, 0)
4746
TYPING_3_10_0 = sys.version_info[:3] >= (3, 10, 0)
4847

@@ -52,10 +51,6 @@
5251
# 3.12 changes the representation of Unpack[] (PEP 692)
5352
TYPING_3_12_0 = sys.version_info[:3] >= (3, 12, 0)
5453

55-
only_with_typing_Protocol = skipUnless(
56-
hasattr(typing, "Protocol"), "Only relevant when typing.Protocol exists"
57-
)
58-
5954
# https://github.com/python/cpython/pull/27017 was backported into some 3.9 and 3.10
6055
# versions, but not all
6156
HAS_FORWARD_MODULE = "module" in inspect.signature(typing._type_check).parameters
@@ -246,13 +241,7 @@ def some(arg: NoReturn) -> NoReturn: ...
246241
def some_str(arg: 'NoReturn') -> 'typing.NoReturn': ...
247242

248243
expected = {'arg': NoReturn, 'return': NoReturn}
249-
targets = [some]
250-
251-
# On 3.7.0 and 3.7.1, https://github.com/python/cpython/pull/10772
252-
# wasn't applied yet and NoReturn fails _type_check.
253-
if not ((3, 7, 0) <= sys.version_info < (3, 7, 2)):
254-
targets.append(some_str)
255-
for target in targets:
244+
for target in some, some_str:
256245
with self.subTest(target=target):
257246
self.assertEqual(gth(target), expected)
258247

@@ -595,15 +584,11 @@ def test_basics(self):
595584
Final[int][str]
596585

597586
def test_repr(self):
598-
if hasattr(typing, 'Final') and sys.version_info[:2] >= (3, 7):
599-
mod_name = 'typing'
600-
else:
601-
mod_name = 'typing_extensions'
602-
self.assertEqual(repr(Final), mod_name + '.Final')
587+
self.assertEqual(repr(Final), 'typing.Final')
603588
cv = Final[int]
604-
self.assertEqual(repr(cv), mod_name + '.Final[int]')
589+
self.assertEqual(repr(cv), 'typing.Final[int]')
605590
cv = Final[Employee]
606-
self.assertEqual(repr(cv), mod_name + f'.Final[{__name__}.Employee]')
591+
self.assertEqual(repr(cv), f'typing.Final[{__name__}.Employee]')
607592

608593
def test_cannot_subclass(self):
609594
with self.assertRaises(TypeError):
@@ -1771,7 +1756,6 @@ class E(C, BP): pass
17711756
self.assertNotIsInstance(D(), E)
17721757
self.assertNotIsInstance(E(), D)
17731758

1774-
@only_with_typing_Protocol
17751759
def test_runtimecheckable_on_typing_dot_Protocol(self):
17761760
@runtime_checkable
17771761
class Foo(typing.Protocol):
@@ -1784,7 +1768,6 @@ def __init__(self):
17841768
self.assertIsInstance(Bar(), Foo)
17851769
self.assertNotIsInstance(object(), Foo)
17861770

1787-
@only_with_typing_Protocol
17881771
def test_typing_dot_runtimecheckable_on_Protocol(self):
17891772
@typing.runtime_checkable
17901773
class Foo(Protocol):
@@ -1797,7 +1780,6 @@ def __init__(self):
17971780
self.assertIsInstance(Bar(), Foo)
17981781
self.assertNotIsInstance(object(), Foo)
17991782

1800-
@only_with_typing_Protocol
18011783
def test_typing_Protocol_and_extensions_Protocol_can_mix(self):
18021784
class TypingProto(typing.Protocol):
18031785
x: int
@@ -3173,7 +3155,6 @@ def c(self) -> int: return 5
31733155
with self.assertRaisesRegex(TypeError, "not a Protocol"):
31743156
get_protocol_members(ConcreteInherit())
31753157

3176-
@only_with_typing_Protocol
31773158
def test_get_protocol_members_typing(self):
31783159
with self.assertRaisesRegex(TypeError, "not a Protocol"):
31793160
get_protocol_members(typing.Protocol)
@@ -3222,7 +3203,6 @@ def test_is_protocol(self):
32223203
# Protocol is not itself a protocol
32233204
self.assertFalse(is_protocol(Protocol))
32243205

3225-
@only_with_typing_Protocol
32263206
def test_is_protocol_with_typing(self):
32273207
self.assertFalse(is_protocol(typing.Protocol))
32283208

@@ -3681,7 +3661,6 @@ class NewGeneric[T](TypedDict):
36813661
if hasattr(typing, "TypedDict"):
36823662
self.assertIs(is_typeddict(typing.TypedDict), False)
36833663

3684-
@skipUnless(TYPING_3_8_0, "Python 3.8+ required")
36853664
def test_is_typeddict_against_typeddict_from_typing(self):
36863665
Point = typing.TypedDict('Point', {'x': int, 'y': int})
36873666

@@ -3844,7 +3823,7 @@ class WithImplicitAny(B):
38443823
def test_non_generic_subscript(self):
38453824
# For backward compatibility, subscription works
38463825
# on arbitrary TypedDict types.
3847-
# (But we don't attempt to backport this misfeature onto 3.7 and 3.8.)
3826+
# (But we don't attempt to backport this misfeature onto 3.8.)
38483827
class TD(TypedDict):
38493828
a: T
38503829
A = TD[int]
@@ -4034,17 +4013,8 @@ class C:
40344013
classvar: Annotated[ClassVar[int], "a decoration"] = 4
40354014
const: Annotated[Final[int], "Const"] = 4
40364015

4037-
if sys.version_info[:2] >= (3, 7):
4038-
self.assertEqual(get_type_hints(C, globals())["classvar"], ClassVar[int])
4039-
self.assertEqual(get_type_hints(C, globals())["const"], Final[int])
4040-
else:
4041-
self.assertEqual(
4042-
get_type_hints(C, globals())["classvar"],
4043-
Annotated[ClassVar[int], "a decoration"]
4044-
)
4045-
self.assertEqual(
4046-
get_type_hints(C, globals())["const"], Annotated[Final[int], "Const"]
4047-
)
4016+
self.assertEqual(get_type_hints(C, globals())["classvar"], ClassVar[int])
4017+
self.assertEqual(get_type_hints(C, globals())["const"], Final[int])
40484018

40494019
def test_cannot_subclass(self):
40504020
with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"):
@@ -5069,11 +5039,8 @@ def test_typing_extensions_defers_when_possible(self):
50695039
'dataclass_transform',
50705040
'overload',
50715041
'ParamSpec',
5072-
'Text',
50735042
'TypeVar',
50745043
'TypeVarTuple',
5075-
'TYPE_CHECKING',
5076-
'Final',
50775044
'get_type_hints',
50785045
}
50795046
if sys.version_info < (3, 10):
@@ -5189,13 +5156,6 @@ class NonDefaultAfterDefault(NamedTuple):
51895156
x: int = 3
51905157
y: int
51915158

5192-
@skipUnless(
5193-
(
5194-
TYPING_3_8_0
5195-
or hasattr(CoolEmployeeWithDefault, '_field_defaults')
5196-
),
5197-
'"_field_defaults" attribute was added in a micro version of 3.7'
5198-
)
51995159
def test_field_defaults(self):
52005160
self.assertEqual(CoolEmployeeWithDefault._field_defaults, dict(cool=0))
52015161

@@ -5296,7 +5256,7 @@ class Group(NamedTuple):
52965256
self.assertEqual(a, (1, [2]))
52975257

52985258
@skipIf(TYPING_3_9_0, "Test isn't relevant to 3.9+")
5299-
def test_non_generic_subscript_error_message_py38_minus(self):
5259+
def test_non_generic_subscript_error_message_py38(self):
53005260
class Group(NamedTuple):
53015261
key: T
53025262
group: List[T]
@@ -5389,10 +5349,7 @@ class CNT(NamedTuple):
53895349
self.assertEqual(struct._fields, ())
53905350
self.assertEqual(struct.__annotations__, {})
53915351
self.assertIsInstance(struct(), struct)
5392-
# Attribute was added in a micro version of 3.7
5393-
# and is tested more fully elsewhere
5394-
if hasattr(struct, "_field_defaults"):
5395-
self.assertEqual(struct._field_defaults, {})
5352+
self.assertEqual(struct._field_defaults, {})
53965353

53975354
def test_namedtuple_errors(self):
53985355
with self.assertRaises(TypeError):
@@ -5429,15 +5386,6 @@ def test_copy_and_pickle(self):
54295386
def test_docstring(self):
54305387
self.assertIsInstance(NamedTuple.__doc__, str)
54315388

5432-
@skipUnless(TYPING_3_8_0, "NamedTuple had a bad signature on <=3.7")
5433-
def test_signature_is_same_as_typing_NamedTuple(self):
5434-
self.assertEqual(inspect.signature(NamedTuple), inspect.signature(typing.NamedTuple))
5435-
5436-
@skipIf(TYPING_3_8_0, "tests are only relevant to <=3.7")
5437-
def test_signature_on_37(self):
5438-
self.assertIsInstance(inspect.signature(NamedTuple), inspect.Signature)
5439-
self.assertFalse(hasattr(NamedTuple, "__text_signature__"))
5440-
54415389
@skipUnless(TYPING_3_9_0, "NamedTuple was a class on 3.8 and lower")
54425390
def test_same_as_typing_NamedTuple_39_plus(self):
54435391
self.assertEqual(
@@ -5592,7 +5540,7 @@ def test_bound_errors(self):
55925540
r"Bound must be a type\. Got \(1, 2\)\."):
55935541
TypeVar('X', bound=(1, 2))
55945542

5595-
# Technically we could run it on later versions of 3.7 and 3.8,
5543+
# Technically we could run it on later versions of 3.8,
55965544
# but that's not worth the effort.
55975545
@skipUnless(TYPING_3_9_0, "Fix was not backported")
55985546
def test_missing__name__(self):

0 commit comments

Comments
 (0)