13
13
import asyncio
14
14
import functools
15
15
import inspect
16
+ import warnings
17
+ import sys
16
18
17
19
import pytest
18
20
@@ -39,6 +41,10 @@ def _get_mock_module(config):
39
41
return _get_mock_module ._module
40
42
41
43
44
+ class PytestMockWarning (UserWarning ):
45
+ """Base class for all warnings emitted by pytest-mock."""
46
+
47
+
42
48
class MockerFixture :
43
49
"""
44
50
Fixture that provides the same interface to functions in the mock module,
@@ -169,7 +175,7 @@ def __init__(self, patches, mocks, mock_module):
169
175
self .mock_module = mock_module
170
176
171
177
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
173
179
) -> unittest .mock .MagicMock :
174
180
"""Patches something by calling the given function from the mock
175
181
module, registering the patch to stop it later and returns the
@@ -182,10 +188,18 @@ def _start_patch(
182
188
self ._mocks .append (mocked )
183
189
# check if `mocked` is actually a mock object, as depending on autospec or target
184
190
# 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 ,
189
203
)
190
204
return mocked
191
205
@@ -206,6 +220,37 @@ def object(
206
220
new = self .mock_module .DEFAULT
207
221
return self ._start_patch (
208
222
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 ,
209
254
target ,
210
255
attribute ,
211
256
new = new ,
@@ -230,6 +275,7 @@ def multiple(
230
275
"""API to mock.patch.multiple"""
231
276
return self ._start_patch (
232
277
self .mock_module .patch .multiple ,
278
+ True ,
233
279
target ,
234
280
spec = spec ,
235
281
create = create ,
@@ -249,6 +295,7 @@ def dict(
249
295
"""API to mock.patch.dict"""
250
296
return self ._start_patch (
251
297
self .mock_module .patch .dict ,
298
+ True ,
252
299
in_dict ,
253
300
values = values ,
254
301
clear = clear ,
@@ -328,6 +375,7 @@ def __call__(
328
375
new = self .mock_module .DEFAULT
329
376
return self ._start_patch (
330
377
self .mock_module .patch ,
378
+ True ,
331
379
target ,
332
380
new = new ,
333
381
spec = spec ,
0 commit comments