]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue 8814: functools.wraps() did not copy __annotations__.
authorRaymond Hettinger <python@rcn.com>
Sun, 8 Aug 2010 00:56:52 +0000 (00:56 +0000)
committerRaymond Hettinger <python@rcn.com>
Sun, 8 Aug 2010 00:56:52 +0000 (00:56 +0000)
Doc/library/functools.rst
Lib/functools.py
Lib/test/test_functools.py
Misc/ACKS
Misc/NEWS

index 94be636ecf9887e45d8faf0a088b6c208153ae6b..570f4d26a5566cca5428ad32b6edad3a0cf44f99 100644 (file)
@@ -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
index a54f03083231379c642f7d6e0bc65e391f07bbd8..103dd426e3fa2691cc03bd3bee66f24e8c9ca7ed 100644 (file)
@@ -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()
index eff31e0420c111b308540b5d4cb638d29abe21f9..7b79f283699ce1c509bb5b9612b75f9b1bd40788 100644 (file)
@@ -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):
 
index 6edb7100973e1d3fbb72405b85280a6d7a0b6c91..67684eb539ed08e6a8e8e41b51bd75bf4c07c326 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -144,6 +144,7 @@ Steve Clift
 Nick Coghlan
 Josh Cogliati
 Dave Cole
+Terrence Cole
 Benjamin Collar
 Jeffery Collins
 Paul Colomiets
index aceb158dbd079cbb530a14e5455ebc2076a36573..997b883ca609cbff8ffc039cc9b513cac6c03ff6 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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