1
1
import inspect
2
+ import sys
2
3
3
4
import pytest
4
5
5
- try :
6
- import mock as mock_module
7
- except ImportError :
8
- import unittest .mock as mock_module
9
-
10
6
from _pytest_mock_version import version
11
7
__version__ = version
12
8
13
9
10
+ def _get_mock_module (config ):
11
+ """
12
+ Import and return the actual "mock" module. By default this is "mock" for Python 2 and
13
+ "unittest.mock" for Python 3, but the user can force to always use "mock" on Python 3 using
14
+ the mock_use_standalone_module ini option.
15
+ """
16
+ try :
17
+ return _get_mock_module ._module
18
+ except AttributeError :
19
+ if sys .version_info .major == 2 :
20
+ import mock
21
+ _get_mock_module ._module = mock
22
+ return mock
23
+ else :
24
+ if parse_ini_boolean (config .getini ('mock_use_standalone_module' )):
25
+ import mock
26
+ module = mock
27
+ else :
28
+ import unittest .mock
29
+ module = unittest .mock
30
+ _get_mock_module ._module = module
31
+ return module
32
+
33
+
14
34
class MockFixture (object ):
15
35
"""
16
36
Fixture that provides the same interface to functions in the mock module,
17
37
ensuring that they are uninstalled at the end of each test.
18
38
"""
19
39
20
- Mock = mock_module .Mock
21
- MagicMock = mock_module .MagicMock
22
- PropertyMock = mock_module .PropertyMock
23
- call = mock_module .call
24
- ANY = mock_module .ANY
25
- sentinel = mock_module .sentinel
26
- mock_open = mock_module .mock_open
27
-
28
- def __init__ (self ):
40
+ def __init__ (self , config ):
29
41
self ._patches = [] # list of mock._patch objects
30
42
self ._mocks = [] # list of MagicMock objects
31
- self .patch = self ._Patcher (self ._patches , self ._mocks )
32
- # temporary fix: this should be at class level, but is blowing
33
- # up in Python 3.6
43
+ self ._mock_module = mock_module = _get_mock_module (config )
44
+ self .patch = self ._Patcher (self ._patches , self ._mocks , mock_module )
45
+ # aliases for convenience
46
+ self .Mock = mock_module .Mock
47
+ self .MagicMock = mock_module .MagicMock
48
+ self .PropertyMock = mock_module .PropertyMock
49
+ self .call = mock_module .call
50
+ self .ANY = mock_module .ANY
51
+ self .DEFAULT = mock_module .DEFAULT
52
+ self .sentinel = mock_module .sentinel
53
+ self .mock_open = mock_module .mock_open
34
54
self .sentinel = mock_module .sentinel
35
55
self .mock_open = mock_module .mock_open
36
56
@@ -90,17 +110,18 @@ def stub(self, name=None):
90
110
:rtype: mock.MagicMock
91
111
:return: Stub object.
92
112
"""
93
- return mock_module .MagicMock (spec = lambda * args , ** kwargs : None , name = name )
113
+ return self . _mock_module .MagicMock (spec = lambda * args , ** kwargs : None , name = name )
94
114
95
115
class _Patcher (object ):
96
116
"""
97
117
Object to provide the same interface as mock.patch, mock.patch.object,
98
118
etc. We need this indirection to keep the same API of the mock package.
99
119
"""
100
120
101
- def __init__ (self , patches , mocks ):
121
+ def __init__ (self , patches , mocks , mock_module ):
102
122
self ._patches = patches
103
123
self ._mocks = mocks
124
+ self ._mock_module = mock_module
104
125
105
126
def _start_patch (self , mock_func , * args , ** kwargs ):
106
127
"""Patches something by calling the given function from the mock
@@ -115,29 +136,29 @@ def _start_patch(self, mock_func, *args, **kwargs):
115
136
116
137
def object (self , * args , ** kwargs ):
117
138
"""API to mock.patch.object"""
118
- return self ._start_patch (mock_module .patch .object , * args , ** kwargs )
139
+ return self ._start_patch (self . _mock_module .patch .object , * args , ** kwargs )
119
140
120
141
def multiple (self , * args , ** kwargs ):
121
142
"""API to mock.patch.multiple"""
122
- return self ._start_patch (mock_module .patch .multiple , * args ,
143
+ return self ._start_patch (self . _mock_module .patch .multiple , * args ,
123
144
** kwargs )
124
145
125
146
def dict (self , * args , ** kwargs ):
126
147
"""API to mock.patch.dict"""
127
- return self ._start_patch (mock_module .patch .dict , * args , ** kwargs )
148
+ return self ._start_patch (self . _mock_module .patch .dict , * args , ** kwargs )
128
149
129
150
def __call__ (self , * args , ** kwargs ):
130
151
"""API to mock.patch"""
131
- return self ._start_patch (mock_module .patch , * args , ** kwargs )
152
+ return self ._start_patch (self . _mock_module .patch , * args , ** kwargs )
132
153
133
154
134
155
@pytest .yield_fixture
135
- def mocker ():
156
+ def mocker (pytestconfig ):
136
157
"""
137
158
return an object that has the same interface to the `mock` module, but
138
159
takes care of automatically undoing all patches after each test method.
139
160
"""
140
- result = MockFixture ()
161
+ result = MockFixture (pytestconfig )
141
162
yield result
142
163
result .stopall ()
143
164
@@ -209,6 +230,8 @@ def wrap_assert_methods(config):
209
230
if _mock_module_originals :
210
231
return
211
232
233
+ mock_module = _get_mock_module (config )
234
+
212
235
wrappers = {
213
236
'assert_not_called' : wrap_assert_not_called ,
214
237
'assert_called_with' : wrap_assert_called_with ,
@@ -247,6 +270,10 @@ def pytest_addoption(parser):
247
270
'Monkeypatch the mock library to improve reporting of the '
248
271
'assert_called_... methods' ,
249
272
default = True )
273
+ parser .addini ('mock_use_standalone_module' ,
274
+ 'Use standalone "mock" (from PyPI) instead of builtin "unittest.mock" '
275
+ 'on Python 3' ,
276
+ default = False )
250
277
251
278
252
279
def parse_ini_boolean (value ):
0 commit comments