[Python-checkins] bpo-25597: Ensure wraps' return value is used for magic methods in MagicMock (#16029)
Chris Withers
webhook-mailer at python.org
Mon Jan 27 01:48:30 EST 2020
https://github.com/python/cpython/commit/72b1004657e60c900e4cd031b2635b587f4b280e
commit: 72b1004657e60c900e4cd031b2635b587f4b280e
branch: master
author: Karthikeyan Singaravelan <tir.karthi at gmail.com>
committer: Chris Withers <chris at withers.org>
date: 2020-01-27T06:48:15Z
summary:
bpo-25597: Ensure wraps' return value is used for magic methods in MagicMock (#16029)
files:
A Misc/NEWS.d/next/Library/2019-09-12-12-11-05.bpo-25597.mPMzVx.rst
M Lib/unittest/mock.py
M Lib/unittest/test/testmock/testmock.py
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index beed717522bba..1acafc51df1d6 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -2033,6 +2033,12 @@ def __aiter__():
def _set_return_value(mock, method, name):
+ # If _mock_wraps is present then attach it so that wrapped object
+ # is used for return value is used when called.
+ if mock._mock_wraps is not None:
+ method._mock_wraps = getattr(mock._mock_wraps, name)
+ return
+
fixed = _return_values.get(name, DEFAULT)
if fixed is not DEFAULT:
method.return_value = fixed
diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py
index 1329346ae7246..677346725bdd2 100644
--- a/Lib/unittest/test/testmock/testmock.py
+++ b/Lib/unittest/test/testmock/testmock.py
@@ -715,6 +715,53 @@ def method(self): pass
self.assertRaises(StopIteration, mock.method)
+ def test_magic_method_wraps_dict(self):
+ data = {'foo': 'bar'}
+
+ wrapped_dict = MagicMock(wraps=data)
+ self.assertEqual(wrapped_dict.get('foo'), 'bar')
+ self.assertEqual(wrapped_dict['foo'], 'bar')
+ self.assertTrue('foo' in wrapped_dict)
+
+ # return_value is non-sentinel and takes precedence over wrapped value.
+ wrapped_dict.get.return_value = 'return_value'
+ self.assertEqual(wrapped_dict.get('foo'), 'return_value')
+
+ # return_value is sentinel and hence wrapped value is returned.
+ wrapped_dict.get.return_value = sentinel.DEFAULT
+ self.assertEqual(wrapped_dict.get('foo'), 'bar')
+
+ self.assertEqual(wrapped_dict.get('baz'), None)
+ with self.assertRaises(KeyError):
+ wrapped_dict['baz']
+ self.assertFalse('bar' in wrapped_dict)
+
+ data['baz'] = 'spam'
+ self.assertEqual(wrapped_dict.get('baz'), 'spam')
+ self.assertEqual(wrapped_dict['baz'], 'spam')
+ self.assertTrue('baz' in wrapped_dict)
+
+ del data['baz']
+ self.assertEqual(wrapped_dict.get('baz'), None)
+
+
+ def test_magic_method_wraps_class(self):
+
+ class Foo:
+
+ def __getitem__(self, index):
+ return index
+
+ def __custom_method__(self):
+ return "foo"
+
+
+ klass = MagicMock(wraps=Foo)
+ obj = klass()
+ self.assertEqual(obj.__getitem__(2), 2)
+ self.assertEqual(obj.__custom_method__(), "foo")
+
+
def test_exceptional_side_effect(self):
mock = Mock(side_effect=AttributeError)
self.assertRaises(AttributeError, mock)
diff --git a/Misc/NEWS.d/next/Library/2019-09-12-12-11-05.bpo-25597.mPMzVx.rst b/Misc/NEWS.d/next/Library/2019-09-12-12-11-05.bpo-25597.mPMzVx.rst
new file mode 100644
index 0000000000000..5ad8c6d90fa03
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-09-12-12-11-05.bpo-25597.mPMzVx.rst
@@ -0,0 +1,3 @@
+Ensure, if ``wraps`` is supplied to :class:`unittest.mock.MagicMock`, it is used
+to calculate return values for the magic methods instead of using the default
+return values. Patch by Karthikeyan Singaravelan.
More information about the Python-checkins
mailing list