From b8f543907d2374f9916bf521ffe0766c80c7e83a Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 31 May 2020 20:30:15 -0300 Subject: [PATCH] Fix performance when raising ValueError when used as context-manager Fix #191 --- CHANGELOG.rst | 8 ++++++++ src/pytest_mock/plugin.py | 24 +++++++----------------- tests/test_pytest_mock.py | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c750cef..ad89c24 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,11 @@ +3.1.1 (2020-05-31) +------------------ + +* Fixed performance regression caused by the ``ValueError`` raised + when ``mocker`` is used as context manager (`#191`_). + +.. _#191: https://github.com/pytest-dev/pytest-mock/issues/191 + 3.1.0 (2020-04-18) ------------------ diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 9d398f3..fdf8365 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -158,30 +158,20 @@ def _start_patch(self, mock_func, *args, **kwargs): module, registering the patch to stop it later and returns the mock object resulting from the mock call. """ - self._enforce_no_with_context(inspect.stack()) p = mock_func(*args, **kwargs) mocked = p.start() self._patches.append(p) if hasattr(mocked, "reset_mock"): self._mocks.append(mocked) + # check if `mocked` is actually a mock object, as depending on autospec or target + # parameters `mocked` can be anything + if hasattr(mocked, "__enter__"): + mocked.__enter__.side_effect = ValueError( + "Using mocker in a with context is not supported. " + "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager" + ) return mocked - def _enforce_no_with_context(self, stack): - """raises a ValueError if mocker is used in a with context""" - caller = stack[2] - frame = caller[0] - info = inspect.getframeinfo(frame) - if info.code_context is None: - # no source code available (#169) - return - code_context = " ".join(info.code_context).strip() - - if code_context.startswith("with mocker."): - raise ValueError( - "Using mocker in a with context is not supported. " - "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager" - ) - def object(self, *args, **kwargs): """API to mock.patch.object""" return self._start_patch(self.mock_module.patch.object, *args, **kwargs) diff --git a/tests/test_pytest_mock.py b/tests/test_pytest_mock.py index 73509a4..ef9f12c 100644 --- a/tests/test_pytest_mock.py +++ b/tests/test_pytest_mock.py @@ -773,7 +773,7 @@ def doIt(self): def test_abort_patch_context_manager(mocker): with pytest.raises(ValueError) as excinfo: - with mocker.patch("some_package"): + with mocker.patch("json.loads"): pass expected_error_msg = (