bpo-43901: Lazy-create an empty annotations dict in all unannotated user classes and modules (#25623)
Change class and module objects to lazy-create empty annotations dicts on demand. The annotations dicts are stored in the object's `__dict__` for backwards compatibility.
diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py
index 1d44563..aa5ee49 100644
--- a/Lib/test/test_module.py
+++ b/Lib/test/test_module.py
@@ -286,6 +286,60 @@ class M(ModuleType):
melon = Descr()
self.assertRaises(RuntimeError, getattr, M("mymod"), "melon")
+ def test_lazy_create_annotations(self):
+ # module objects lazy create their __annotations__ dict on demand.
+ # the annotations dict is stored in module.__dict__.
+ # a freshly created module shouldn't have an annotations dict yet.
+ foo = ModuleType("foo")
+ for i in range(4):
+ 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)
+ if i % 2:
+ del foo.__annotations__
+ else:
+ del foo.__dict__['__annotations__']
+
+ def test_setting_annotations(self):
+ foo = ModuleType("foo")
+ for i in range(4):
+ 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)
+ if i % 2:
+ del foo.__annotations__
+ else:
+ del foo.__dict__['__annotations__']
+
+ def test_annotations_getset_raises(self):
+ # module has no dict, all operations fail
+ foo = ModuleType.__new__(ModuleType)
+ with self.assertRaises(TypeError):
+ print(foo.__annotations__)
+ with self.assertRaises(TypeError):
+ foo.__annotations__ = {}
+ with self.assertRaises(TypeError):
+ del foo.__annotations__
+
+ # double delete
+ foo = ModuleType("foo")
+ foo.__annotations__ = {}
+ del foo.__annotations__
+ with self.assertRaises(AttributeError):
+ del foo.__annotations__
+
+ def test_annotations_are_created_correctly(self):
+ from test import ann_module4
+ self.assertTrue("__annotations__" in ann_module4.__dict__)
+ del ann_module4.__annotations__
+ self.assertFalse("__annotations__" in ann_module4.__dict__)
+
+
# frozen and namespace module reprs are tested in importlib.