Skip to content

Commit ec1876c

Browse files
More fixes for 3.14 and 3.15 (#602)
1 parent e89d789 commit ec1876c

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
- Do not attempt to re-export names that have been removed from `typing`,
55
anticipating the removal of `typing.no_type_check_decorator` in Python 3.15.
66
Patch by Jelle Zijlstra.
7-
- Update `typing_extensions.Format` and `typing_extensions.evaluate_forward_ref` to align
8-
with changes in Python 3.14. Patch by Jelle Zijlstra.
9-
- Fix tests for Python 3.14. Patch by Jelle Zijlstra.
7+
- Update `typing_extensions.Format`, `typing_extensions.evaluate_forward_ref`, and
8+
`typing_extensions.TypedDict` to align
9+
with changes in Python 3.14. Patches by Jelle Zijlstra.
10+
- Fix tests for Python 3.14 and 3.15. Patches by Jelle Zijlstra.
1011

1112
New features:
1213

src/test_typing_extensions.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4402,6 +4402,39 @@ class Cat(Animal):
44024402
'voice': str,
44034403
}
44044404

4405+
@skipIf(sys.version_info == (3, 14, 0, "beta", 1), "Broken on beta 1, fixed in beta 2")
4406+
def test_inheritance_pep563(self):
4407+
def _make_td(future, class_name, annos, base, extra_names=None):
4408+
lines = []
4409+
if future:
4410+
lines.append('from __future__ import annotations')
4411+
lines.append('from typing import TypedDict')
4412+
lines.append(f'class {class_name}({base}):')
4413+
for name, anno in annos.items():
4414+
lines.append(f' {name}: {anno}')
4415+
code = '\n'.join(lines)
4416+
ns = {**extra_names} if extra_names else {}
4417+
exec(code, ns)
4418+
return ns[class_name]
4419+
4420+
for base_future in (True, False):
4421+
for child_future in (True, False):
4422+
with self.subTest(base_future=base_future, child_future=child_future):
4423+
base = _make_td(
4424+
base_future, "Base", {"base": "int"}, "TypedDict"
4425+
)
4426+
if sys.version_info >= (3, 14):
4427+
self.assertIsNotNone(base.__annotate__)
4428+
child = _make_td(
4429+
child_future, "Child", {"child": "int"}, "Base", {"Base": base}
4430+
)
4431+
base_anno = typing.ForwardRef("int", module="builtins") if base_future else int
4432+
child_anno = typing.ForwardRef("int", module="builtins") if child_future else int
4433+
self.assertEqual(base.__annotations__, {'base': base_anno})
4434+
self.assertEqual(
4435+
child.__annotations__, {'child': child_anno, 'base': base_anno}
4436+
)
4437+
44054438
def test_required_notrequired_keys(self):
44064439
self.assertEqual(NontotalMovie.__required_keys__,
44074440
frozenset({"title"}))
@@ -7014,6 +7047,7 @@ class Group(NamedTuple):
70147047
self.assertIs(type(a), Group)
70157048
self.assertEqual(a, (1, [2]))
70167049

7050+
@skipUnless(sys.version_info <= (3, 15), "Behavior removed in 3.15")
70177051
def test_namedtuple_keyword_usage(self):
70187052
with self.assertWarnsRegex(
70197053
DeprecationWarning,
@@ -7049,6 +7083,7 @@ def test_namedtuple_keyword_usage(self):
70497083
):
70507084
NamedTuple('Name', None, x=int)
70517085

7086+
@skipUnless(sys.version_info <= (3, 15), "Behavior removed in 3.15")
70527087
def test_namedtuple_special_keyword_names(self):
70537088
with self.assertWarnsRegex(
70547089
DeprecationWarning,
@@ -7064,6 +7099,7 @@ def test_namedtuple_special_keyword_names(self):
70647099
self.assertEqual(a.typename, 'foo')
70657100
self.assertEqual(a.fields, [('bar', tuple)])
70667101

7102+
@skipUnless(sys.version_info <= (3, 15), "Behavior removed in 3.15")
70677103
def test_empty_namedtuple(self):
70687104
expected_warning = re.escape(
70697105
"Failing to pass a value for the 'fields' parameter is deprecated "

src/typing_extensions.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,8 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None,
10161016
else:
10171017
generic_base = ()
10181018

1019+
ns_annotations = ns.pop('__annotations__', None)
1020+
10191021
# typing.py generally doesn't let you inherit from plain Generic, unless
10201022
# the name of the class happens to be "Protocol"
10211023
tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns)
@@ -1028,8 +1030,8 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None,
10281030

10291031
annotations = {}
10301032
own_annotate = None
1031-
if "__annotations__" in ns:
1032-
own_annotations = ns["__annotations__"]
1033+
if ns_annotations is not None:
1034+
own_annotations = ns_annotations
10331035
elif sys.version_info >= (3, 14):
10341036
if hasattr(annotationlib, "get_annotate_from_class_namespace"):
10351037
own_annotate = annotationlib.get_annotate_from_class_namespace(ns)
@@ -1119,7 +1121,7 @@ def __annotate__(format):
11191121
if base_annotate is None:
11201122
continue
11211123
base_annos = annotationlib.call_annotate_function(
1122-
base.__annotate__, format, owner=base)
1124+
base_annotate, format, owner=base)
11231125
annos.update(base_annos)
11241126
if own_annotate is not None:
11251127
own = annotationlib.call_annotate_function(

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy