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.
This commit is contained in:
larryhastings 2021-04-29 20:09:08 -07:00 committed by GitHub
parent dbe60ee09d
commit 2f2b69855d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 308 additions and 8 deletions

View file

@ -286,6 +286,60 @@ a = A(destroyed)"""
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.