]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-36593: Fix isinstance check for Mock objects with spec executed under tracing...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 13 Apr 2019 19:31:58 +0000 (12:31 -0700)
committerGitHub <noreply@github.com>
Sat, 13 Apr 2019 19:31:58 +0000 (12:31 -0700)
In Python having a trace function in effect while mock is imported causes isinstance to be wrong for MagicMocks. This is due to the usage of super() in some class methods, as this sets the __class__ attribute. To avoid this, as a workaround, alias the usage of super .
(cherry picked from commit 830b43d03cc47a27a22a50d777f23c8e60820867)

Co-authored-by: Xtreak <tir.karthi@gmail.com>
Lib/unittest/mock.py
Lib/unittest/test/testmock/testmock.py
Misc/NEWS.d/next/Library/2019-04-11-22-11-24.bpo-36598.hfzDUl.rst [new file with mode: 0644]

index 5b8e7441403538ca49bb17f7d63342666d888f9b..373e1d5f64d87b347efcad92d9ce12c1a579f3cd 100644 (file)
@@ -738,7 +738,7 @@ class NonCallableMock(Base):
 
         obj = self._mock_children.get(name, _missing)
         if name in self.__dict__:
-            super().__delattr__(name)
+            _safe_super(NonCallableMock, self).__delattr__(name)
         elif obj is _deleted:
             raise AttributeError(name)
         if obj is not _missing:
index 447a502b57d6eb5845b50293cfc9c886016d9e18..2f50236d1ece1a0f2de5e0f23066d2965b695d60 100644 (file)
@@ -1811,6 +1811,44 @@ class MockTest(unittest.TestCase):
         self.assertRaises(TypeError, mock.child, 1)
         self.assertEqual(mock.mock_calls, [call.child(1, 2)])
 
+    def test_isinstance_under_settrace(self):
+        # bpo-36593 : __class__ is not set for a class that has __class__
+        # property defined when it's used with sys.settrace(trace) set.
+        # Delete the module to force reimport with tracing function set
+        # restore the old reference later since there are other tests that are
+        # dependent on unittest.mock.patch. In testpatch.PatchTest
+        # test_patch_dict_test_prefix and test_patch_test_prefix not restoring
+        # causes the objects patched to go out of sync
+
+        old_patch = unittest.mock.patch
+
+        # Directly using __setattr__ on unittest.mock causes current imported
+        # reference to be updated. Use a lambda so that during cleanup the
+        # re-imported new reference is updated.
+        self.addCleanup(lambda patch: setattr(unittest.mock, 'patch', patch),
+                        old_patch)
+
+        with patch.dict('sys.modules'):
+            del sys.modules['unittest.mock']
+
+            def trace(frame, event, arg):
+                return trace
+
+            sys.settrace(trace)
+            self.addCleanup(sys.settrace, None)
+
+            from unittest.mock import (
+                Mock, MagicMock, NonCallableMock, NonCallableMagicMock
+            )
+
+            mocks = [
+                Mock, MagicMock, NonCallableMock, NonCallableMagicMock
+            ]
+
+            for mock in mocks:
+                obj = mock(spec=Something)
+                self.assertIsInstance(obj, Something)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2019-04-11-22-11-24.bpo-36598.hfzDUl.rst b/Misc/NEWS.d/next/Library/2019-04-11-22-11-24.bpo-36598.hfzDUl.rst
new file mode 100644 (file)
index 0000000..2a79802
--- /dev/null
@@ -0,0 +1,2 @@
+Fix ``isinstance`` check for Mock objects with spec when the code is
+executed under tracing. Patch by Karthikeyan Singaravelan.