-
-
Notifications
You must be signed in to change notification settings - Fork 30.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bpo-43901: Lazy-create an empty annotations dict in all unannotated u…
…ser 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.
- Loading branch information
1 parent
dbe60ee
commit 2f2b698
Showing
9 changed files
with
308 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# This ann_module isn't for test_typing, | ||
# it's for test_module | ||
|
||
a:int=3 | ||
b:str=4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
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 hasattr(self, 'my_annotations') and self.my_annotations == 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__, {}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
Misc/NEWS.d/next/Core and Builtins/2021-04-25-22-50-47.bpo-43901.oKjG5E.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters