Skip to content
Merged
Prev Previous commit
Next Next commit
Fix of property setters along with a test for them
  • Loading branch information
Red4Ru committed Nov 10, 2024
commit 862d5a0390f4659054ed7da12d2bf9ae377b78a7
19 changes: 19 additions & 0 deletions Lib/test/test_unittest/testmock/testpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,25 @@ def test_second_start_after_stop(self):
patcher.stop()


def test_property_setters(self):
mock_object = Mock()
mock_bar = mock_object.bar
patcher = patch.object(mock_object, 'bar', 'x')
with patcher:
self.assertEqual(patcher.is_local, False)
self.assertIs(patcher.target, mock_object)
self.assertEqual(patcher.temp_original, mock_bar)
patcher.is_local = True
patcher.target = mock_bar
patcher.temp_original = mock_object
self.assertEqual(patcher.is_local, True)
self.assertIs(patcher.target, mock_bar)
self.assertEqual(patcher.temp_original, mock_object)
# if changes are left intact, they may lead to disruption as shown below (it might be what someone needs though)
self.assertEqual(mock_bar.bar, mock_object)
self.assertEqual(mock_object.bar, 'x')


def test_patchobject_start_stop(self):
original = something
patcher = patch.object(PTModule, 'something', 'foo')
Expand Down
33 changes: 24 additions & 9 deletions Lib/unittest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1482,25 +1482,40 @@ def is_started(self):
def is_local(self):
return self._context.is_local

@is_local.setter
def is_local(self, value):
self._context.is_local = value

@property
def target(self):
return self._context.target

@target.setter
def target(self, value):
self._context.target = value

@property
def temp_original(self):
return self._context.original

@is_local.setter
def is_local(self, value):
self._context = _PatchContext(
exit_stack=self._context.exit_stack,
is_local=value,
original=self._context.original,
target=self._context.target,
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Urgh, I forgot that you cannot change the value of namedtuples. Ok, my suggestion using namedtuples was wrong. To reduce memory footprint, we can use __slots__ in a regular class instead like you had before. That way, we save an from collections import namedtuple as well and simplify the property's setter. WDYT? (again sorry for this bad suggestion).


@target.setter
def target(self, value):
self._context = _PatchContext(
exit_stack=self._context.exit_stack,
is_local=self._context.is_local,
original=self._context.original,
target=value,
)

@temp_original.setter
def temp_original(self, value):
self._context.original = value
self._context = _PatchContext(
exit_stack=self._context.exit_stack,
is_local=self._context.is_local,
original=value,
target=self._context.target,
)

def __enter__(self):
"""Perform the patch."""
Expand Down