Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

autospec for spy: remove if else which was in place for python < 3.7 #399

Merged
merged 2 commits into from Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/pytest_mock/plugin.py
Expand Up @@ -137,14 +137,6 @@ def spy(self, obj: object, name: str) -> MockType:
:return: Spy object.
"""
method = getattr(obj, name)
if inspect.isclass(obj) and isinstance(
inspect.getattr_static(obj, name), (classmethod, staticmethod)
):
# Can't use autospec classmethod or staticmethod objects before 3.7
# see: https://bugs.python.org/issue23078
autospec = False
else:
autospec = inspect.ismethod(method) or inspect.isfunction(method)

def wrapper(*args, **kwargs):
spy_obj.spy_return = None
Expand Down Expand Up @@ -175,6 +167,8 @@ async def async_wrapper(*args, **kwargs):
else:
wrapped = functools.update_wrapper(wrapper, method)

autospec = inspect.ismethod(method) or inspect.isfunction(method)

spy_obj = self.patch.object(obj, name, side_effect=wrapped, autospec=autospec)
spy_obj.spy_return = None
spy_obj.spy_exception = None
Expand Down
37 changes: 23 additions & 14 deletions tests/test_pytest_mock.py
Expand Up @@ -314,17 +314,37 @@ def bar(self, arg):
assert str(spy.spy_exception) == f"Error with {v}"


def test_instance_method_spy_autospec_true(mocker: MockerFixture) -> None:
def test_instance_class_static_method_spy_autospec_true(mocker: MockerFixture) -> None:
class Foo:
def bar(self, arg):
return arg * 2

@classmethod
def baz(cls, arg):
return arg * 2

@staticmethod
def qux(arg):
return arg * 2

foo = Foo()
spy = mocker.spy(foo, "bar")
instance_method_spy = mocker.spy(foo, "bar")
with pytest.raises(
AttributeError, match="'function' object has no attribute 'fake_assert_method'"
):
spy.fake_assert_method(arg=5)
instance_method_spy.fake_assert_method(arg=5)

class_method_spy = mocker.spy(Foo, "baz")
with pytest.raises(
AttributeError, match="Mock object has no attribute 'fake_assert_method'"
):
class_method_spy.fake_assert_method(arg=5)

static_method_spy = mocker.spy(Foo, "qux")
with pytest.raises(
AttributeError, match="Mock object has no attribute 'fake_assert_method'"
):
static_method_spy.fake_assert_method(arg=5)


def test_spy_reset(mocker: MockerFixture) -> None:
Expand Down Expand Up @@ -404,17 +424,6 @@ def bar(cls, arg):
assert spy.spy_return == 20


@skip_pypy
def test_class_method_spy_autospec_false(mocker: MockerFixture) -> None:
class Foo:
@classmethod
def bar(cls, arg):
return arg * 2

spy = mocker.spy(Foo, "bar")
spy.fake_assert_method()


@skip_pypy
def test_class_method_subclass_spy(mocker: MockerFixture) -> None:
class Base:
Expand Down