Skip to content

Honour resetall() arguments for non-callable mocks - #606

Open
dylanpulver wants to merge 1 commit into
pytest-dev:mainfrom
dylanpulver:fix/resetall-non-callable-mocks
Open

Honour resetall() arguments for non-callable mocks#606
dylanpulver wants to merge 1 commit into
pytest-dev:mainfrom
dylanpulver:fix/resetall-non-callable-mocks

Conversation

@dylanpulver

Copy link
Copy Markdown

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 it took the else branch and return_value= / side_effect= were silently dropped:

m = mocker.create_autospec(TestObject, instance=True)
m.run.return_value = "mocked"
mocker.resetall(return_value=True, side_effect=True)
m.run.return_value   # still "mocked"

Calling m.reset_mock(return_value=True, side_effect=True) directly does reset it, and the callable variant create_autospec(cls) already works — so the two disagree today.

The guard itself is load-bearing and I kept it. Autospecced functions carry a no-argument reset_mock closure (#237), and those are plain functions, not NonCallableMock instances, so they still take the else branch. Removing the isinstance check altogether re-breaks test_spy_reset with the original TypeError — I checked. AsyncMock in the old tuple was redundant: it already subclasses Mock.

Why nothing caught it: #390 added create_autospec results to the cache in 2023, which is how non-callable mocks started reaching this loop; the type guard is from #241 (2021) and was not revisited. The test #390 added uses create_autospec(TestObject) without instance=True — the one variant that takes the working branch.

Ran on Python 3.12: pytest tests/ gives 87 passed here vs 86 on main, same venv and command. Four tests fail identically on both (test_detailed_introspection*, test_assert_called_*_with_introspection) — assertion-output differences under pytest 9.1.1, not related to this change. ruff 0.16.5 check + format, mypy 2.3.1 and rst-lint are clean at the versions .pre-commit-config.yaml pins.

How I found it: enumerating the public mocker.* keyword arguments and checking where each is actually honoured. These two are honoured on one branch only.

AI assistance: this change and its test were drafted with Claude Opus 5 (claude-opus-5). The commands and numbers above were run locally.

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 pytest-dev#237); those are plain functions, so they still
take the else branch. AsyncMock was redundant: it already subclasses Mock.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant