Skip to content

Commit 5583db4

Browse files
committed
test: Fallback to external mock for AsyncMock
AsyncMock is not included in unittest.mock under Python 3.7, so we must fallback to the external mock requirement for that Python version. Only install it for that version. Keep this as a separate commit so it can be reverted when 3.7 isn't supported anymore.
1 parent 5f28e21 commit 5583db4

8 files changed

+54
-24
lines changed

noxfile.py

+2
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ def default(session, install_grpc=True, prerelease=False, install_async_rest=Fal
124124

125125
session.install(
126126
"dataclasses",
127+
"mock; python_version=='3.7'",
127128
"pytest",
128129
"pytest-cov",
129130
"pytest-xdist",
@@ -280,6 +281,7 @@ def mypy(session):
280281
"types-requests",
281282
"types-protobuf",
282283
"types-dataclasses",
284+
"types-mock; python_version=='3.7'",
283285
)
284286
session.run("mypy", "google", "tests")
285287

tests/asyncio/gapic/test_method_async.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
import datetime
1616
from unittest import mock
1717

18+
try:
19+
from unittest.mock import AsyncMock
20+
except ImportError:
21+
from mock import AsyncMock
1822
import pytest
1923

2024
try:
@@ -256,7 +260,7 @@ async def test_wrap_method_with_overriding_timeout_as_a_number():
256260

257261
@pytest.mark.asyncio
258262
async def test_wrap_method_without_wrap_errors():
259-
fake_call = mock.AsyncMock()
263+
fake_call = AsyncMock()
260264

261265
wrapped_method = gapic_v1.method_async.wrap_method(fake_call, kind="rest")
262266
with mock.patch("google.api_core.grpc_helpers_async.wrap_errors") as method:

tests/asyncio/retry/test_retry_unary_async.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import re
1717
from unittest import mock
1818

19+
try:
20+
from unittest.mock import AsyncMock
21+
except ImportError:
22+
from mock import AsyncMock
1923
import pytest
2024

2125
from google.api_core import exceptions
@@ -168,7 +172,7 @@ def if_exception_type(exc):
168172
@pytest.mark.asyncio
169173
async def test___call___and_execute_success(self, sleep):
170174
retry_ = retry_async.AsyncRetry()
171-
target = mock.AsyncMock(spec=["__call__"], return_value=42)
175+
target = AsyncMock(spec=["__call__"], return_value=42)
172176
# __name__ is needed by functools.partial.
173177
target.__name__ = "target"
174178

@@ -190,7 +194,7 @@ async def test___call___and_execute_retry(self, sleep, uniform):
190194
predicate=retry_async.if_exception_type(ValueError)
191195
)
192196

193-
target = mock.AsyncMock(spec=["__call__"], side_effect=[ValueError(), 42])
197+
target = AsyncMock(spec=["__call__"], side_effect=[ValueError(), 42])
194198
# __name__ is needed by functools.partial.
195199
target.__name__ = "target"
196200

@@ -220,7 +224,7 @@ async def test___call___and_execute_retry_hitting_timeout(self, sleep, uniform):
220224

221225
monotonic_patcher = mock.patch("time.monotonic", return_value=0)
222226

223-
target = mock.AsyncMock(spec=["__call__"], side_effect=[ValueError()] * 10)
227+
target = AsyncMock(spec=["__call__"], side_effect=[ValueError()] * 10)
224228
# __name__ is needed by functools.partial.
225229
target.__name__ = "target"
226230

@@ -270,7 +274,7 @@ async def test___init___without_retry_executed(self, sleep):
270274
# check the proper creation of the class
271275
assert retry_._on_error is _some_function
272276

273-
target = mock.AsyncMock(spec=["__call__"], side_effect=[42])
277+
target = AsyncMock(spec=["__call__"], side_effect=[42])
274278
# __name__ is needed by functools.partial.
275279
target.__name__ = "target"
276280

@@ -295,7 +299,7 @@ async def test___init___when_retry_is_executed(self, sleep, uniform):
295299
# check the proper creation of the class
296300
assert retry_._on_error is _some_function
297301

298-
target = mock.AsyncMock(
302+
target = AsyncMock(
299303
spec=["__call__"], side_effect=[ValueError(), ValueError(), 42]
300304
)
301305
# __name__ is needed by functools.partial.

tests/asyncio/test_grpc_helpers_async.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
from unittest import mock
1616

17+
try:
18+
from unittest.mock import AsyncMock
19+
except ImportError:
20+
from mock import AsyncMock
1721
import pytest # noqa: I202
1822

1923
try:
@@ -50,7 +54,7 @@ def trailing_metadata(self):
5054
@pytest.mark.asyncio
5155
async def test_wrap_unary_errors():
5256
grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT)
53-
callable_ = mock.AsyncMock(spec=["__call__"], side_effect=grpc_error)
57+
callable_ = AsyncMock(spec=["__call__"], side_effect=grpc_error)
5458

5559
wrapped_callable = grpc_helpers_async._wrap_unary_errors(callable_)
5660

@@ -170,7 +174,7 @@ async def test_wrap_stream_errors_stream_stream():
170174
async def test_wrap_stream_errors_raised():
171175
grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT)
172176
mock_call = mock.Mock(aio.StreamStreamCall, autospec=True)
173-
mock_call.wait_for_connection = mock.AsyncMock(side_effect=[grpc_error])
177+
mock_call.wait_for_connection = AsyncMock(side_effect=[grpc_error])
174178
multicallable = mock.Mock(return_value=mock_call)
175179

176180
wrapped_callable = grpc_helpers_async._wrap_stream_errors(
@@ -187,7 +191,7 @@ async def test_wrap_stream_errors_read():
187191
grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT)
188192

189193
mock_call = mock.Mock(aio.StreamStreamCall, autospec=True)
190-
mock_call.read = mock.AsyncMock(side_effect=grpc_error)
194+
mock_call.read = AsyncMock(side_effect=grpc_error)
191195
multicallable = mock.Mock(return_value=mock_call)
192196

193197
wrapped_callable = grpc_helpers_async._wrap_stream_errors(
@@ -209,7 +213,7 @@ async def test_wrap_stream_errors_aiter():
209213

210214
mock_call = mock.Mock(aio.StreamStreamCall, autospec=True)
211215
mocked_aiter = mock.Mock(spec=["__anext__"])
212-
mocked_aiter.__anext__ = mock.AsyncMock(
216+
mocked_aiter.__anext__ = AsyncMock(
213217
side_effect=[mock.sentinel.response, grpc_error]
214218
)
215219
mock_call.__aiter__ = mock.Mock(return_value=mocked_aiter)
@@ -232,7 +236,7 @@ async def test_wrap_stream_errors_aiter_non_rpc_error():
232236

233237
mock_call = mock.Mock(aio.StreamStreamCall, autospec=True)
234238
mocked_aiter = mock.Mock(spec=["__anext__"])
235-
mocked_aiter.__anext__ = mock.AsyncMock(
239+
mocked_aiter.__anext__ = AsyncMock(
236240
side_effect=[mock.sentinel.response, non_grpc_error]
237241
)
238242
mock_call.__aiter__ = mock.Mock(return_value=mocked_aiter)
@@ -267,8 +271,8 @@ async def test_wrap_stream_errors_write():
267271
grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT)
268272

269273
mock_call = mock.Mock(aio.StreamStreamCall, autospec=True)
270-
mock_call.write = mock.AsyncMock(side_effect=[None, grpc_error])
271-
mock_call.done_writing = mock.AsyncMock(side_effect=[None, grpc_error])
274+
mock_call.write = AsyncMock(side_effect=[None, grpc_error])
275+
mock_call.done_writing = AsyncMock(side_effect=[None, grpc_error])
272276
multicallable = mock.Mock(return_value=mock_call)
273277

274278
wrapped_callable = grpc_helpers_async._wrap_stream_errors(

tests/asyncio/test_operation_async.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
from unittest import mock
1717

18+
try:
19+
from unittest.mock import AsyncMock
20+
except ImportError:
21+
from mock import AsyncMock
1822
import pytest
1923

2024
try:
@@ -55,9 +59,9 @@ def make_operation_future(client_operations_responses=None):
5559
if client_operations_responses is None:
5660
client_operations_responses = [make_operation_proto()]
5761

58-
refresh = mock.AsyncMock(spec=["__call__"], side_effect=client_operations_responses)
62+
refresh = AsyncMock(spec=["__call__"], side_effect=client_operations_responses)
5963
refresh.responses = client_operations_responses
60-
cancel = mock.AsyncMock(spec=["__call__"])
64+
cancel = AsyncMock(spec=["__call__"])
6165
operation_future = operation_async.AsyncOperation(
6266
client_operations_responses[0],
6367
refresh,

tests/asyncio/test_page_iterator_async.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
import inspect
1616
from unittest import mock
1717

18+
try:
19+
from unittest.mock import AsyncMock
20+
except ImportError:
21+
from mock import AsyncMock
1822
import pytest
1923

2024
from google.api_core import page_iterator_async
@@ -58,7 +62,7 @@ async def test_anext(self):
5862
)
5963

6064
async_iterator = PageAsyncIteratorImpl(None, None)
61-
async_iterator._next_page = mock.AsyncMock(side_effect=[page_1, page_2, None])
65+
async_iterator._next_page = AsyncMock(side_effect=[page_1, page_2, None])
6266

6367
# Consume items and check the state of the async_iterator.
6468
assert async_iterator.num_results == 0
@@ -98,7 +102,7 @@ async def test__page_aiter_increment(self):
98102
page = page_iterator_async.Page(
99103
iterator, ("item",), page_iterator_async._item_to_value_identity
100104
)
101-
iterator._next_page = mock.AsyncMock(side_effect=[page, None])
105+
iterator._next_page = AsyncMock(side_effect=[page, None])
102106

103107
assert iterator.num_results == 0
104108

@@ -136,7 +140,7 @@ async def test__items_aiter(self):
136140
)
137141

138142
iterator = PageAsyncIteratorImpl(None, None)
139-
iterator._next_page = mock.AsyncMock(side_effect=[page1, page2, None])
143+
iterator._next_page = AsyncMock(side_effect=[page1, page2, None])
140144

141145
items_aiter = iterator._items_aiter()
142146

@@ -159,7 +163,7 @@ async def test__items_aiter(self):
159163
@pytest.mark.asyncio
160164
async def test___aiter__(self):
161165
async_iterator = PageAsyncIteratorImpl(None, None)
162-
async_iterator._next_page = mock.AsyncMock(side_effect=[(1, 2), (3,), None])
166+
async_iterator._next_page = AsyncMock(side_effect=[(1, 2), (3,), None])
163167

164168
assert not async_iterator._started
165169

@@ -248,7 +252,7 @@ async def test_iterate(self):
248252
response1 = mock.Mock(items=["a", "b"], next_page_token="1")
249253
response2 = mock.Mock(items=["c"], next_page_token="2")
250254
response3 = mock.Mock(items=["d"], next_page_token="")
251-
method = mock.AsyncMock(side_effect=[response1, response2, response3])
255+
method = AsyncMock(side_effect=[response1, response2, response3])
252256
iterator = page_iterator_async.AsyncGRPCIterator(
253257
mock.sentinel.client, method, request, "items"
254258
)
@@ -271,7 +275,7 @@ async def test_iterate_with_max_results(self):
271275
response1 = mock.Mock(items=["a", "b"], next_page_token="1")
272276
response2 = mock.Mock(items=["c"], next_page_token="2")
273277
response3 = mock.Mock(items=["d"], next_page_token="")
274-
method = mock.AsyncMock(side_effect=[response1, response2, response3])
278+
method = AsyncMock(side_effect=[response1, response2, response3])
275279
iterator = page_iterator_async.AsyncGRPCIterator(
276280
mock.sentinel.client, method, request, "items", max_results=3
277281
)

tests/asyncio/test_rest_streaming_async.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
from typing import List, AsyncIterator
2323
from unittest import mock
2424

25+
try:
26+
from unittest.mock import AsyncMock
27+
except ImportError:
28+
from mock import AsyncMock
2529
import pytest # noqa: I202
2630

2731
import proto
@@ -303,7 +307,7 @@ async def test_next_not_array(response_type):
303307
@pytest.mark.parametrize("response_type", [EchoResponse, httpbody_pb2.HttpBody])
304308
async def test_cancel(response_type):
305309
with mock.patch.object(
306-
ResponseMock, "close", new_callable=mock.AsyncMock
310+
ResponseMock, "close", new_callable=AsyncMock
307311
) as mock_method:
308312
resp = ResponseMock(responses=[], response_cls=response_type)
309313
itr = rest_streaming_async.AsyncResponseIterator(resp, response_type)
@@ -315,7 +319,7 @@ async def test_cancel(response_type):
315319
@pytest.mark.parametrize("response_type", [EchoResponse, httpbody_pb2.HttpBody])
316320
async def test_iterator_as_context_manager(response_type):
317321
with mock.patch.object(
318-
ResponseMock, "close", new_callable=mock.AsyncMock
322+
ResponseMock, "close", new_callable=AsyncMock
319323
) as mock_method:
320324
resp = ResponseMock(responses=[], response_cls=response_type)
321325
async with rest_streaming_async.AsyncResponseIterator(resp, response_type):

tests/unit/retry/test_retry_unary.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import re
1717
from unittest import mock
1818

19+
try:
20+
from unittest.mock import AsyncMock
21+
except ImportError:
22+
from mock import AsyncMock
1923
import pytest
2024

2125
from google.api_core import exceptions
@@ -102,7 +106,7 @@ def test_retry_target_non_retryable_error(utcnow, sleep):
102106
@pytest.mark.asyncio
103107
async def test_retry_target_warning_for_retry(utcnow, sleep):
104108
predicate = retry.if_exception_type(ValueError)
105-
target = mock.AsyncMock(spec=["__call__"])
109+
target = AsyncMock(spec=["__call__"])
106110

107111
with pytest.warns(Warning) as exc_info:
108112
# Note: predicate is just a filler and doesn't affect the test

0 commit comments

Comments
 (0)