From 9682602bcff486e35298cd7b53beb84bd1412502 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Mon, 9 Jan 2023 09:32:24 -0800 Subject: [PATCH] restore Mock._spec_asyncs and match upstream Summary: D42039568 (https://github.com/facebookincubator/cinder/commit/733b7b3b492551bc32111980b4f052e149cd2829) backported an early version of https://github.com/python/cpython/pull/100252, and there were some changes made before that PR was merged upstream. Backport those changes so we match upstream behavior. Most importantly, this restores `_spec_asyncs`, which although a private API does seem to be used. Reviewed By: itamaro Differential Revision: D42416767 fbshipit-source-id: a7e7a2171b8ace10cd2cb1e370ae0a4a7fd24906 --- Lib/unittest/mock.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 01f6aea6a46..54c35560033 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -493,6 +493,7 @@ def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, _eat_self=False): _spec_class = None _spec_signature = None + _spec_asyncs = [] if spec is not None and not _is_list(spec): if isinstance(spec, type): @@ -503,13 +504,20 @@ def _mock_add_spec(self, spec, spec_set, _spec_as_instance=False, _spec_as_instance, _eat_self) _spec_signature = res and res[1] - spec = dir(spec) + spec_list = dir(spec) + + for attr in spec_list: + if iscoroutinefunction(getattr(spec, attr, None)): + _spec_asyncs.append(attr) + + spec = spec_list __dict__ = self.__dict__ __dict__['_spec_class'] = _spec_class __dict__['_spec_set'] = spec_set __dict__['_spec_signature'] = _spec_signature __dict__['_mock_methods'] = spec + __dict__['_spec_asyncs'] = _spec_asyncs def __get_return_value(self): ret = self._mock_return_value @@ -998,8 +1006,7 @@ 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") - _spec_val = getattr(self.__dict__["_spec_class"], _new_name, None) - if _spec_val is not None and asyncio.iscoroutinefunction(_spec_val): + if _new_name in self.__dict__['_spec_asyncs']: return AsyncMock(**kw) if self._mock_sealed: