You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.7 KiB
104 lines
3.7 KiB
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__, {})
|