diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2010-08-04 18:28:02 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2010-08-04 18:28:02 (GMT) |
commit | 560f7647ce5991140e215a7ac775130798c92dc8 (patch) | |
tree | 7b19296ddf3d8a0d111766226cff9367f77bd619 /Lib | |
parent | 5626eec0c2f62999967eff0ab6aa8ad329e8571b (diff) | |
download | cpython-560f7647ce5991140e215a7ac775130798c92dc8.zip cpython-560f7647ce5991140e215a7ac775130798c92dc8.tar.gz cpython-560f7647ce5991140e215a7ac775130798c92dc8.tar.bz2 |
Issue #8814: function annotations (the `__annotations__` attribute)
are now included in the set of attributes copied by default by
functools.wraps and functools.update_wrapper. Patch by Terrence Cole.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/functools.py | 5 | ||||
-rw-r--r-- | Lib/test/test_functools.py | 8 |
2 files changed, 9 insertions, 4 deletions
diff --git a/Lib/functools.py b/Lib/functools.py index 863706d..e244070 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -19,7 +19,7 @@ from operator import itemgetter # update_wrapper() and wraps() are tools to help write # wrapper functions that can handle naive introspection -WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__') +WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__', '__annotations__') WRAPPER_UPDATES = ('__dict__',) def update_wrapper(wrapper, wrapped, @@ -37,7 +37,8 @@ def update_wrapper(wrapper, function (defaults to functools.WRAPPER_UPDATES) """ for attr in assigned: - setattr(wrapper, attr, getattr(wrapped, attr)) + if hasattr(wrapped, attr): + setattr(wrapper, attr, getattr(wrapped, attr)) for attr in updated: getattr(wrapper, attr).update(getattr(wrapped, attr, {})) # Return the wrapper so this can be used as a decorator via partial() diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index a02d37c..70a8ad6 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -182,11 +182,11 @@ class TestUpdateWrapper(unittest.TestCase): self.assertTrue(wrapped_attr[key] is wrapper_attr[key]) def _default_update(self): - def f(): + def f(a:'This is a new annotation'): """This is a test""" pass f.attr = 'This is also a test' - def wrapper(): + def wrapper(b:'This is the prior annotation'): pass functools.update_wrapper(wrapper, f) return wrapper, f @@ -196,6 +196,8 @@ class TestUpdateWrapper(unittest.TestCase): self.check_wrapper(wrapper, f) self.assertEqual(wrapper.__name__, 'f') self.assertEqual(wrapper.attr, 'This is also a test') + self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation') + self.assertNotIn('b', wrapper.__annotations__) @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") @@ -214,6 +216,7 @@ class TestUpdateWrapper(unittest.TestCase): self.check_wrapper(wrapper, f, (), ()) self.assertEqual(wrapper.__name__, 'wrapper') self.assertEqual(wrapper.__doc__, None) + self.assertEqual(wrapper.__annotations__, {}) self.assertFalse(hasattr(wrapper, 'attr')) def test_selective_update(self): @@ -240,6 +243,7 @@ class TestUpdateWrapper(unittest.TestCase): functools.update_wrapper(wrapper, max) self.assertEqual(wrapper.__name__, 'max') self.assertTrue(wrapper.__doc__.startswith('max(')) + self.assertEqual(wrapper.__annotations__, {}) class TestWraps(TestUpdateWrapper): |