summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2013-07-15 11:13:08 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2013-07-15 11:13:08 (GMT)
commit24c05bc1542d9637550d5253306016412e5119d3 (patch)
tree12651b54b5479ed65b5b28506098632b7f796464 /Lib
parent6180a2f45321982386200e20bb323eb4261cf1fb (diff)
downloadcpython-24c05bc1542d9637550d5253306016412e5119d3.zip
cpython-24c05bc1542d9637550d5253306016412e5119d3.tar.gz
cpython-24c05bc1542d9637550d5253306016412e5119d3.tar.bz2
Close issue 17482: don't overwrite __wrapped__
Diffstat (limited to 'Lib')
-rw-r--r--Lib/functools.py4
-rw-r--r--Lib/test/test_functools.py14
2 files changed, 14 insertions, 4 deletions
diff --git a/Lib/functools.py b/Lib/functools.py
index 6aa13a2..19f88c7 100644
--- a/Lib/functools.py
+++ b/Lib/functools.py
@@ -55,7 +55,6 @@ def update_wrapper(wrapper,
are updated with the corresponding attribute from the wrapped
function (defaults to functools.WRAPPER_UPDATES)
"""
- wrapper.__wrapped__ = wrapped
for attr in assigned:
try:
value = getattr(wrapped, attr)
@@ -65,6 +64,9 @@ def update_wrapper(wrapper,
setattr(wrapper, attr, value)
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
+ # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
+ # from the wrapped function when updating __dict__
+ wrapper.__wrapped__ = wrapped
# Return the wrapper so this can be used as a decorator via partial()
return wrapper
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 99dccb0..ab76efb 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -224,19 +224,26 @@ class TestUpdateWrapper(unittest.TestCase):
updated=functools.WRAPPER_UPDATES):
# Check attributes were assigned
for name in assigned:
- self.assertTrue(getattr(wrapper, name) is getattr(wrapped, name))
+ self.assertIs(getattr(wrapper, name), getattr(wrapped, name))
# Check attributes were updated
for name in updated:
wrapper_attr = getattr(wrapper, name)
wrapped_attr = getattr(wrapped, name)
for key in wrapped_attr:
- self.assertTrue(wrapped_attr[key] is wrapper_attr[key])
+ if name == "__dict__" and key == "__wrapped__":
+ # __wrapped__ is overwritten by the update code
+ continue
+ self.assertIs(wrapped_attr[key], wrapper_attr[key])
+ # Check __wrapped__
+ self.assertIs(wrapper.__wrapped__, wrapped)
+
def _default_update(self):
def f(a:'This is a new annotation'):
"""This is a test"""
pass
f.attr = 'This is also a test'
+ f.__wrapped__ = "This is a bald faced lie"
def wrapper(b:'This is the prior annotation'):
pass
functools.update_wrapper(wrapper, f)
@@ -331,14 +338,15 @@ class TestWraps(TestUpdateWrapper):
"""This is a test"""
pass
f.attr = 'This is also a test'
+ f.__wrapped__ = "This is still a bald faced lie"
@functools.wraps(f)
def wrapper():
pass
- self.check_wrapper(wrapper, f)
return wrapper, f
def test_default_update(self):
wrapper, f = self._default_update()
+ self.check_wrapper(wrapper, f)
self.assertEqual(wrapper.__name__, 'f')
self.assertEqual(wrapper.__qualname__, f.__qualname__)
self.assertEqual(wrapper.attr, 'This is also a test')