[issue35226] mock.call equality surprisingly broken

Karthikeyan Singaravelan report at bugs.python.org
Tue Nov 13 04:53:22 EST 2018


Karthikeyan Singaravelan <tir.karthi at gmail.com> added the comment:

I think this is due to the fact that when an attribute of a call object is accessed a new call object is returned with the parent as self.parent [0] but the original information regarding the parent is lost during representation and no check for self.parent equality while the call objects are compared [1]

./python.exe
Python 3.8.0a0 (heads/master:0dc1e45dfd, Nov 13 2018, 11:19:49)
[Clang 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import call
>>> call(x=2).foo
call().foo
>>> call(x=1).foo
call().foo
>>> # Comparison returns true since it's similar to call().foo == call().foo though parents are set
>>> call(x=1).foo == call(x=2).foo
True
>>> call(x=1).foo.parent
call(x=1)
>>> call(x=2).foo.parent
call(x=2)
>>> call(x=2).foo(x=2).bar
call().foo().bar
>>> call(x=4).foo(x=3).bar
call().foo().bar
>>> # Comparison returns true since it's similar to call().foo().bar == call().foo().bar
>>> call(x=2).foo(x=2).bar == call(x=4).foo(x=3).bar 
True
>>> call(x=4).foo(x=3).bar.parent
call().foo(x=3)

Maybe we can add a check for parent to be equal if present? 

diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index a9c82dcb5d..a7565d5f60 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -2054,6 +2054,10 @@ class _Call(tuple):
         else:
             self_name, self_args, self_kwargs = self

+        if (getattr(self, 'parent', None) and getattr(other, 'parent', None)
+            and self.parent != other.parent):
+            return False
+
         other_name = ''
         if len_other == 0:
             other_args, other_kwargs = (), {}

With patch the checks return False and there is no test suite failure but I am not sure if I need to put this inside a while loop to check for nested parents and there maybe other cases that my code doesn't handle.

➜  cpython git:(master) ✗ ./python.exe -c 'from unittest.mock import call; print(call(x=2).foo.bar == call(x=1).foo.bar)'
False
➜  cpython git:(master) ✗ ./python.exe -c 'from unittest.mock import call; print(call(x=2).foo == call(x=1).foo)'
False


[0] https://github.com/python/cpython/blob/0d12672b30b8c6c992bef7564581117ae83e11ad/Lib/unittest/mock.py#L2109
[1] https://github.com/python/cpython/blob/0d12672b30b8c6c992bef7564581117ae83e11ad/Lib/unittest/mock.py#L2043

----------
nosy: +xtreak

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue35226>
_______________________________________


More information about the Python-bugs-list mailing list