From 039d4e8ee48fa7d354f8c851ad63efee5b4f2a97 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 20 Jan 2022 18:53:20 +0300 Subject: [PATCH 1/3] bpo-46445: cover multiple inheritance of `TypedDict` in `test_typing` --- Lib/test/test_typing.py | 72 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index ce0c940e2a112ee..cd9162248ad0715 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -22,7 +22,6 @@ from typing import is_typeddict from typing import no_type_check, no_type_check_decorator from typing import Type -from typing import NewType from typing import NamedTuple, TypedDict from typing import IO, TextIO, BinaryIO from typing import Pattern, Match @@ -4393,6 +4392,77 @@ class Cat(Animal): 'voice': str, } + def test_multiple_inheritance(self): + class One(TypedDict): + one: int + class Two(TypedDict): + two: str + class Untotal(TypedDict, total=False): + untotal: str + Inline = TypedDict('Inline', {'inline': bool}) + class Regular: + pass + + class Child(One, Two): + child: bool + self.assertEqual( + Child.__required_keys__, + frozenset(['one', 'two', 'child']), + ) + self.assertEqual( + Child.__optional_keys__, + frozenset([]), + ) + self.assertEqual( + Child.__annotations__, + {'one': int, 'two': str, 'child': bool}, + ) + + class ChildWithOptional(One, Untotal): + child: bool + self.assertEqual( + ChildWithOptional.__required_keys__, + frozenset(['one', 'child']), + ) + self.assertEqual( + ChildWithOptional.__optional_keys__, + frozenset(['untotal']), + ) + self.assertEqual( + ChildWithOptional.__annotations__, + {'one': int, 'untotal': str, 'child': bool}, + ) + + class ChildWithInlineAndOptional(Untotal, Inline): + child: bool + self.assertEqual( + ChildWithInlineAndOptional.__required_keys__, + frozenset(['inline', 'child']), + ) + self.assertEqual( + ChildWithInlineAndOptional.__optional_keys__, + frozenset(['untotal']), + ) + self.assertEqual( + ChildWithInlineAndOptional.__annotations__, + {'inline': bool, 'untotal': str, 'child': bool}, + ) + + wrong_bases = [ + (One, Regular), + (Regular, One), + (One, Two, Regular), + (Inline, Regular), + ] + for bases in wrong_bases: + with self.subTest(bases=bases): + with self.assertRaisesRegex( + TypeError, + 'cannot inherit from both a TypedDict type and a non-TypedDict', + ): + class Wrong(*bases): + pass + def test_is_typeddict(self): assert is_typeddict(Point2D) is True assert is_typeddict(Union[str, int]) is False From bcc867c87d1d6788b102c650f0efa56fe1110642 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 21 Jan 2022 21:17:52 +0300 Subject: [PATCH 2/3] Address review --- Lib/test/test_typing.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index cd9162248ad0715..26b0ed6ec2b872f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4433,6 +4433,21 @@ class ChildWithOptional(One, Untotal): {'one': int, 'untotal': str, 'child': bool}, ) + class ChildWithTotalFalse(One, Untotal, total=False): + child: bool + self.assertEqual( + ChildWithTotalFalse.__required_keys__, + frozenset(['one']), + ) + self.assertEqual( + ChildWithTotalFalse.__optional_keys__, + frozenset(['untotal', 'child']), + ) + self.assertEqual( + ChildWithTotalFalse.__annotations__, + {'one': int, 'untotal': str, 'child': bool}, + ) + class ChildWithInlineAndOptional(Untotal, Inline): child: bool self.assertEqual( From 2f1b06f98ef658e8ebc7b5fc70a22ca687ac5ebc Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 21 Jan 2022 21:21:12 +0300 Subject: [PATCH 3/3] One more test --- Lib/test/test_typing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 26b0ed6ec2b872f..150d7c081c30b64 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4468,6 +4468,7 @@ class ChildWithInlineAndOptional(Untotal, Inline): (Regular, One), (One, Two, Regular), (Inline, Regular), + (Untotal, Regular), ] for bases in wrong_bases: with self.subTest(bases=bases):