From 3d40673047bea2c2458c20abe54cdd33a97021fe Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Wed, 2 Sep 2026 11:51:41 +0300 Subject: [PATCH] Honour resetall() arguments for non-callable mocks reset_mock() is defined on NonCallableMock, but resetall() narrowed the kwargs-capable set to (Mock, AsyncMock). NonCallableMagicMock -- what mocker.create_autospec(cls, instance=True) returns -- is not a Mock subclass, so return_value= and side_effect= were silently dropped for it. The guard exists because autospecced functions carry a no-argument reset_mock closure (issue #237); those are plain functions, so they still take the else branch. AsyncMock was redundant: it already subclasses Mock. --- CHANGELOG.rst | 1 + src/pytest_mock/plugin.py | 12 +++++------- tests/test_pytest_mock.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 46d1677..843023c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ Releases Unreleased ---------- +* `#606 `_: ``mocker.resetall(return_value=True, side_effect=True)`` now also applies to non-callable mocks, such as those returned by ``mocker.create_autospec(SomeClass, instance=True)``. Previously both arguments were silently ignored for them. * `#547 `_: Added ``SpyType`` for annotating ``mocker.spy`` results. * Dropped support for EOL Python 3.9. * `#147 `_: Removed handling of ``RuntimeError: stop called on unstarted patcher``, which can no longer occur in the supported Python versions. diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index df63fb4..4ba8757 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -130,12 +130,6 @@ def resetall( :param bool return_value: Reset the return_value of mocks. :param bool side_effect: Reset the side_effect of mocks. """ - supports_reset_mock_with_args: tuple[type[Any], ...] - if hasattr(self, "AsyncMock"): - supports_reset_mock_with_args = (self.Mock, self.AsyncMock) - else: - supports_reset_mock_with_args = (self.Mock,) - for mock_item in self._mock_cache: # See issue #237. if not hasattr(mock_item.mock, "reset_mock"): @@ -145,7 +139,11 @@ def resetall( mock_item.mock.spy_return_list = [] if hasattr(mock_item.mock, "spy_return_iter"): mock_item.mock.spy_return_iter = None - if isinstance(mock_item.mock, supports_reset_mock_with_args): + # ``reset_mock`` is defined on ``NonCallableMock``, which is the base + # of every mock class. Autospecced *functions* are plain functions + # carrying a no-argument ``reset_mock`` closure, so they take the + # ``else`` branch. + if isinstance(mock_item.mock, self.NonCallableMock): mock_item.mock.reset_mock( return_value=return_value, side_effect=side_effect ) diff --git a/tests/test_pytest_mock.py b/tests/test_pytest_mock.py index c497aea..50b6a57 100644 --- a/tests/test_pytest_mock.py +++ b/tests/test_pytest_mock.py @@ -224,6 +224,19 @@ def test_mocker_resetall(mocker: MockerFixture) -> None: assert mocked_object.run.return_value != "mocked" +def test_mocker_resetall_non_callable_mock(mocker: MockerFixture) -> None: + """``resetall`` must honour its arguments for non-callable mocks too (#389).""" + mocked_object = mocker.create_autospec(TestObject, instance=True) + assert not isinstance(mocked_object, mocker.Mock) + mocked_object.run.return_value = "mocked" + mocked_object.run.side_effect = ValueError + + mocker.resetall(return_value=True, side_effect=True) + + assert mocked_object.run.return_value != "mocked" + assert mocked_object.run.side_effect is None + + class TestMockerStub: def test_call(self, mocker: MockerFixture) -> None: stub = mocker.stub()