From a9127012a310a9d0c76e28f292bc2279e9368bb8 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sat, 24 Dec 2022 13:39:39 -0600 Subject: [PATCH] [3.11] gh-100287: Fix unittest.mock.seal with AsyncMock (GH-100496) (cherry picked from commit e4b43ebb3afbd231a4e5630e7e358aa3093f8677) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> --- Lib/unittest/mock.py | 8 ++++---- Lib/unittest/test/testmock/testasync.py | 14 +++++++++++++- .../2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 6720e5bc22dc56..6a1c932081e0f5 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1014,15 +1014,15 @@ def _get_child_mock(self, /, **kw): For non-callable mocks the callable variant will be used (rather than any custom subclass).""" - _new_name = kw.get("_new_name") - if _new_name in self.__dict__['_spec_asyncs']: - return AsyncMock(**kw) - if self._mock_sealed: attribute = f".{kw['name']}" if "name" in kw else "()" mock_name = self._extract_mock_name() + attribute raise AttributeError(mock_name) + _new_name = kw.get("_new_name") + if _new_name in self.__dict__['_spec_asyncs']: + return AsyncMock(**kw) + _type = type(self) if issubclass(_type, MagicMock) and _new_name in _async_method_magics: # Any asynchronous magic becomes an AsyncMock diff --git a/Lib/unittest/test/testmock/testasync.py b/Lib/unittest/test/testmock/testasync.py index e05a22861d47bf..df260abde950ba 100644 --- a/Lib/unittest/test/testmock/testasync.py +++ b/Lib/unittest/test/testmock/testasync.py @@ -11,7 +11,7 @@ from asyncio import run, iscoroutinefunction from unittest import IsolatedAsyncioTestCase from unittest.mock import (ANY, call, AsyncMock, patch, MagicMock, Mock, - create_autospec, sentinel, _CallList) + create_autospec, sentinel, _CallList, seal) def tearDownModule(): @@ -300,6 +300,14 @@ def test_spec_normal_methods_on_class_with_mock(self): self.assertIsInstance(mock.async_method, AsyncMock) self.assertIsInstance(mock.normal_method, Mock) + def test_spec_normal_methods_on_class_with_mock_seal(self): + mock = Mock(AsyncClass) + seal(mock) + with self.assertRaises(AttributeError): + mock.normal_method + with self.assertRaises(AttributeError): + mock.async_method + def test_spec_mock_type_kw(self): def inner_test(mock_type): async_mock = mock_type(spec=async_func) @@ -1076,3 +1084,7 @@ async def f(x=None): pass 'Actual: [call(1)]'))) as cm: self.mock.assert_has_awaits([call(), call(1, 2)]) self.assertIsInstance(cm.exception.__cause__, TypeError) + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/NEWS.d/next/Library/2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst b/Misc/NEWS.d/next/Library/2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst new file mode 100644 index 00000000000000..b353f0810c6a33 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst @@ -0,0 +1 @@ +Fix the interaction of :func:`unittest.mock.seal` with :class:`unittest.mock.AsyncMock`.