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):

`