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

Reply via email to