Conversation
Tejas5405
force-pushed
the
fix-15099-monkeypatch-custom-setattr
branch
from
October 1, 2026 00:26
bf147d8 to
8932bb1
Compare
…tr__ Since 0c601d5 (pytest-dev#14969), `MonkeyPatch.setattr()` looks the old value up in the instance `__dict__` whenever no data descriptor is in the way, because that is where `setattr()` is assumed to write. A class which defines `__setattr__` can store the value anywhere -- a proxy object's private mapping, for example -- so the old value is recorded as `NOTSET`, `undo()` then tries to delete the attribute instead of restoring it, and the patched value leaks into later tests. Restrict that lookup to types which use `object.__setattr__`. For the others the `getattr()` value stays the right one to restore, since `undo()` writes it back through the same hook. Adds a regression test and a changelog entry. The test also asserts that the proxy object converts a missing attribute to `AttributeError`, which keeps the whole diff covered. Closes pytest-dev#15099
Tejas5405
force-pushed
the
fix-15099-monkeypatch-custom-setattr
branch
from
October 1, 2026 00:43
8932bb1 to
68cb1be
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes #15099
Problem
MonkeyPatch.setattr()records the old value from the instance__dict__whenever no data descriptor is in the way, on the assumption thatsetattr()writes there:A class which defines
__setattr__can store the value anywhere -- a proxy object's private mapping, for example. For those,oldvalis recorded asNOTSET, soundo()callsdelattr()instead of restoring the value. That raisesAttributeErrorduring teardown, and the patched value then leaks into later tests:Fix
Restrict the
__dict__lookup to types which useobject.__setattr__, the only case wheresetattr()is known to write into the instance__dict__. For every other type thegetattr()value stays the right one to restore, becauseundo()writes it back through the same__setattr__hook.This keeps what #14969 added for #10644 intact: those cases use plain classes, so they still take the
__dict__path andundo()still removes the entry it created.Tests
testing/test_monkeypatch.py::test_undo_attribute_stored_outside_instance_dict, a new regression test modelled on the reproducer in the issue. Without the source change it fails withAttributeError; with it,undo()restores the original value.changelog/15099.bugfix.rst, the news fragment.Executed before submitting:
pytest testing/test_monkeypatch.py-> 46 passed, 1 skippedpytest testing/-> 4632 passed, 51 skipped, 15 xfailed, 5 xpassed, 1 failed, 1 error. Both the failure (test_fixture_doctest_skip_has_line_number) and the error (test_cache_makedir) reproduce identically on the unmodified checkout in this environment, so they are unrelated to this change.ruff checkandruff format --checkwith 0.16.9, the version pinned in.pre-commit-config.yaml: clean.mypy: no new diagnostics for the changed files. (The one remaining report, an unusedtype: ignorefurther downtesting/test_monkeypatch.py, is present on the unmodified file too.)AI assistance disclosure
Per the project's AI/LLM-Assisted Contributions Policy: this change -- the reproduction analysis, the fix, the regression test and the changelog entry -- was produced with AI assistance, and I validated it by hand before submitting. I reproduced the failure and confirmed the fix on Python 3.13, verified the new test fails without the source change, and ran the full suite plus ruff and mypy. I am happy to go through any part of the diff.