summaryrefslogtreecommitdiffstats
path: root/Lib/unittest
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2022-12-23 19:41:37 (GMT)
committerGitHub <noreply@github.com>2022-12-23 19:41:37 (GMT)
commitc5726b727e26b81a267933654cf26b760a90d9aa (patch)
treea30c81c9fd052e6e8081c28cdd787ea6d4402a7b /Lib/unittest
parenta98d9ea56e7b473af54438ecc487a6bf1b4d6530 (diff)
downloadcpython-c5726b727e26b81a267933654cf26b760a90d9aa.zip
cpython-c5726b727e26b81a267933654cf26b760a90d9aa.tar.gz
cpython-c5726b727e26b81a267933654cf26b760a90d9aa.tar.bz2
gh-83076: 3.8x speed improvement in (Async)Mock instantiation (#100252)
Diffstat (limited to 'Lib/unittest')
-rw-r--r--Lib/unittest/mock.py38
1 files changed, 22 insertions, 16 deletions
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index a273753..583ab74 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -411,15 +411,18 @@ class NonCallableMock(Base):
# necessary.
_lock = RLock()
- def __new__(cls, /, *args, **kw):
+ def __new__(
+ cls, spec=None, wraps=None, name=None, spec_set=None,
+ parent=None, _spec_state=None, _new_name='', _new_parent=None,
+ _spec_as_instance=False, _eat_self=None, unsafe=False, **kwargs
+ ):
# every instance has its own class
# so we can create magic methods on the
# class without stomping on other mocks
bases = (cls,)
if not issubclass(cls, AsyncMockMixin):
# Check if spec is an async object or function
- bound_args = _MOCK_SIG.bind_partial(cls, *args, **kw).arguments
- spec_arg = bound_args.get('spec_set', bound_args.get('spec'))
+ spec_arg = spec_set or spec
if spec_arg is not None and _is_async_obj(spec_arg):
bases = (AsyncMockMixin, cls)
new = type(cls.__name__, bases, {'__doc__': cls.__doc__})
@@ -505,10 +508,6 @@ class NonCallableMock(Base):
_spec_signature = None
_spec_asyncs = []
- for attr in dir(spec):
- if iscoroutinefunction(getattr(spec, attr, None)):
- _spec_asyncs.append(attr)
-
if spec is not None and not _is_list(spec):
if isinstance(spec, type):
_spec_class = spec
@@ -518,7 +517,13 @@ class NonCallableMock(Base):
_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
@@ -1057,9 +1062,6 @@ class NonCallableMock(Base):
return f"\n{prefix}: {safe_repr(self.mock_calls)}."
-_MOCK_SIG = inspect.signature(NonCallableMock.__init__)
-
-
class _AnyComparer(list):
"""A list which checks if it contains a call which may have an
argument of ANY, flipping the components of item and self from
@@ -2138,10 +2140,8 @@ class NonCallableMagicMock(MagicMixin, NonCallableMock):
class AsyncMagicMixin(MagicMixin):
- def __init__(self, /, *args, **kw):
- self._mock_set_magics() # make magic work for kwargs in init
- _safe_super(AsyncMagicMixin, self).__init__(*args, **kw)
- self._mock_set_magics() # fix magic broken by upper level init
+ pass
+
class MagicMock(MagicMixin, Mock):
"""
@@ -2183,6 +2183,10 @@ class MagicProxy(Base):
return self.create_mock()
+_CODE_ATTRS = dir(CodeType)
+_CODE_SIG = inspect.signature(partial(CodeType.__init__, None))
+
+
class AsyncMockMixin(Base):
await_count = _delegating_property('await_count')
await_args = _delegating_property('await_args')
@@ -2200,7 +2204,9 @@ class AsyncMockMixin(Base):
self.__dict__['_mock_await_count'] = 0
self.__dict__['_mock_await_args'] = None
self.__dict__['_mock_await_args_list'] = _CallList()
- code_mock = NonCallableMock(spec_set=CodeType)
+ code_mock = NonCallableMock(spec_set=_CODE_ATTRS)
+ code_mock.__dict__["_spec_class"] = CodeType
+ code_mock.__dict__["_spec_signature"] = _CODE_SIG
code_mock.co_flags = inspect.CO_COROUTINE
self.__dict__['__code__'] = code_mock
self.__dict__['__name__'] = 'AsyncMock'