[3.11] gh-100287: Fix unittest.mock.seal with AsyncMock (GH-100496) (#100506)

https://github.com/python/cpython/commit/75b75dfdacc25a0ffc125c2e372036c3f79... commit: 75b75dfdacc25a0ffc125c2e372036c3f799f5ea branch: 3.11 author: Shantanu <12621235+hauntsaninja@users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja@users.noreply.github.com> date: 2022-12-24T14:39:19-06:00 summary: [3.11] gh-100287: Fix unittest.mock.seal with AsyncMock (GH-100496) (#100506) (cherry picked from commit e4b43ebb3afbd231a4e5630e7e358aa3093f8677) Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2022-12-24-08-42-05.gh-issue-100287.n0oEuG.rst M Lib/unittest/mock.py M Lib/unittest/test/testmock/testasync.py diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 6720e5bc22dc..6a1c932081e0 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 e05a22861d47..df260abde950 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 000000000000..b353f0810c6a --- /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`.
participants (1)
-
hauntsaninja