From 745c5f1e3f26961ded6b3351fbeacea81930db93 Mon Sep 17 00:00:00 2001 From: Astral Date: Mon, 24 Apr 2023 09:26:17 +0000 Subject: [PATCH 1/2] add assert_has_calls_wrapper --- src/pytest_mock/plugin.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 1d52555..27d8e5f 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -467,6 +467,43 @@ def assert_wrapper( raise e +def assert_has_calls_wrapper( + __wrapped_mock_method__: Callable[..., Any], *args: Any, **kwargs: Any +) -> None: + __tracebackhide__ = True + try: + __wrapped_mock_method__(*args, **kwargs) + return + except AssertionError as e: + any_order = kwargs.get("any_order", False) + if getattr(e, "_mock_introspection_applied", 0) or any_order: + msg = str(e) + else: + __mock_self = args[0] + msg = str(e) + if __mock_self.call_args_list is not None: + actual_calls = list(__mock_self.call_args_list) + expect_calls = args[1] + introspection = "" + from itertools import zip_longest + for actual_call, expect_call in zip_longest(actual_calls, expect_calls): + actual_args, actual_kwargs = actual_call + _, expect_args, expect_kwargs = expect_call + try: + assert actual_args == expect_args + except AssertionError as e_args: + introspection += "\nArgs:\n" + str(e_args) + try: + assert actual_kwargs == expect_kwargs + except AssertionError as e_kwargs: + introspection += "\nKwargs:\n" + str(e_kwargs) + if introspection: + msg += "\n\npytest introspection follows:\n" + introspection + e = AssertionError(msg) + e._mock_introspection_applied = True # type:ignore[attr-defined] + raise e + + def wrap_assert_not_called(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_not_called"], *args, **kwargs) @@ -489,7 +526,7 @@ def wrap_assert_called_once_with(*args: Any, **kwargs: Any) -> None: def wrap_assert_has_calls(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True - assert_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs) + assert_has_calls_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs) def wrap_assert_any_call(*args: Any, **kwargs: Any) -> None: From 50532882d957ec6f2ad19590a6414bdacea4662b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 09:39:41 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pytest_mock/plugin.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 27d8e5f..74c90b2 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -486,6 +486,7 @@ def assert_has_calls_wrapper( expect_calls = args[1] introspection = "" from itertools import zip_longest + for actual_call, expect_call in zip_longest(actual_calls, expect_calls): actual_args, actual_kwargs = actual_call _, expect_args, expect_kwargs = expect_call @@ -526,7 +527,9 @@ def wrap_assert_called_once_with(*args: Any, **kwargs: Any) -> None: def wrap_assert_has_calls(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True - assert_has_calls_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs) + assert_has_calls_wrapper( + _mock_module_originals["assert_has_calls"], *args, **kwargs + ) def wrap_assert_any_call(*args: Any, **kwargs: Any) -> None: