Skip to content

patch does not correctly restore state on objects without __dict__ #126886

@c00w

Description

@c00w

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. pytorch/pytorch#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

if not self.create and (not hasattr(self.target, self.attribute) or
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

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions