summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_typing.py
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2019-05-26 08:39:24 (GMT)
committerGitHub <noreply@github.com>2019-05-26 08:39:24 (GMT)
commit135c6a56e55d2f4f8718b3b9f03ce3c692b15f0f (patch)
treeb585115cb0b9684430a7a3ffe02b2a0df584890a /Lib/test/test_typing.py
parentb891c465bb7d38a597c5c2ad547d7b19194f4dad (diff)
downloadcpython-135c6a56e55d2f4f8718b3b9f03ce3c692b15f0f.zip
cpython-135c6a56e55d2f4f8718b3b9f03ce3c692b15f0f.tar.gz
cpython-135c6a56e55d2f4f8718b3b9f03ce3c692b15f0f.tar.bz2
bpo-37049: PEP 589: Add TypedDict to typing module (GH-13573)
The implementation is straightforward and essentially is just copied from `typing_extensions`.
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r--Lib/test/test_typing.py105
1 files changed, 104 insertions, 1 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index eb61893..088db9c 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -18,7 +18,7 @@ from typing import get_type_hints
from typing import no_type_check, no_type_check_decorator
from typing import Type
from typing import NewType
-from typing import NamedTuple
+from typing import NamedTuple, TypedDict
from typing import IO, TextIO, BinaryIO
from typing import Pattern, Match
import abc
@@ -1883,6 +1883,18 @@ class XRepr(NamedTuple):
def __add__(self, other):
return 0
+Label = TypedDict('Label', [('label', str)])
+
+class Point2D(TypedDict):
+ x: int
+ y: int
+
+class LabelPoint2D(Point2D, Label): ...
+
+class Options(TypedDict, total=False):
+ log_level: int
+ log_path: str
+
class HasForeignBaseClass(mod_generics_cache.A):
some_xrepr: 'XRepr'
other_a: 'mod_generics_cache.A'
@@ -2658,6 +2670,97 @@ class XMethBad2(NamedTuple):
self.assertEqual(jane2, jane)
+class TypedDictTests(BaseTestCase):
+ def test_basics_functional_syntax(self):
+ Emp = TypedDict('Emp', {'name': str, 'id': int})
+ self.assertIsSubclass(Emp, dict)
+ self.assertIsSubclass(Emp, typing.MutableMapping)
+ self.assertNotIsSubclass(Emp, collections.abc.Sequence)
+ jim = Emp(name='Jim', id=1)
+ self.assertIs(type(jim), dict)
+ self.assertEqual(jim['name'], 'Jim')
+ self.assertEqual(jim['id'], 1)
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__module__, __name__)
+ self.assertEqual(Emp.__bases__, (dict,))
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+ self.assertEqual(Emp.__total__, True)
+
+ def test_basics_keywords_syntax(self):
+ Emp = TypedDict('Emp', name=str, id=int)
+ self.assertIsSubclass(Emp, dict)
+ self.assertIsSubclass(Emp, typing.MutableMapping)
+ self.assertNotIsSubclass(Emp, collections.abc.Sequence)
+ jim = Emp(name='Jim', id=1)
+ self.assertIs(type(jim), dict)
+ self.assertEqual(jim['name'], 'Jim')
+ self.assertEqual(jim['id'], 1)
+ self.assertEqual(Emp.__name__, 'Emp')
+ self.assertEqual(Emp.__module__, __name__)
+ self.assertEqual(Emp.__bases__, (dict,))
+ self.assertEqual(Emp.__annotations__, {'name': str, 'id': int})
+ self.assertEqual(Emp.__total__, True)
+
+ def test_typeddict_errors(self):
+ Emp = TypedDict('Emp', {'name': str, 'id': int})
+ self.assertEqual(TypedDict.__module__, 'typing')
+ jim = Emp(name='Jim', id=1)
+ with self.assertRaises(TypeError):
+ isinstance({}, Emp)
+ with self.assertRaises(TypeError):
+ isinstance(jim, Emp)
+ with self.assertRaises(TypeError):
+ issubclass(dict, Emp)
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', x=1)
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', [('x', int), ('y', 1)])
+ with self.assertRaises(TypeError):
+ TypedDict('Hi', [('x', int)], y=int)
+
+ def test_py36_class_syntax_usage(self):
+ self.assertEqual(LabelPoint2D.__name__, 'LabelPoint2D')
+ self.assertEqual(LabelPoint2D.__module__, __name__)
+ self.assertEqual(LabelPoint2D.__annotations__, {'x': int, 'y': int, 'label': str})
+ self.assertEqual(LabelPoint2D.__bases__, (dict,))
+ self.assertEqual(LabelPoint2D.__total__, True)
+ self.assertNotIsSubclass(LabelPoint2D, typing.Sequence)
+ not_origin = Point2D(x=0, y=1)
+ self.assertEqual(not_origin['x'], 0)
+ self.assertEqual(not_origin['y'], 1)
+ other = LabelPoint2D(x=0, y=1, label='hi')
+ self.assertEqual(other['label'], 'hi')
+
+ def test_pickle(self):
+ global EmpD # pickle wants to reference the class by name
+ EmpD = TypedDict('EmpD', name=str, id=int)
+ jane = EmpD({'name': 'jane', 'id': 37})
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ z = pickle.dumps(jane, proto)
+ jane2 = pickle.loads(z)
+ self.assertEqual(jane2, jane)
+ self.assertEqual(jane2, {'name': 'jane', 'id': 37})
+ ZZ = pickle.dumps(EmpD, proto)
+ EmpDnew = pickle.loads(ZZ)
+ self.assertEqual(EmpDnew({'name': 'jane', 'id': 37}), jane)
+
+ def test_optional(self):
+ EmpD = TypedDict('EmpD', name=str, id=int)
+
+ self.assertEqual(typing.Optional[EmpD], typing.Union[None, EmpD])
+ self.assertNotEqual(typing.List[EmpD], typing.Tuple[EmpD])
+
+ def test_total(self):
+ D = TypedDict('D', {'x': int}, total=False)
+ self.assertEqual(D(), {})
+ self.assertEqual(D(x=1), {'x': 1})
+ self.assertEqual(D.__total__, False)
+
+ self.assertEqual(Options(), {})
+ self.assertEqual(Options(log_level=2), {'log_level': 2})
+ self.assertEqual(Options.__total__, False)
+
+
class IOTests(BaseTestCase):
def test_io(self):