Skip to content

Commit 7d20814

Browse files
authored
Merge pull request #192 from nicoddemus/context-slow
2 parents 5842895 + 55c11a9 commit 7d20814

File tree

3 files changed

+36
-18
lines changed

3 files changed

+36
-18
lines changed

CHANGELOG.rst

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
3.1.1 (2020-05-31)
2+
------------------
3+
4+
* Fixed performance regression caused by the ``ValueError`` raised
5+
when ``mocker`` is used as context manager (`#191`_).
6+
7+
.. _#191: https://github.com/pytest-dev/pytest-mock/issues/191
8+
19
3.1.0 (2020-04-18)
210
------------------
311

src/pytest_mock/plugin.py

+7-17
Original file line numberDiff line numberDiff line change
@@ -158,30 +158,20 @@ def _start_patch(self, mock_func, *args, **kwargs):
158158
module, registering the patch to stop it later and returns the
159159
mock object resulting from the mock call.
160160
"""
161-
self._enforce_no_with_context(inspect.stack())
162161
p = mock_func(*args, **kwargs)
163162
mocked = p.start()
164163
self._patches.append(p)
165164
if hasattr(mocked, "reset_mock"):
166165
self._mocks.append(mocked)
166+
# check if `mocked` is actually a mock object, as depending on autospec or target
167+
# parameters `mocked` can be anything
168+
if hasattr(mocked, "__enter__"):
169+
mocked.__enter__.side_effect = ValueError(
170+
"Using mocker in a with context is not supported. "
171+
"https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager"
172+
)
167173
return mocked
168174

169-
def _enforce_no_with_context(self, stack):
170-
"""raises a ValueError if mocker is used in a with context"""
171-
caller = stack[2]
172-
frame = caller[0]
173-
info = inspect.getframeinfo(frame)
174-
if info.code_context is None:
175-
# no source code available (#169)
176-
return
177-
code_context = " ".join(info.code_context).strip()
178-
179-
if code_context.startswith("with mocker."):
180-
raise ValueError(
181-
"Using mocker in a with context is not supported. "
182-
"https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager"
183-
)
184-
185175
def object(self, *args, **kwargs):
186176
"""API to mock.patch.object"""
187177
return self._start_patch(self.mock_module.patch.object, *args, **kwargs)

tests/test_pytest_mock.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ def doIt(self):
773773

774774
def test_abort_patch_context_manager(mocker):
775775
with pytest.raises(ValueError) as excinfo:
776-
with mocker.patch("some_package"):
776+
with mocker.patch("json.loads"):
777777
pass
778778

779779
expected_error_msg = (
@@ -784,6 +784,26 @@ def test_abort_patch_context_manager(mocker):
784784
assert str(excinfo.value) == expected_error_msg
785785

786786

787+
def test_context_manager_patch_example(mocker):
788+
"""Our message about misusing mocker as a context manager should not affect mocking
789+
context managers (see #192)"""
790+
791+
class dummy_module:
792+
class MyContext:
793+
def __enter__(self, *args, **kwargs):
794+
return 10
795+
796+
def __exit__(self, *args, **kwargs):
797+
pass
798+
799+
def my_func():
800+
with dummy_module.MyContext() as v:
801+
return v
802+
803+
m = mocker.patch.object(dummy_module, "MyContext")
804+
assert isinstance(my_func(), mocker.MagicMock)
805+
806+
787807
def test_abort_patch_context_manager_with_stale_pyc(testdir):
788808
"""Ensure we don't trigger an error in case the frame where mocker.patch is being
789809
used doesn't have a 'context' (#169)"""

0 commit comments

Comments
 (0)