Skip to content

Commit d796deb

Browse files
committed
Fixed spy for classmethods and staticmethods in py3
1 parent bb4be32 commit d796deb

File tree

1 file changed

+21
-27
lines changed

1 file changed

+21
-27
lines changed

pytest_mock.py

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
2-
32
import inspect
3+
44
import pytest
55

66

@@ -32,42 +32,36 @@ def stopall(self):
3232
p.stop()
3333
self._patches[:] = []
3434

35-
def spy(self, obj, method_name):
35+
def spy(self, obj, name):
3636
"""
37-
Creates a spy of method. It will run method normally, but it is now possible to use `mock`
38-
call features with it, like call count.
37+
Creates a spy of method. It will run method normally, but it is now
38+
possible to use `mock` call features with it, like call count.
3939
4040
:param object obj: An object.
41-
:param unicode method_name: A method in object.
41+
:param unicode name: A method in object.
4242
:rtype: mock.MagicMock
4343
:return: Spy object.
4444
"""
45-
method = getattr(obj, method_name)
46-
47-
if not inspect.ismethod(method): # staticmethod
48-
can_autospec = False
49-
elif method.__self__ is obj: # classmethod
50-
can_autospec = False
51-
else:
52-
can_autospec = True
53-
54-
if can_autospec:
55-
kwargs = dict(
56-
autospec=True,
57-
)
58-
else:
59-
# Can't use autospec because of https://bugs.python.org/issue23078
60-
kwargs = dict(
61-
new_callable=mock_module.MagicMock,
62-
spec=True,
63-
)
64-
65-
result = self.patch.object(obj, method_name, side_effect=method, **kwargs)
45+
method = getattr(obj, name)
46+
47+
autospec = inspect.ismethod(method) or inspect.isfunction(method)
48+
# Can't use autospec classmethod or staticmethod objects
49+
# see: https://bugs.python.org/issue23078
50+
if inspect.isclass(obj):
51+
# bypass class descriptor:
52+
# http://stackoverflow.com/questions/14187973/python3-check-if-method-is-static
53+
value = obj.__getattribute__(obj, name)
54+
if isinstance(value, (classmethod, staticmethod)):
55+
autospec = False
56+
57+
result = self.patch.object(obj, name, side_effect=method,
58+
autospec=autospec)
6659
return result
6760

6861
def stub(self):
6962
"""
70-
Creates a stub method. It accepts any arguments. Ideal to register to callbacks in tests.
63+
Creates a stub method. It accepts any arguments. Ideal to register to
64+
callbacks in tests.
7165
7266
:rtype: mock.MagicMock
7367
:return: Stub object.

0 commit comments

Comments
 (0)