Fix monkeypatch undo when deleting missing attrs/items with raising=False#14271
Fix monkeypatch undo when deleting missing attrs/items with raising=False#14271kartikdp wants to merge 1 commit intopytest-dev:mainfrom
Conversation
| assert A.x == 1 | ||
|
|
||
|
|
||
| def test_delattr_non_existing_with_raising_false() -> None: |
There was a problem hiding this comment.
This test already passes on main, so it is not reflecting/reproducing the issue.
Did you intend to use setattr directly to set x (instead of monkeypatch.setattr).
| assert d == {"hello": "world", "x": 1} | ||
|
|
||
|
|
||
| def test_delitem_non_existing_with_raising_false() -> None: |
There was a problem hiding this comment.
Same comment as the other test.
| @@ -0,0 +1 @@ | |||
| Fixed ``MonkeyPatch.delattr(..., raising=False)`` and ``MonkeyPatch.delitem(..., raising=False)`` so ``undo()`` restores the original missing state. | |||
There was a problem hiding this comment.
Not sure if this is a bug-fix, seems like an improvement: now delattr will always delete the attribute at the end of the test.
This is a behavior change which I don't think can cause problems later, as it depends on the user explicitly calling monkeydelattr.delattr(..., raising=False).
There was a problem hiding this comment.
@The-Compiler you commented on the issue; are you OK with this?
|
I am indeed -1 on this. Here's a trivial example: import types
def test_attribute(monkeypatch):
obj = types.SimpleNamespace()
with monkeypatch.context() as mp:
mp.delattr(obj, "attr", raising=False)
obj.attr = 42
assert hasattr(obj, "attr")It seems natural to me to assume that the object still has the attribute after monkeypatch is done. After all, I never set the attribute through monkeypatch, so I really wouldn't expect monkeypatch to mess with it (as, with |
Summary
Fixes a state-restoration bug in
MonkeyPatchwhen deleting a missing attribute/item withraising=False.Previously:
delattr(..., raising=False)anddelitem(..., raising=False)did not record the missing state.undo()would not reliably restore the original missing state.This change records
NOTSETfor those delete calls, and makesundo()tolerant when the target attribute is already absent.Closes #14094.
Why this matters
Tests that use non-raising deletes expect monkeypatch teardown to fully restore pre-test state. Without this fix, state could leak after tests.
How tested
uv run -m pytest testing/test_monkeypatch.py -k "delattr_non_existing_with_raising_false or delitem_non_existing_with_raising_false or test_delattr or test_delitem"uv run -m pytest testing/test_monkeypatch.pyuv run --with pre-commit pre-commit run --files src/_pytest/monkeypatch.py testing/test_monkeypatch.py changelog/14094.bugfix.rst