[Python-checkins] Fix `mock.patch.dict` to be stopped with `mock.patch.stopall` (#17606)

Chris Withers webhook-mailer at python.org
Fri Jan 24 03:38:37 EST 2020


https://github.com/python/cpython/commit/e131c9720d087c0c4988bd2a5c62020feb9d1d77
commit: e131c9720d087c0c4988bd2a5c62020feb9d1d77
branch: master
author: Mario Corchero <mariocj89 at gmail.com>
committer: Chris Withers <chris at withers.org>
date: 2020-01-24T08:38:32Z
summary:

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.

files:
A Misc/NEWS.d/next/Library/2019-12-14-14-38-40.bpo-21600.kC4Cgh.rst
M Lib/unittest/mock.py
M Lib/unittest/test/testmock/testpatch.py

diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 5622917dc3743..3fafe594c5978 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -1851,8 +1851,23 @@ def __exit__(self, *args):
         self._unpatch_dict()
         return False
 
-    start = __enter__
-    stop = __exit__
+
+    def start(self):
+        """Activate a patch, returning any created mock."""
+        result = self.__enter__()
+        _patch._active_patches.append(self)
+        return result
+
+
+    def stop(self):
+        """Stop an active patch."""
+        try:
+            _patch._active_patches.remove(self)
+        except ValueError:
+            # If the patch hasn't been started this will fail
+            pass
+
+        return self.__exit__()
 
 
 def _clear_dict(in_dict):
diff --git a/Lib/unittest/test/testmock/testpatch.py b/Lib/unittest/test/testmock/testpatch.py
index dc4ccdbae242b..438dfd8cfbcc0 100644
--- a/Lib/unittest/test/testmock/testpatch.py
+++ b/Lib/unittest/test/testmock/testpatch.py
@@ -1808,6 +1808,56 @@ def stop(self):
 
         self.assertEqual(stopped, ["three", "two", "one"])
 
+    def test_patch_dict_stopall(self):
+        dic1 = {}
+        dic2 = {1: 'a'}
+        dic3 = {1: 'A', 2: 'B'}
+        origdic1 = dic1.copy()
+        origdic2 = dic2.copy()
+        origdic3 = dic3.copy()
+        patch.dict(dic1, {1: 'I', 2: 'II'}).start()
+        patch.dict(dic2, {2: 'b'}).start()
+
+        @patch.dict(dic3)
+        def patched():
+            del dic3[1]
+
+        patched()
+        self.assertNotEqual(dic1, origdic1)
+        self.assertNotEqual(dic2, origdic2)
+        self.assertEqual(dic3, origdic3)
+
+        patch.stopall()
+
+        self.assertEqual(dic1, origdic1)
+        self.assertEqual(dic2, origdic2)
+        self.assertEqual(dic3, origdic3)
+
+
+    def test_patch_and_patch_dict_stopall(self):
+        original_unlink = os.unlink
+        original_chdir = os.chdir
+        dic1 = {}
+        dic2 = {1: 'A', 2: 'B'}
+        origdic1 = dic1.copy()
+        origdic2 = dic2.copy()
+
+        patch('os.unlink', something).start()
+        patch('os.chdir', something_else).start()
+        patch.dict(dic1, {1: 'I', 2: 'II'}).start()
+        patch.dict(dic2).start()
+        del dic2[1]
+
+        self.assertIsNot(os.unlink, original_unlink)
+        self.assertIsNot(os.chdir, original_chdir)
+        self.assertNotEqual(dic1, origdic1)
+        self.assertNotEqual(dic2, origdic2)
+        patch.stopall()
+        self.assertIs(os.unlink, original_unlink)
+        self.assertIs(os.chdir, original_chdir)
+        self.assertEqual(dic1, origdic1)
+        self.assertEqual(dic2, origdic2)
+
 
     def test_special_attrs(self):
         def foo(x=0):
diff --git a/Misc/NEWS.d/next/Library/2019-12-14-14-38-40.bpo-21600.kC4Cgh.rst b/Misc/NEWS.d/next/Library/2019-12-14-14-38-40.bpo-21600.kC4Cgh.rst
new file mode 100644
index 0000000000000..0f72639310653
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-12-14-14-38-40.bpo-21600.kC4Cgh.rst
@@ -0,0 +1,2 @@
+Fix :func:`mock.patch.stopall` to stop active patches that were created with
+:func:`mock.patch.dict`.



More information about the Python-checkins mailing list