bpo-37049: PEP 589: Add TypedDict to typing module (GH-13573) · python/cpython@135c6a5 (original) (raw)
`@@ -18,7 +18,7 @@
`
18
18
`from typing import no_type_check, no_type_check_decorator
`
19
19
`from typing import Type
`
20
20
`from typing import NewType
`
21
``
`-
from typing import NamedTuple
`
``
21
`+
from typing import NamedTuple, TypedDict
`
22
22
`from typing import IO, TextIO, BinaryIO
`
23
23
`from typing import Pattern, Match
`
24
24
`import abc
`
`@@ -1883,6 +1883,18 @@ def str(self):
`
1883
1883
`def add(self, other):
`
1884
1884
`return 0
`
1885
1885
``
``
1886
`+
Label = TypedDict('Label', [('label', str)])
`
``
1887
+
``
1888
`+
class Point2D(TypedDict):
`
``
1889
`+
x: int
`
``
1890
`+
y: int
`
``
1891
+
``
1892
`+
class LabelPoint2D(Point2D, Label): ...
`
``
1893
+
``
1894
`+
class Options(TypedDict, total=False):
`
``
1895
`+
log_level: int
`
``
1896
`+
log_path: str
`
``
1897
+
1886
1898
`class HasForeignBaseClass(mod_generics_cache.A):
`
1887
1899
`some_xrepr: 'XRepr'
`
1888
1900
`other_a: 'mod_generics_cache.A'
`
`@@ -2658,6 +2670,97 @@ def test_pickle(self):
`
2658
2670
`self.assertEqual(jane2, jane)
`
2659
2671
``
2660
2672
``
``
2673
`+
class TypedDictTests(BaseTestCase):
`
``
2674
`+
def test_basics_functional_syntax(self):
`
``
2675
`+
Emp = TypedDict('Emp', {'name': str, 'id': int})
`
``
2676
`+
self.assertIsSubclass(Emp, dict)
`
``
2677
`+
self.assertIsSubclass(Emp, typing.MutableMapping)
`
``
2678
`+
self.assertNotIsSubclass(Emp, collections.abc.Sequence)
`
``
2679
`+
jim = Emp(name='Jim', id=1)
`
``
2680
`+
self.assertIs(type(jim), dict)
`
``
2681
`+
self.assertEqual(jim['name'], 'Jim')
`
``
2682
`+
self.assertEqual(jim['id'], 1)
`
``
2683
`+
self.assertEqual(Emp.name, 'Emp')
`
``
2684
`+
self.assertEqual(Emp.module, name)
`
``
2685
`+
self.assertEqual(Emp.bases, (dict,))
`
``
2686
`+
self.assertEqual(Emp.annotations, {'name': str, 'id': int})
`
``
2687
`+
self.assertEqual(Emp.total, True)
`
``
2688
+
``
2689
`+
def test_basics_keywords_syntax(self):
`
``
2690
`+
Emp = TypedDict('Emp', name=str, id=int)
`
``
2691
`+
self.assertIsSubclass(Emp, dict)
`
``
2692
`+
self.assertIsSubclass(Emp, typing.MutableMapping)
`
``
2693
`+
self.assertNotIsSubclass(Emp, collections.abc.Sequence)
`
``
2694
`+
jim = Emp(name='Jim', id=1)
`
``
2695
`+
self.assertIs(type(jim), dict)
`
``
2696
`+
self.assertEqual(jim['name'], 'Jim')
`
``
2697
`+
self.assertEqual(jim['id'], 1)
`
``
2698
`+
self.assertEqual(Emp.name, 'Emp')
`
``
2699
`+
self.assertEqual(Emp.module, name)
`
``
2700
`+
self.assertEqual(Emp.bases, (dict,))
`
``
2701
`+
self.assertEqual(Emp.annotations, {'name': str, 'id': int})
`
``
2702
`+
self.assertEqual(Emp.total, True)
`
``
2703
+
``
2704
`+
def test_typeddict_errors(self):
`
``
2705
`+
Emp = TypedDict('Emp', {'name': str, 'id': int})
`
``
2706
`+
self.assertEqual(TypedDict.module, 'typing')
`
``
2707
`+
jim = Emp(name='Jim', id=1)
`
``
2708
`+
with self.assertRaises(TypeError):
`
``
2709
`+
isinstance({}, Emp)
`
``
2710
`+
with self.assertRaises(TypeError):
`
``
2711
`+
isinstance(jim, Emp)
`
``
2712
`+
with self.assertRaises(TypeError):
`
``
2713
`+
issubclass(dict, Emp)
`
``
2714
`+
with self.assertRaises(TypeError):
`
``
2715
`+
TypedDict('Hi', x=1)
`
``
2716
`+
with self.assertRaises(TypeError):
`
``
2717
`+
TypedDict('Hi', [('x', int), ('y', 1)])
`
``
2718
`+
with self.assertRaises(TypeError):
`
``
2719
`+
TypedDict('Hi', [('x', int)], y=int)
`
``
2720
+
``
2721
`+
def test_py36_class_syntax_usage(self):
`
``
2722
`+
self.assertEqual(LabelPoint2D.name, 'LabelPoint2D')
`
``
2723
`+
self.assertEqual(LabelPoint2D.module, name)
`
``
2724
`+
self.assertEqual(LabelPoint2D.annotations, {'x': int, 'y': int, 'label': str})
`
``
2725
`+
self.assertEqual(LabelPoint2D.bases, (dict,))
`
``
2726
`+
self.assertEqual(LabelPoint2D.total, True)
`
``
2727
`+
self.assertNotIsSubclass(LabelPoint2D, typing.Sequence)
`
``
2728
`+
not_origin = Point2D(x=0, y=1)
`
``
2729
`+
self.assertEqual(not_origin['x'], 0)
`
``
2730
`+
self.assertEqual(not_origin['y'], 1)
`
``
2731
`+
other = LabelPoint2D(x=0, y=1, label='hi')
`
``
2732
`+
self.assertEqual(other['label'], 'hi')
`
``
2733
+
``
2734
`+
def test_pickle(self):
`
``
2735
`+
global EmpD # pickle wants to reference the class by name
`
``
2736
`+
EmpD = TypedDict('EmpD', name=str, id=int)
`
``
2737
`+
jane = EmpD({'name': 'jane', 'id': 37})
`
``
2738
`+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
`
``
2739
`+
z = pickle.dumps(jane, proto)
`
``
2740
`+
jane2 = pickle.loads(z)
`
``
2741
`+
self.assertEqual(jane2, jane)
`
``
2742
`+
self.assertEqual(jane2, {'name': 'jane', 'id': 37})
`
``
2743
`+
ZZ = pickle.dumps(EmpD, proto)
`
``
2744
`+
EmpDnew = pickle.loads(ZZ)
`
``
2745
`+
self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane)
`
``
2746
+
``
2747
`+
def test_optional(self):
`
``
2748
`+
EmpD = TypedDict('EmpD', name=str, id=int)
`
``
2749
+
``
2750
`+
self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD])
`
``
2751
`+
self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD])
`
``
2752
+
``
2753
`+
def test_total(self):
`
``
2754
`+
D = TypedDict('D', {'x': int}, total=False)
`
``
2755
`+
self.assertEqual(D(), {})
`
``
2756
`+
self.assertEqual(D(x=1), {'x': 1})
`
``
2757
`+
self.assertEqual(D.total, False)
`
``
2758
+
``
2759
`+
self.assertEqual(Options(), {})
`
``
2760
`+
self.assertEqual(Options(log_level=2), {'log_level': 2})
`
``
2761
`+
self.assertEqual(Options.total, False)
`
``
2762
+
``
2763
+
2661
2764
`class IOTests(BaseTestCase):
`
2662
2765
``
2663
2766
`def test_io(self):
`