Karthikeyan Singaravelan <[email protected]> added the comment:
I think the original issue with patch.object reported by Carl is different from
the one reported by David for autospec. Analyzed the report by David and When
we call autospec on a class with instance=True then the spec is modeled on the
signature of __call__ instead of __init__ where __call__ has the signature of
(self, x) and self is discarded with _eat_self passed as True. But mock also
stores _spec_signature that is not aware of skipping self and has the signature
as (self, x) and is used for checking signature in mock.assert_called_with.
When instance=True then kwargs['_spec_as_instance']=True so does it makes sense
to set kwargs['_eat_self'] = True at [0] ? I applied the change and there are
no test failures so this deserves a test.
This makes __call__ to have a different signature when it's called from mock
and when the call is checked with assert_called_with_once. But it's not the
case for methods of the class where self is skipped both for mock and
_spec_signature. Since __signature__ is set for mock with my PR this makes it
little easy to debug. Can this be dealt as a separate issue?
I would also love to see if the assertion message can be improved since
expected_call and actual_call are printed with repr version of the call object
in spite of the signature failure. This has caused confusion here and in other
places like issue26752 and issue25312.
Sample program to demonstrate difference in signatures :
import inspect
from unittest import mock
class Foo:
def __call__(self, x):
return x
def bar(self, x):
pass
m = mock.create_autospec(Foo, instance=True)
m(7)
m.bar(7)
print(inspect.signature(m))
print(m._spec_signature)
print(inspect.signature(m.bar))
print(m.bar._spec_signature)
m.bar.assert_called_once_with(7) # 7 passed as self with no value for x
m.assert_called_once_with(7) # Fails due to self
(x)
(self, x) # self is not skipped in _spec_signature
(x)
(x)
TypeError: missing a required argument: 'x'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "../backups/bpo27715_1.py", line 20, in <module>
m.assert_called_once_with(7)
File
"/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py",
line 840, in assert_called_once_with
return self.assert_called_with(*args, **kwargs)
File
"/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/mock.py",
line 827, in assert_called_with
raise AssertionError(_error_message()) from cause
AssertionError: Expected call: mock(7)
Actual call: mock(7)
[0]
https://github.com/python/cpython/blob/f8e9bd568adf85c1e4aea1dda542a96b027797e2/Lib/unittest/mock.py#L2199
----------
nosy: +cjw296, mariocj89
versions: -Python 3.6
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue27715>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com