Commit a875ea58 authored by Xtreak's avatar Xtreak Committed by Chris Withers

bpo-35512: Resolve string target to patch.dict decorator during function call GH#12000

* Resolve string target to patch.dict during function call

* Add NEWS entry

* Remove unneeded call

* Restore original value for support.target and refactor assertions

* Add extra assertion to verify unpatched dict
parent aeca373b
...@@ -1620,8 +1620,6 @@ class _patch_dict(object): ...@@ -1620,8 +1620,6 @@ class _patch_dict(object):
""" """
def __init__(self, in_dict, values=(), clear=False, **kwargs): def __init__(self, in_dict, values=(), clear=False, **kwargs):
if isinstance(in_dict, str):
in_dict = _importer(in_dict)
self.in_dict = in_dict self.in_dict = in_dict
# support any argument supported by dict(...) constructor # support any argument supported by dict(...) constructor
self.values = dict(values) self.values = dict(values)
...@@ -1662,6 +1660,8 @@ class _patch_dict(object): ...@@ -1662,6 +1660,8 @@ class _patch_dict(object):
def _patch_dict(self): def _patch_dict(self):
values = self.values values = self.values
if isinstance(self.in_dict, str):
self.in_dict = _importer(self.in_dict)
in_dict = self.in_dict in_dict = self.in_dict
clear = self.clear clear = self.clear
......
target = {'foo': 'FOO'}
def is_instance(obj, klass): def is_instance(obj, klass):
"""Version of is_instance that doesn't access __class__""" """Version of is_instance that doesn't access __class__"""
return issubclass(type(obj), klass) return issubclass(type(obj), klass)
......
...@@ -664,6 +664,23 @@ class PatchTest(unittest.TestCase): ...@@ -664,6 +664,23 @@ class PatchTest(unittest.TestCase):
test() test()
def test_patch_dict_decorator_resolution(self):
# bpo-35512: Ensure that patch with a string target resolves to
# the new dictionary during function call
original = support.target.copy()
@patch.dict('unittest.test.testmock.support.target', {'bar': 'BAR'})
def test():
self.assertEqual(support.target, {'foo': 'BAZ', 'bar': 'BAR'})
try:
support.target = {'foo': 'BAZ'}
test()
self.assertEqual(support.target, {'foo': 'BAZ'})
finally:
support.target = original
def test_patch_descriptor(self): def test_patch_descriptor(self):
# would be some effort to fix this - we could special case the # would be some effort to fix this - we could special case the
# builtin descriptors: classmethod, property, staticmethod # builtin descriptors: classmethod, property, staticmethod
......
:func:`unittest.mock.patch.dict` used as a decorator with string target
resolves the target during function call instead of during decorator
construction. Patch by Karthikeyan Singaravelan.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment