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.
This commit is contained in:
parent
5626eec0c2
commit
560f7647ce
|
@ -165,9 +165,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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ Steve Clift
|
|||
Nick Coghlan
|
||||
Josh Cogliati
|
||||
Dave Cole
|
||||
Terrence Cole
|
||||
Benjamin Collar
|
||||
Jeffery Collins
|
||||
Robert Collins
|
||||
|
|
|
@ -37,6 +37,10 @@ Extensions
|
|||
Library
|
||||
-------
|
||||
|
||||
- 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 #2944: asyncore doesn't handle connection refused correctly.
|
||||
|
||||
- Issue #4184: Private attributes on smtpd.SMTPChannel made public and
|
||||
|
|
Loading…
Reference in New Issue