diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 2719f74d6fca50..d3ea5a5614c4c7 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -496,9 +496,8 @@ def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, _spec_signature = None _spec_asyncs = [] - for attr in dir(spec): - if iscoroutinefunction(getattr(spec, attr, None)): - _spec_asyncs.append(attr) + for attr, _ in inspect.getmembers_static(spec, iscoroutinefunction): + _spec_asyncs.append(attr) if spec is not None and not _is_list(spec): if isinstance(spec, type): diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index c99098dc4ea86a..aaac55c18d28dd 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -325,6 +325,20 @@ def test_call(self): "call_args_list not set") + def test_not_called_descriptor_protocol(self): + import types + class A: + @property + def name(self): + raise NotImplementedError + @types.DynamicClassAttribute + def eggs(self): + raise NotImplementedError + + self.assertIsInstance(Mock(spec=A), A) + self.assertIsInstance(Mock(spec=A()), A) + + def test_call_args_comparison(self): mock = Mock() mock() diff --git a/Misc/NEWS.d/next/Library/2022-02-15-14-29-41.bpo-45756.P0sGlU.rst b/Misc/NEWS.d/next/Library/2022-02-15-14-29-41.bpo-45756.P0sGlU.rst new file mode 100644 index 00000000000000..92f942ebd0a346 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-02-15-14-29-41.bpo-45756.P0sGlU.rst @@ -0,0 +1,2 @@ +Fix :mod:`unittest.mock` triggers dynamic lookup via the descriptor +protocol. Patch by Weipeng Hong.