patch does not correctly restore state on objects without __dict__
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 77.2k
- Forks
- 35.9k
- PR merge metrics
- PR metrics pending
Description
Bug report
Bug description:
from unittest.mock import patch
class Proxy(object):
config = {}
def __getattr__(self, name):
return self.config[name]
def __setattr__(self, name, value):
if name == 'config':
object.__setattr__(self, name, value)
return
self.config[name] = value
def __delattr__(self, name):
self.config[name] = 'DEFAULT'
p = Proxy()
p.a = True
print(p.a)
with patch('__main__.p.a', False):
print(p.a)
print(p.a)
Expected
True
False
True
Actual
True
False
DEFAULT
Note that this is a relatively niche issue, but for example in a config system (i.e. https://github.com/pytorch/pytorch/pull/140779), if you don't want to have a delete work, (i.e. have it set it back to a default value), the code in https://github.com/python/cpython/blob/94a7a4e22fb8f567090514785c69e65298acca42/Lib/unittest/mock.py#L1637 will call delattr, and then not call setattr, because it still has the attr.
Possible fixes:
If delattr throws (maybe NotImplementederror), call setattr instead (this is nice and explicit + removes the hacky workaround I have to do).
If the value after it's been deleted doesn't equal the original value, reassign it? (this might require objects to be comparable, not sure if that is already an issue here).
Either way I wanted to see if there was any interest in fixing this, and if anyone saw a solution that seemed reasonable enough.
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction in the issue and inspect the restoration logic at Lib/unittest/mock.py around line 1637. Compare how patch handles attributes on objects without dict when deletion changes the observed value. Done means the example restores p.a to True while preserving existing behavior for ordinary objects, with regression coverage added in the relevant unittest.mock tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100