Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 560f764

Browse files
committed
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.
1 parent 5626eec commit 560f764

5 files changed

Lines changed: 17 additions & 7 deletions

File tree

Doc/library/functools.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ The :mod:`functools` module defines the following functions:
165165
attributes of the wrapper function are updated with the corresponding attributes
166166
from the original function. The default values for these arguments are the
167167
module level constants *WRAPPER_ASSIGNMENTS* (which assigns to the wrapper
168-
function's *__name__*, *__module__* and *__doc__*, the documentation string) and
169-
*WRAPPER_UPDATES* (which updates the wrapper function's *__dict__*, i.e. the
170-
instance dictionary).
168+
function's *__name__*, *__module__*, *__annotations__* and *__doc__*, the
169+
documentation string) and *WRAPPER_UPDATES* (which updates the wrapper
170+
function's *__dict__*, i.e. the instance dictionary).
171171

172172
The main intended use for this function is in :term:`decorator` functions which
173173
wrap the decorated function and return the wrapper. If the wrapper function is

Lib/functools.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# update_wrapper() and wraps() are tools to help write
2020
# wrapper functions that can handle naive introspection
2121

22-
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
22+
WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__', '__annotations__')
2323
WRAPPER_UPDATES = ('__dict__',)
2424
def update_wrapper(wrapper,
2525
wrapped,
@@ -37,7 +37,8 @@ def update_wrapper(wrapper,
3737
function (defaults to functools.WRAPPER_UPDATES)
3838
"""
3939
for attr in assigned:
40-
setattr(wrapper, attr, getattr(wrapped, attr))
40+
if hasattr(wrapped, attr):
41+
setattr(wrapper, attr, getattr(wrapped, attr))
4142
for attr in updated:
4243
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
4344
# Return the wrapper so this can be used as a decorator via partial()

Lib/test/test_functools.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,11 @@ def check_wrapper(self, wrapper, wrapped,
182182
self.assertTrue(wrapped_attr[key] is wrapper_attr[key])
183183

184184
def _default_update(self):
185-
def f():
185+
def f(a:'This is a new annotation'):
186186
"""This is a test"""
187187
pass
188188
f.attr = 'This is also a test'
189-
def wrapper():
189+
def wrapper(b:'This is the prior annotation'):
190190
pass
191191
functools.update_wrapper(wrapper, f)
192192
return wrapper, f
@@ -196,6 +196,8 @@ def test_default_update(self):
196196
self.check_wrapper(wrapper, f)
197197
self.assertEqual(wrapper.__name__, 'f')
198198
self.assertEqual(wrapper.attr, 'This is also a test')
199+
self.assertEqual(wrapper.__annotations__['a'], 'This is a new annotation')
200+
self.assertNotIn('b', wrapper.__annotations__)
199201

200202
@unittest.skipIf(sys.flags.optimize >= 2,
201203
"Docstrings are omitted with -O2 and above")
@@ -214,6 +216,7 @@ def wrapper():
214216
self.check_wrapper(wrapper, f, (), ())
215217
self.assertEqual(wrapper.__name__, 'wrapper')
216218
self.assertEqual(wrapper.__doc__, None)
219+
self.assertEqual(wrapper.__annotations__, {})
217220
self.assertFalse(hasattr(wrapper, 'attr'))
218221

219222
def test_selective_update(self):
@@ -240,6 +243,7 @@ def wrapper():
240243
functools.update_wrapper(wrapper, max)
241244
self.assertEqual(wrapper.__name__, 'max')
242245
self.assertTrue(wrapper.__doc__.startswith('max('))
246+
self.assertEqual(wrapper.__annotations__, {})
243247

244248
class TestWraps(TestUpdateWrapper):
245249

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ Steve Clift
154154
Nick Coghlan
155155
Josh Cogliati
156156
Dave Cole
157+
Terrence Cole
157158
Benjamin Collar
158159
Jeffery Collins
159160
Robert Collins

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Extensions
3737
Library
3838
-------
3939

40+
- Issue #8814: function annotations (the ``__annotations__`` attribute)
41+
are now included in the set of attributes copied by default by
42+
functools.wraps and functools.update_wrapper. Patch by Terrence Cole.
43+
4044
- Issue #2944: asyncore doesn't handle connection refused correctly.
4145

4246
- Issue #4184: Private attributes on smtpd.SMTPChannel made public and

0 commit comments

Comments
 (0)