Skip to content

Commit e131c97

Browse files
mariocj89cjw296
authored andcommitted
Fix mock.patch.dict to be stopped with mock.patch.stopall (#17606)
As the function was not registering in the active patches, the mocks started by `mock.patch.dict` were not being stopped when `mock.patch.stopall` was being called.
1 parent 1d0c5e1 commit e131c97

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

Lib/unittest/mock.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,8 +1851,23 @@ def __exit__(self, *args):
18511851
self._unpatch_dict()
18521852
return False
18531853

1854-
start = __enter__
1855-
stop = __exit__
1854+
1855+
def start(self):
1856+
"""Activate a patch, returning any created mock."""
1857+
result = self.__enter__()
1858+
_patch._active_patches.append(self)
1859+
return result
1860+
1861+
1862+
def stop(self):
1863+
"""Stop an active patch."""
1864+
try:
1865+
_patch._active_patches.remove(self)
1866+
except ValueError:
1867+
# If the patch hasn't been started this will fail
1868+
pass
1869+
1870+
return self.__exit__()
18561871

18571872

18581873
def _clear_dict(in_dict):

Lib/unittest/test/testmock/testpatch.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,56 @@ def stop(self):
18081808

18091809
self.assertEqual(stopped, ["three", "two", "one"])
18101810

1811+
def test_patch_dict_stopall(self):
1812+
dic1 = {}
1813+
dic2 = {1: 'a'}
1814+
dic3 = {1: 'A', 2: 'B'}
1815+
origdic1 = dic1.copy()
1816+
origdic2 = dic2.copy()
1817+
origdic3 = dic3.copy()
1818+
patch.dict(dic1, {1: 'I', 2: 'II'}).start()
1819+
patch.dict(dic2, {2: 'b'}).start()
1820+
1821+
@patch.dict(dic3)
1822+
def patched():
1823+
del dic3[1]
1824+
1825+
patched()
1826+
self.assertNotEqual(dic1, origdic1)
1827+
self.assertNotEqual(dic2, origdic2)
1828+
self.assertEqual(dic3, origdic3)
1829+
1830+
patch.stopall()
1831+
1832+
self.assertEqual(dic1, origdic1)
1833+
self.assertEqual(dic2, origdic2)
1834+
self.assertEqual(dic3, origdic3)
1835+
1836+
1837+
def test_patch_and_patch_dict_stopall(self):
1838+
original_unlink = os.unlink
1839+
original_chdir = os.chdir
1840+
dic1 = {}
1841+
dic2 = {1: 'A', 2: 'B'}
1842+
origdic1 = dic1.copy()
1843+
origdic2 = dic2.copy()
1844+
1845+
patch('os.unlink', something).start()
1846+
patch('os.chdir', something_else).start()
1847+
patch.dict(dic1, {1: 'I', 2: 'II'}).start()
1848+
patch.dict(dic2).start()
1849+
del dic2[1]
1850+
1851+
self.assertIsNot(os.unlink, original_unlink)
1852+
self.assertIsNot(os.chdir, original_chdir)
1853+
self.assertNotEqual(dic1, origdic1)
1854+
self.assertNotEqual(dic2, origdic2)
1855+
patch.stopall()
1856+
self.assertIs(os.unlink, original_unlink)
1857+
self.assertIs(os.chdir, original_chdir)
1858+
self.assertEqual(dic1, origdic1)
1859+
self.assertEqual(dic2, origdic2)
1860+
18111861

18121862
def test_special_attrs(self):
18131863
def foo(x=0):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :func:`mock.patch.stopall` to stop active patches that were created with
2+
:func:`mock.patch.dict`.

0 commit comments

Comments
 (0)