diff options
author | Raymond Hettinger <python@rcn.com> | 2010-08-08 00:56:52 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2010-08-08 00:56:52 (GMT) |
commit | c6d80c1bef62c996d1a7d3b544a108fef17fbf65 (patch) | |
tree | 69bfd207498ceb86fcec365e074c50c0f752e5fc | |
parent | f56c9cd30d7b7113e32a2562f66cc78a3ec441a3 (diff) | |
download | cpython-c6d80c1bef62c996d1a7d3b544a108fef17fbf65.zip cpython-c6d80c1bef62c996d1a7d3b544a108fef17fbf65.tar.gz cpython-c6d80c1bef62c996d1a7d3b544a108fef17fbf65.tar.bz2 |
Issue 8814: functools.wraps() did not copy __annotations__.
-rw-r--r-- | Doc/library/functools.rst | 6 | ||||
-rw-r--r-- | Lib/functools.py | 5 | ||||
-rw-r--r-- | Lib/test/test_functools.py | 8 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/NEWS | 4 |
5 files changed, 17 insertions, 7 deletions
diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 94be636..570f4d2 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -66,9 +66,9 @@ The :mod:`functools` module defines the following functions: attributes of the wrapper function are updated with the corresponding attributes from the original function. The default values for these arguments are the module level constants *WRAPPER_ASSIGNMENTS* (which assigns to the wrapper - function's *__name__*, *__module__* and *__doc__*, the documentation string) and - *WRAPPER_UPDATES* (which updates the wrapper function's *__dict__*, i.e. the - instance dictionary). + function's *__name__*, *__module__*, *__annotations__* and *__doc__*, the + documentation string) and *WRAPPER_UPDATES* (which updates the wrapper + function's *__dict__*, i.e. the instance dictionary). The main intended use for this function is in :term:`decorator` functions which wrap the decorated function and return the wrapper. If the wrapper function is diff --git a/Lib/functools.py b/Lib/functools.py index a54f030..103dd42 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -12,7 +12,7 @@ from _functools import partial, reduce # 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, @@ -30,7 +30,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 eff31e0..7b79f28 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -181,17 +181,19 @@ class TestUpdateWrapper(unittest.TestCase): self.assertTrue(wrapped_attr[key] is wrapper_attr[key]) def test_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) self.check_wrapper(wrapper, f) self.assertEqual(wrapper.__name__, 'f') self.assertEqual(wrapper.__doc__, 'This is a test') self.assertEqual(wrapper.attr, 'This is also a test') + self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation') + self.assertNotIn('b', wrapper.__annotations__) def test_no_update(self): def f(): @@ -204,6 +206,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): @@ -230,6 +233,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): @@ -144,6 +144,7 @@ Steve Clift Nick Coghlan Josh Cogliati Dave Cole +Terrence Cole Benjamin Collar Jeffery Collins Paul Colomiets @@ -12,6 +12,10 @@ What's New in Python 3.1.3? Core and Builtins ----------------- +- 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. + - Issue #83755: Implicit set-to-frozenset conversion was not thread-safe. - Issue #9416: Fix some issues with complex formatting where the |