summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2022-01-21 21:38:23 (GMT)
committerGitHub <noreply@github.com>2022-01-21 21:38:23 (GMT)
commit65b88d5e01c845c0cfa3ff61bc8b2faec8f67a57 (patch)
treed09fb38ac18cb172d35ec85dbde4c70f6b7ef0f6
parent881a763cfe07ef4a5806ec78f13a9bc99e8909dc (diff)
downloadcpython-65b88d5e01c845c0cfa3ff61bc8b2faec8f67a57.zip
cpython-65b88d5e01c845c0cfa3ff61bc8b2faec8f67a57.tar.gz
cpython-65b88d5e01c845c0cfa3ff61bc8b2faec8f67a57.tar.bz2
bpo-46445: Cover multiple inheritance of `TypedDict` in `test_typing` (GH-30719)
-rw-r--r--Lib/test/test_typing.py88
1 files changed, 87 insertions, 1 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index ce0c940..150d7c0 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -22,7 +22,6 @@ from typing import get_origin, get_args
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,93 @@ class TypedDictTests(BaseTestCase):
'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 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(
+ 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),
+ (Untotal, 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