From e87e79dcfaa1f27ee0fad7fd863adc69a8770c1a Mon Sep 17 00:00:00 2001 From: Daniel Sperber Date: Sat, 22 Feb 2025 17:57:24 +0100 Subject: [PATCH 1/4] Backport of python/cpython#109544 Co-authored-by: Jelle Zijlstra --- src/test_typing_extensions.py | 11 +++++++++++ src/typing_extensions.py | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index ac8bb0f3..b5c433ac 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -4237,6 +4237,17 @@ def test_total(self): self.assertEqual(Options.__required_keys__, frozenset()) self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) + def test_total_inherits_non_total(self): + class TD1(TypedDict, total=False): + a: int + + self.assertIs(TD1.__total__, False) + + class TD2(TD1): + b: str + + self.assertIs(TD2.__total__, True) + def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): z: int diff --git a/src/typing_extensions.py b/src/typing_extensions.py index e7d20815..fe492a3f 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -1029,8 +1029,7 @@ def __new__(cls, name, bases, ns, *, total=True, closed=False): tp_dict.__optional_keys__ = frozenset(optional_keys) tp_dict.__readonly_keys__ = frozenset(readonly_keys) tp_dict.__mutable_keys__ = frozenset(mutable_keys) - if not hasattr(tp_dict, '__total__'): - tp_dict.__total__ = total + tp_dict.__total__ = total tp_dict.__closed__ = closed tp_dict.__extra_items__ = extra_items_type return tp_dict From e2abebf6e45a4f114a181d61252dc4a3622e71ce Mon Sep 17 00:00:00 2001 From: Daniel Sperber Date: Sat, 22 Feb 2025 17:58:22 +0100 Subject: [PATCH 2/4] backport of python/cpython#130460 --- src/test_typing_extensions.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index b5c433ac..979e4250 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -4248,6 +4248,22 @@ class TD2(TD1): self.assertIs(TD2.__total__, True) + def test_total_with_assigned_value(self): + class TD(TypedDict): + __total__ = "some_value" + + self.assertIs(TD.__total__, True) + + class TD2(TypedDict, total=True): + __total__ = "some_value" + + self.assertIs(TD2.__total__, True) + + class TD3(TypedDict, total=False): + __total__ = "some value" + + self.assertIs(TD3.__total__, False) + def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): z: int From 1bd079fd96f421211ce795f11017f4a3d58cb985 Mon Sep 17 00:00:00 2001 From: Daniel Sperber Date: Sat, 22 Feb 2025 19:21:12 +0100 Subject: [PATCH 3/4] Add test also for functional interface --- src/test_typing_extensions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 979e4250..17ce28f2 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -4264,6 +4264,10 @@ class TD3(TypedDict, total=False): self.assertIs(TD3.__total__, False) + TD4 = TypedDict('TD4', {'__total__': "some_value"}) # noqa: F821 + self.assertIs(TD4.__total__, True) + + def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): z: int From af59a5ad19b93d00889db5f0c0a203fe0883bef1 Mon Sep 17 00:00:00 2001 From: Daniel Sperber Date: Sat, 22 Feb 2025 19:28:19 +0100 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2aa42922..690bf5d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ aliases that have a `Concatenate` special form as their argument. Patch by [Daraan](https://github.com/Daraan). - Fix error on Python 3.10 when using `typing.Concatenate` and `typing_extensions.Concatenate` together. Patch by [Daraan](https://github.com/Daraan). +- Backport of CPython PR [#109544](https://github.com/python/cpython/pull/109544) + to reflect Python 3.13+ behavior: A value assigned to `__total__` in the class body of a + `TypedDict` will be overwritten by the `total` argument of the `TypedDict` constructor. + Patch by [Daraan](https://github.com/Daraan), backporting a CPython PR by Jelle Zijlstra. # Release 4.12.2 (June 7, 2024)