Skip to content

Commit 5563d44

Browse files
habnabitberkerpeksag
authored andcommitted
Fix autospec's behavior on method-bound builtins.
Cython will, in the right circumstances, offer a MethodType instance where im_func is a builtin function. Any instance of MethodType is automatically assumed to be a python-defined function (more specifically, a function that has an inspectable signature), but _set_signature was still conservative in its assumptions. As a result _set_signature would return early with None instead of a mock since the im_func had no inspectable signature. This causes problems deeper inside mock, as _set_signature is assumed to _always_ return a mock, and nothing checked its return value. In similar corner cases, autospec will simply not check the spec of the function, so _set_signature is amended to now return early with the original, not-wrapped mock object.
1 parent ed014f7 commit 5563d44

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

Lib/unittest/mock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def _set_signature(mock, original, instance=False):
155155
skipfirst = isinstance(original, type)
156156
result = _get_signature_object(original, instance, skipfirst)
157157
if result is None:
158-
return
158+
return mock
159159
func, sig = result
160160
def checksig(*args, **kwargs):
161161
sig.bind(*args, **kwargs)

Lib/unittest/test/testmock/testhelpers.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import time
2+
import types
13
import unittest
24

35
from unittest.mock import (
@@ -883,6 +885,19 @@ def test_args_list_contains_call_list(self):
883885
self.assertNotIn([call('fish')], mock.call_args_list)
884886

885887

888+
def test_autospec_on_bound_builtin_function(self):
889+
meth = types.MethodType(time.ctime, time.time())
890+
self.assertIsInstance(meth(), str)
891+
mocked = create_autospec(meth)
892+
893+
# no signature, so no spec to check against
894+
mocked()
895+
mocked.assert_called_once_with()
896+
mocked.reset_mock()
897+
mocked(4, 5, 6)
898+
mocked.assert_called_once_with(4, 5, 6)
899+
900+
886901
def test_call_list_str(self):
887902
mock = Mock()
888903
mock(1, 2)

0 commit comments

Comments
 (0)