From 917d72234adad2351147d750f2ea597f534f70ff Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Wed, 11 Sep 2019 16:08:00 +0100 Subject: [PATCH 1/6] Port tests from original PR --- Lib/unittest/test/testmock/testmock.py | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 581afaaeb815df..d42cfe0b3b6eab 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -529,6 +529,48 @@ def test_only_allowed_methods_exist(self): ) + def _check_autospeced_something(self, something): + for method_name in ['meth', 'cmeth', 'smeth']: + mock_method = getattr(something, method_name) + + # check that the methods are callable with correct args. + mock_method(sentinel.a, sentinel.b, sentinel.c) + mock_method(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d) + mock_method.assert_has_calls([ + call(sentinel.a, sentinel.b, sentinel.c), + call(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d)]) + + # assert that TypeError is raised if the method signature is not + # respected. + self.assertRaises(TypeError, mock_method) + self.assertRaises(TypeError, mock_method, sentinel.a) + self.assertRaises(TypeError, mock_method, a=sentinel.a) + self.assertRaises(TypeError, mock_method, sentinel.a, sentinel.b, + sentinel.c, e=sentinel.e) + + # assert that AttributeError is raised if the method does not exist. + self.assertRaises(AttributeError, getattr, something, 'foolish') + + + def test_mock_autospec_all_members(self): + for spec in [Something, Something()]: + mock_something = Mock(autospec=spec) + self._check_autospeced_something(mock_something) + + + def test_mock_spec_function(self): + def foo(lish): + pass + + mock_foo = Mock(spec=foo) + + mock_foo(sentinel.lish) + mock_foo.assert_called_once_with(sentinel.lish) + self.assertRaises(TypeError, mock_foo) + self.assertRaises(TypeError, mock_foo, sentinel.foo, sentinel.lish) + self.assertRaises(TypeError, mock_foo, foo=sentinel.foo) + + def test_from_spec(self): class Something(object): x = 3 @@ -1387,6 +1429,13 @@ def meth1(self, a, b): pass ) + def test_mock_add_spec_autospec_all_members(self): + for spec in [Something, Something()]: + mock_something = Mock() + mock_something.mock_add_spec(spec, autospec=True) + self._check_autospeced_something(mock_something) + + def test_assert_has_calls_nested_without_spec(self): m = MagicMock() m().foo().bar().baz() From 890795e5f06f3683f351c090ec376ea6ae6b4123 Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Wed, 11 Sep 2019 16:08:00 +0100 Subject: [PATCH 2/6] Port tests from original PR --- Lib/unittest/test/testmock/testmock.py | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 581afaaeb815df..d42cfe0b3b6eab 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -529,6 +529,48 @@ def test_only_allowed_methods_exist(self): ) + def _check_autospeced_something(self, something): + for method_name in ['meth', 'cmeth', 'smeth']: + mock_method = getattr(something, method_name) + + # check that the methods are callable with correct args. + mock_method(sentinel.a, sentinel.b, sentinel.c) + mock_method(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d) + mock_method.assert_has_calls([ + call(sentinel.a, sentinel.b, sentinel.c), + call(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d)]) + + # assert that TypeError is raised if the method signature is not + # respected. + self.assertRaises(TypeError, mock_method) + self.assertRaises(TypeError, mock_method, sentinel.a) + self.assertRaises(TypeError, mock_method, a=sentinel.a) + self.assertRaises(TypeError, mock_method, sentinel.a, sentinel.b, + sentinel.c, e=sentinel.e) + + # assert that AttributeError is raised if the method does not exist. + self.assertRaises(AttributeError, getattr, something, 'foolish') + + + def test_mock_autospec_all_members(self): + for spec in [Something, Something()]: + mock_something = Mock(autospec=spec) + self._check_autospeced_something(mock_something) + + + def test_mock_spec_function(self): + def foo(lish): + pass + + mock_foo = Mock(spec=foo) + + mock_foo(sentinel.lish) + mock_foo.assert_called_once_with(sentinel.lish) + self.assertRaises(TypeError, mock_foo) + self.assertRaises(TypeError, mock_foo, sentinel.foo, sentinel.lish) + self.assertRaises(TypeError, mock_foo, foo=sentinel.foo) + + def test_from_spec(self): class Something(object): x = 3 @@ -1387,6 +1429,13 @@ def meth1(self, a, b): pass ) + def test_mock_add_spec_autospec_all_members(self): + for spec in [Something, Something()]: + mock_something = Mock() + mock_something.mock_add_spec(spec, autospec=True) + self._check_autospeced_something(mock_something) + + def test_assert_has_calls_nested_without_spec(self): m = MagicMock() m().foo().bar().baz() From 9f8a081f07193cef4aa70bfec2b02cf0fac57bb5 Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Fri, 13 Sep 2019 14:04:10 +0100 Subject: [PATCH 3/6] Minor fixes --- Lib/unittest/mock.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index a98decc2c9f008..bc8124748ba65d 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -402,18 +402,12 @@ def __new__(cls, /, *args, **kw): # so we can create magic methods on the # class without stomping on other mocks bases = (cls,) - if not issubclass(cls, AsyncMock): + if not issubclass(cls, AsyncMockMixin): # Check if spec is an async object or function - sig = inspect.signature(NonCallableMock.__init__) - bound_args = sig.bind_partial(cls, *args, **kw).arguments - spec_arg = [ - arg for arg in bound_args.keys() - if arg.startswith('spec') - ] - if spec_arg: - # what if spec_set is different than spec? - if _is_async_obj(bound_args[spec_arg[0]]): - bases = (AsyncMockMixin, cls,) + bound_args = _MOCK_SIG.bind_partial(cls, *args, **kw).arguments + spec_arg = bound_args.get('spec_set', bound_args.get('spec')) + if spec_arg and _is_async_obj(spec_arg): + bases = (AsyncMockMixin, cls) new = type(cls.__name__, bases, {'__doc__': cls.__doc__}) instance = object.__new__(new) return instance @@ -1018,7 +1012,7 @@ def _calls_repr(self, prefix="Calls"): return "" return f"\n{prefix}: {safe_repr(self.mock_calls)}." - +_MOCK_SIG = inspect.signature(NonCallableMock.__init__) def _try_iter(obj): if obj is None: From 327b33cc50cc72b2419cd32532af115808242315 Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Fri, 13 Sep 2019 14:09:04 +0100 Subject: [PATCH 4/6] Remove extraneous tests --- Lib/unittest/test/testmock/testmock.py | 42 -------------------------- 1 file changed, 42 deletions(-) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index d42cfe0b3b6eab..03cedca6e38636 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -529,48 +529,6 @@ def test_only_allowed_methods_exist(self): ) - def _check_autospeced_something(self, something): - for method_name in ['meth', 'cmeth', 'smeth']: - mock_method = getattr(something, method_name) - - # check that the methods are callable with correct args. - mock_method(sentinel.a, sentinel.b, sentinel.c) - mock_method(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d) - mock_method.assert_has_calls([ - call(sentinel.a, sentinel.b, sentinel.c), - call(sentinel.a, sentinel.b, sentinel.c, d=sentinel.d)]) - - # assert that TypeError is raised if the method signature is not - # respected. - self.assertRaises(TypeError, mock_method) - self.assertRaises(TypeError, mock_method, sentinel.a) - self.assertRaises(TypeError, mock_method, a=sentinel.a) - self.assertRaises(TypeError, mock_method, sentinel.a, sentinel.b, - sentinel.c, e=sentinel.e) - - # assert that AttributeError is raised if the method does not exist. - self.assertRaises(AttributeError, getattr, something, 'foolish') - - - def test_mock_autospec_all_members(self): - for spec in [Something, Something()]: - mock_something = Mock(autospec=spec) - self._check_autospeced_something(mock_something) - - - def test_mock_spec_function(self): - def foo(lish): - pass - - mock_foo = Mock(spec=foo) - - mock_foo(sentinel.lish) - mock_foo.assert_called_once_with(sentinel.lish) - self.assertRaises(TypeError, mock_foo) - self.assertRaises(TypeError, mock_foo, sentinel.foo, sentinel.lish) - self.assertRaises(TypeError, mock_foo, foo=sentinel.foo) - - def test_from_spec(self): class Something(object): x = 3 From 6f058d9d69441b9fe9b6793aefa89f2182e78a45 Mon Sep 17 00:00:00 2001 From: Michael Foord Date: Fri, 13 Sep 2019 14:10:18 +0100 Subject: [PATCH 5/6] Remove extraneous test --- Lib/unittest/test/testmock/testmock.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Lib/unittest/test/testmock/testmock.py b/Lib/unittest/test/testmock/testmock.py index 03cedca6e38636..581afaaeb815df 100644 --- a/Lib/unittest/test/testmock/testmock.py +++ b/Lib/unittest/test/testmock/testmock.py @@ -1387,13 +1387,6 @@ def meth1(self, a, b): pass ) - def test_mock_add_spec_autospec_all_members(self): - for spec in [Something, Something()]: - mock_something = Mock() - mock_something.mock_add_spec(spec, autospec=True) - self._check_autospeced_something(mock_something) - - def test_assert_has_calls_nested_without_spec(self): m = MagicMock() m().foo().bar().baz() From fbc12ef19235a8a4b7e1f193b5fad3d515d7dce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 13 Sep 2019 18:19:17 +0200 Subject: [PATCH 6/6] Fix whitespace --- Lib/unittest/mock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 917dbfe5be4e13..b33d58a2cb0df2 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -1013,7 +1013,7 @@ def _calls_repr(self, prefix="Calls"): return "" return f"\n{prefix}: {safe_repr(self.mock_calls)}." - + _MOCK_SIG = inspect.signature(NonCallableMock.__init__)