classification
Title: unittest.mock does not wrap dunder methods (__getitem__ etc)
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Darragh Bailey, anthonypjshaw, cjw296, josephgordon, lisroach, mariocj89, michael.foord, pconnell, r.david.murray, rbcollins, xtreak
Priority: normal Keywords: patch

Created on 2015-11-10 17:02 by Darragh Bailey, last changed 2019-10-28 20:48 by pconnell.

Files
File name Uploaded Description Edit
test-mock-wraps-dict.py Darragh Bailey, 2015-11-10 17:02
Pull Requests
URL Status Linked Edit
PR 16029 open xtreak, 2019-09-12 11:23
Messages (8)
msg254453 - (view) Author: Darragh Bailey (Darragh Bailey) Date: 2015-11-10 17:02
Both unittest.mock and the backported release for earlier pythons don't appear to support mocking of dictionary objects.

Specifically I'm expecting that any of the methods used to test for membership, or get items from a mock object wrapping a dictionary should succeed. However it appears that MagicMock doesn't appear to support this.

Attached file shows an attempt to use different methods with a wrapped dictionary object where only the '.get()' method appears to work as expected.
msg254466 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-11-10 23:12
Looking at the source, it's not clear that wraps is supported for __ methods, despite what the documentation implies.  That is, MagicProxy doesn't seem to look at the wraps information.  I suspect it is doable, but it may be an enhancement request rather than a bug fix, I'm not sure.
msg261835 - (view) Author: Robert Collins (rbcollins) * (Python committer) Date: 2016-03-15 23:11
I think this is a valid mock bug; it likely needs some thoughtful exhaustive testing, and obviously support added for it.
msg341615 - (view) Author: anthony shaw (anthonypjshaw) * (Python triager) Date: 2019-05-06 19:29
The assertions in the attached test still fail on master (3.8a3), so this still applies. 

Michael, are you able to look at this, the code hasn't changed since the original PEP417 implementation, which doesn't specify if this behaviour should be supported.

The documentation does not specify that this is supported also, so i suspect this is an enhancement request.

        elif result is None:
            wraps = None
            if self._mock_wraps is not None:
                # XXXX should we get the attribute without triggering code
                # execution?
                wraps = getattr(self._mock_wraps, name)

            result = self._get_child_mock(
                parent=self, name=name, wraps=wraps, _new_name=name,
                _new_parent=self
            )
msg351469 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-09-09 14:03
This seems to a reasonable change to me since dict.get returns the value then making a contains check dict.__contains__ should return True instead of the fixed return value of False. Below is a patch where the mock_wraps attribute is set with the relevant method that would make sure in the report dict.get would used.


diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 298b41e0d7..077d22d08e 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -1935,6 +1935,12 @@ _side_effect_methods = {


 def _set_return_value(mock, method, name):
+    # If _mock_wraps is present then attach it so that it's 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
msg351824 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-09-11 11:15
Michael, any thoughts on this? This more feels like an enhancement to me and I have marked it as 3.9 since I am not sure someone might be depending on the behavior where they have used wraps but still expect default values for magicmethods as they do now.
msg352124 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2019-09-12 11:28
As discussed with Karthik, I think this is a nice feature enhancement for the wraps functionality and worth fixing. It has the great advantage that the fix is nice and isolated and simple.
msg352125 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2019-09-12 11:29
The previous behaviour was unspecified and clearly due to missing functionality, so the advantages of fixing it outweigh any potential compatibility issues. But I'd see it as a feature enhancement for 3.9.
History
Date User Action Args
2019-10-28 20:48:53pconnellsetnosy: + pconnell
2019-09-12 11:29:41michael.foordsetmessages: + msg352125
2019-09-12 11:28:18michael.foordsetmessages: + msg352124
2019-09-12 11:23:57xtreaksetkeywords: + patch
stage: test needed -> patch review
pull_requests: + pull_request15652
2019-09-11 11:15:38xtreaksetversions: + Python 3.9, - Python 3.5
nosy: + lisroach

messages: + msg351824

components: + Library (Lib)
2019-09-09 14:03:32xtreaksetnosy: + cjw296, mariocj89
messages: + msg351469
2019-05-06 19:29:13anthonypjshawsetnosy: + anthonypjshaw
messages: + msg341615
2018-09-22 19:15:12xtreaksetnosy: + xtreak
2016-03-15 23:11:30rbcollinssettitle: unittest.mock does not wrap dict objects correctly -> unittest.mock does not wrap dunder methods (__getitem__ etc)
messages: + msg261835
stage: test needed
2015-12-22 08:31:35josephgordonsetnosy: + josephgordon
2015-11-10 23:12:01r.david.murraysetnosy: + r.david.murray, michael.foord, rbcollins
messages: + msg254466
2015-11-10 17:02:38Darragh Baileycreate