1313import asyncio
1414import functools
1515import inspect
16+ import warnings
17+ import sys
1618
1719import pytest
1820
@@ -39,6 +41,10 @@ def _get_mock_module(config):
3941 return _get_mock_module ._module
4042
4143
44+ class PytestMockWarning (UserWarning ):
45+ """Base class for all warnings emitted by pytest-mock."""
46+
47+
4248class MockerFixture :
4349 """
4450 Fixture that provides the same interface to functions in the mock module,
@@ -169,7 +175,7 @@ def __init__(self, patches, mocks, mock_module):
169175 self .mock_module = mock_module
170176
171177 def _start_patch (
172- self , mock_func : Any , * args : Any , ** kwargs : Any
178+ self , mock_func : Any , warn_on_mock_enter : bool , * args : Any , ** kwargs : Any
173179 ) -> unittest .mock .MagicMock :
174180 """Patches something by calling the given function from the mock
175181 module, registering the patch to stop it later and returns the
@@ -182,10 +188,18 @@ def _start_patch(
182188 self ._mocks .append (mocked )
183189 # check if `mocked` is actually a mock object, as depending on autospec or target
184190 # parameters `mocked` can be anything
185- if hasattr (mocked , "__enter__" ):
186- mocked .__enter__ .side_effect = ValueError (
187- "Using mocker in a with context is not supported. "
188- "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager"
191+ if hasattr (mocked , "__enter__" ) and warn_on_mock_enter :
192+ if sys .version_info >= (3 , 8 ):
193+ depth = 5
194+ else :
195+ depth = 4
196+ mocked .__enter__ .side_effect = lambda : warnings .warn (
197+ "Mocks returned by pytest-mock do not need to be used as context managers. "
198+ "The mocker fixture automatically undoes mocking at the end of a test. "
199+ "This warning can be ignored if it was triggered by mocking a context manager. "
200+ "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager" ,
201+ PytestMockWarning ,
202+ stacklevel = depth ,
189203 )
190204 return mocked
191205
@@ -206,6 +220,37 @@ def object(
206220 new = self .mock_module .DEFAULT
207221 return self ._start_patch (
208222 self .mock_module .patch .object ,
223+ True ,
224+ target ,
225+ attribute ,
226+ new = new ,
227+ spec = spec ,
228+ create = create ,
229+ spec_set = spec_set ,
230+ autospec = autospec ,
231+ new_callable = new_callable ,
232+ ** kwargs
233+ )
234+
235+ def context_manager (
236+ self ,
237+ target : builtins .object ,
238+ attribute : str ,
239+ new : builtins .object = DEFAULT ,
240+ spec : Optional [builtins .object ] = None ,
241+ create : bool = False ,
242+ spec_set : Optional [builtins .object ] = None ,
243+ autospec : Optional [builtins .object ] = None ,
244+ new_callable : builtins .object = None ,
245+ ** kwargs : Any
246+ ) -> unittest .mock .MagicMock :
247+ """This is equivalent to mock.patch.object except that the returned mock
248+ does not issue a warning when used as a context manager."""
249+ if new is self .DEFAULT :
250+ new = self .mock_module .DEFAULT
251+ return self ._start_patch (
252+ self .mock_module .patch .object ,
253+ False ,
209254 target ,
210255 attribute ,
211256 new = new ,
@@ -230,6 +275,7 @@ def multiple(
230275 """API to mock.patch.multiple"""
231276 return self ._start_patch (
232277 self .mock_module .patch .multiple ,
278+ True ,
233279 target ,
234280 spec = spec ,
235281 create = create ,
@@ -249,6 +295,7 @@ def dict(
249295 """API to mock.patch.dict"""
250296 return self ._start_patch (
251297 self .mock_module .patch .dict ,
298+ True ,
252299 in_dict ,
253300 values = values ,
254301 clear = clear ,
@@ -328,6 +375,7 @@ def __call__(
328375 new = self .mock_module .DEFAULT
329376 return self ._start_patch (
330377 self .mock_module .patch ,
378+ True ,
331379 target ,
332380 new = new ,
333381 spec = spec ,
0 commit comments