mirror of
https://github.com/python/cpython.git
synced 2025-07-24 19:54:21 +00:00
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
This commit is contained in:
parent
aeca373b33
commit
a875ea58b2
4 changed files with 25 additions and 2 deletions
|
@ -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):
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
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):
|
||||||
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
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
: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.
|
Loading…
Add table
Add a link
Reference in a new issue