Skip to content

Commit 856cbcc

Browse files
habnabitberkerpeksag
authored andcommitted
bpo-29403: Fix mock's broken autospec behavior on method-bound builtin functions (GH-3)
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. Patch by Aaron Gallagher.
1 parent ed014f7 commit 856cbcc

File tree

3 files changed

+18
-1
lines changed

3 files changed

+18
-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 (
@@ -856,6 +858,19 @@ def check_data_descriptor(mock_attr):
856858
check_data_descriptor(foo.desc)
857859

858860

861+
def test_autospec_on_bound_builtin_function(self):
862+
meth = types.MethodType(time.ctime, time.time())
863+
self.assertIsInstance(meth(), str)
864+
mocked = create_autospec(meth)
865+
866+
# no signature, so no spec to check against
867+
mocked()
868+
mocked.assert_called_once_with()
869+
mocked.reset_mock()
870+
mocked(4, 5, 6)
871+
mocked.assert_called_once_with(4, 5, 6)
872+
873+
859874
class TestCallList(unittest.TestCase):
860875

861876
def test_args_list_contains_call_list(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix ``unittest.mock``'s autospec to not fail on method-bound builtin
2+
functions. Patch by Aaron Gallagher.

0 commit comments

Comments
 (0)