Karthikeyan Singaravelan <tir.kar...@gmail.com> added the comment: I think I got to this. See issue12370 (Use of super overwrites use of __class__ in class namespace) . msg138712 suggests a workaround to alias super at the module level. unittest.mock has the below line and NonCallableMock has __class__ defined as a property which is not set when set trace is used since the linked commit in 3.7.2 uses super() is somehow executed by settrace since it's in __delattr__ and not in a code path executed by user code?
Looking at the unittest.mock code super is not used anywhere but _safe_super is used which I hope is for this reason. So this is not a case with MagicMock only but rather a case with anything that inherits from NonCallableMock i.e. Mock, MagicMock etc. This is not a problem with import being made before the trace is set as you mentioned so set trace does something that exposes this issue https://github.com/python/cpython/blob/536a35b3f14888999f1ffa5be7239d0c26b73d7a/Lib/unittest/mock.py#L48 # Workaround for issue #12370 # Without this, the __class__ properties wouldn't be set correctly _safe_super = super Sample program in issue12370. Add set trace SuperClass with using super() fails and passes without set trace for super(). Whereas SafeSuperClass that uses _safe_super (module level alias to super) passes both cases irrespective of usage of set trace. Nick coughlan added a message so that unittest.mock should use _safe_super in https://bugs.python.org/issue12370#msg161704 import sys _safe_super = super def trace(frame, event, arg): return trace if len(sys.argv) > 1: sys.settrace(trace) class SuperClass(object): def __init__(self): super().__init__() @property def __class__(self): return int class SafeSuperClass(object): def __init__(self): _safe_super(SafeSuperClass, self).__init__() @property def __class__(self): return int print(isinstance(SuperClass(), int)) print(isinstance(SafeSuperClass(), int)) Running above code with trace and without trace ➜ cpython git:(master) ✗ ./python.exe /tmp/buz.py True True ➜ cpython git:(master) ✗ ./python.exe /tmp/buz.py 1 False True There is a test for the above in Lib/test/test_super.py at https://github.com/python/cpython/blob/4c409beb4c360a73d054f37807d3daad58d1b567/Lib/test/test_super.py#L87 Add a trace as below in test_super.py at the top and the test case fails import sys def trace(frame, event, arg): return trace sys.settrace(trace) ➜ cpython git:(master) ✗ ./python.exe Lib/test/test_super.py ....................F ====================================================================== FAIL: test_various___class___pathologies (__main__.TestSuper) ---------------------------------------------------------------------- Traceback (most recent call last): File "Lib/test/test_super.py", line 100, in test_various___class___pathologies self.assertEqual(x.__class__, 413) AssertionError: <class '__main__.TestSuper.test_various___class___pathologies.<locals>.X'> != 413 ---------------------------------------------------------------------- Ran 21 tests in 0.058s FAILED (failures=1) The patch for this issue would be to use _safe_super instead of super() or to fallback to object() in the previous case that doesn't seemed to have suffered from this case. I can try to make a PR with tests. Added Michael for confirmation. diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 8684f1dfa5..0e77f0e489 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -739,7 +739,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: ---------- nosy: +michael.foord _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue36593> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com