Skip to content

Commit 5bf4f69

Browse files
committed
Fix mock.patch.dict to be stopped with mock.patch.stopall
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 94d2c8d commit 5bf4f69

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
@@ -1853,8 +1853,23 @@ def __exit__(self, *args):
18531853
self._unpatch_dict()
18541854
return False
18551855

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

18591874

18601875
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
@@ -1807,6 +1807,56 @@ def stop(self):
18071807

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

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

18111861
def test_special_attrs(self):
18121862
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)