import unittest class TypeAnnotationTests(unittest.TestCase): def test_lazy_create_annotations(self): # type objects lazy create their __annotations__ dict on demand. # the annotations dict is stored in type.__dict__. # a freshly created type shouldn't have an annotations dict yet. foo = type("Foo", (), {}) for i in range(3): self.assertFalse("__annotations__" in foo.__dict__) d = foo.__annotations__ self.assertTrue("__annotations__" in foo.__dict__) self.assertEqual(foo.__annotations__, d) self.assertEqual(foo.__dict__['__annotations__'], d) del foo.__annotations__ def test_setting_annotations(self): foo = type("Foo", (), {}) for i in range(3): self.assertFalse("__annotations__" in foo.__dict__) d = {'a': int} foo.__annotations__ = d self.assertTrue("__annotations__" in foo.__dict__) self.assertEqual(foo.__annotations__, d) self.assertEqual(foo.__dict__['__annotations__'], d) del foo.__annotations__ def test_annotations_getset_raises(self): # builtin types don't have __annotations__ (yet!) with self.assertRaises(AttributeError): print(float.__annotations__) with self.assertRaises(TypeError): float.__annotations__ = {} with self.assertRaises(TypeError): del float.__annotations__ # double delete foo = type("Foo", (), {}) foo.__annotations__ = {} del foo.__annotations__ with self.assertRaises(AttributeError): del foo.__annotations__ def test_annotations_are_created_correctly(self): class C: a:int=3 b:str=4 self.assertTrue("__annotations__" in C.__dict__) del C.__annotations__ self.assertFalse("__annotations__" in C.__dict__) def test_descriptor_still_works(self): class C: def __init__(self, name=None, bases=None, d=None): self.my_annotations = None @property def __annotations__(self): if not hasattr(self, 'my_annotations'): self.my_annotations = {} if not isinstance(self.my_annotations, dict): self.my_annotations = {} return self.my_annotations @__annotations__.setter def __annotations__(self, value): if not isinstance(value, dict): raise ValueError("can only set __annotations__ to a dict") self.my_annotations = value @__annotations__.deleter def __annotations__(self): if getattr(self, 'my_annotations', False) is None: raise AttributeError('__annotations__') self.my_annotations = None c = C() self.assertEqual(c.__annotations__, {}) d = {'a':'int'} c.__annotations__ = d self.assertEqual(c.__annotations__, d) with self.assertRaises(ValueError): c.__annotations__ = 123 del c.__annotations__ with self.assertRaises(AttributeError): del c.__annotations__ self.assertEqual(c.__annotations__, {}) class D(metaclass=C): pass self.assertEqual(D.__annotations__, {}) d = {'a':'int'} D.__annotations__ = d self.assertEqual(D.__annotations__, d) with self.assertRaises(ValueError): D.__annotations__ = 123 del D.__annotations__ with self.assertRaises(AttributeError): del D.__annotations__ self.assertEqual(D.__annotations__, {})