Karthikeyan Singaravelan <tir.kar...@gmail.com> added the comment:
Is this being worked on or can I try fixing this? My analysis so far is as below : 1. For functions : inspect.signature looks for attribute __signature__ for functions and while creating the mock for a function since we already have the signature we can set __signature__ attribute during _set_signature. I don't know why __signature__ was set. I downloaded mock from GitHub to look at the actual mocksignature implementation which uses lambda signature: _mock_signature to form a mock function which I hope is done here too with a function constructed and evald with sig.bind used for parameter checking. I am still new to the mocksignature internals so I couldn't understand how mocksignature worked. 2. For class and partial functions _check_signature is called and __call__ is overriden in the mock class to check for signature during initialization acting like a constructor. The actual signature will have self along with rest of the parameters but _get_signature_object checks for __init__ and skips the self thus the constructor signature skips self to return a partial function which makes comparing actual constructor call with self and the partial function signature without self to fail. Attaching a sample patch with tests. Hope I am on the right track and guidance would help. I am changing the version to 3.8 diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index a9c82dcb5d..8cbef0e514 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -103,6 +103,7 @@ def _check_signature(func, mock, skipfirst, instance=False): sig.bind(*args, **kwargs) _copy_func_details(func, checksig) type(mock)._mock_check_sig = checksig + type(mock).__signature__ = sig def _copy_func_details(func, funcopy): @@ -172,11 +173,11 @@ def _set_signature(mock, original, instance=False): return mock(*args, **kwargs)""" % name exec (src, context) funcopy = context[name] - _setup_func(funcopy, mock) + _setup_func(funcopy, mock, sig) return funcopy -def _setup_func(funcopy, mock): +def _setup_func(funcopy, mock, sig): funcopy.mock = mock # can't use isinstance with mocks @@ -224,6 +225,7 @@ def _setup_func(funcopy, mock): funcopy.assert_called = assert_called funcopy.assert_not_called = assert_not_called funcopy.assert_called_once = assert_called_once + funcopy.__signature__ = sig mock._mock_delegate = funcopy Initial set of tests where partial function and class test fails : def test_spec_inspect_signature(self): def foo(a: int, b: int=10, *, c:int) -> int: return a b c mock = create_autospec(foo) assert inspect.getfullargspec(mock) == inspect.getfullargspec(foo) self.assertRaises(TypeError, mock, 1) def test_spec_inspect_signature_partial(self): def foo(a: int, b: int=10, *, c:int) -> int: return a b c import functools partial_object = functools.partial(foo, 1) mock = create_autospec(partial_object) assert inspect.getfullargspec(mock) == inspect.getfullargspec(partial_object) # Fails self.assertRaises(TypeError, partial_object) def test_spec_inspect_signature_class(self): class Bar: def __init__(self, a: int): self.a = a mock = create_autospec(Bar) assert inspect.getfullargspec(mock) == inspect.getfullargspec(Bar) # Fails since mock signature has no self self.assertRaises(TypeError, mock) self._check_someclass_mock(mock) ---------- versions: +Python 3.8 -Python 3.4, Python 3.5 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue17185> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com