Skip to content

Commit

Permalink
Fix performance when raising ValueError when used as context-manager
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed May 31, 2020
1 parent e6a1d0a commit b8f5439
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 18 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -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)
------------------

Expand Down
24 changes: 7 additions & 17 deletions src/pytest_mock/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down

0 comments on commit b8f5439

Please sign in to comment.