Karthikeyan Singaravelan <[email protected]> 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 <[email protected]>
<https://bugs.python.org/issue17185>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com