Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bugfix/126 coroutine deprecated warnings #134

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 16 additions & 23 deletions asynctest/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,7 @@ def _run_test_method(self, method):
if asyncio.iscoroutine(result):
self.loop.run_until_complete(result)

@asyncio.coroutine
def doCleanups(self):
async def doCleanups(self):
"""
Execute all cleanup functions. Normally called for you after tearDown.
"""
Expand All @@ -363,7 +362,7 @@ def doCleanups(self):
function, args, kwargs = self._cleanups.pop()
with outcome.testPartExecutor(self):
if asyncio.iscoroutinefunction(function):
yield from function(*args, **kwargs)
await function(*args, **kwargs)
else:
function(*args, **kwargs)

Expand All @@ -377,49 +376,45 @@ def addCleanup(self, function, *args, **kwargs):
"""
return super().addCleanup(function, *args, **kwargs)

@asyncio.coroutine
def assertAsyncRaises(self, exception, awaitable):
async def assertAsyncRaises(self, exception, awaitable):
"""
Test that an exception of type ``exception`` is raised when an
exception is raised when awaiting ``awaitable``, a future or coroutine.

:see: :meth:`unittest.TestCase.assertRaises()`
"""
with self.assertRaises(exception):
return (yield from awaitable)
return await awaitable

@asyncio.coroutine
def assertAsyncRaisesRegex(self, exception, regex, awaitable):
async def assertAsyncRaisesRegex(self, exception, regex, awaitable):
"""
Like :meth:`assertAsyncRaises()` but also tests that ``regex`` matches
on the string representation of the raised exception.

:see: :meth:`unittest.TestCase.assertRaisesRegex()`
"""
with self.assertRaisesRegex(exception, regex):
return (yield from awaitable)
return await awaitable

@asyncio.coroutine
def assertAsyncWarns(self, warning, awaitable):
async def assertAsyncWarns(self, warning, awaitable):
"""
Test that a warning is triggered when awaiting ``awaitable``, a future
or a coroutine.

:see: :meth:`unittest.TestCase.assertWarns()`
"""
with self.assertWarns(warning):
return (yield from awaitable)
return await awaitable

@asyncio.coroutine
def assertAsyncWarnsRegex(self, warning, regex, awaitable):
async def assertAsyncWarnsRegex(self, warning, regex, awaitable):
"""
Like :meth:`assertAsyncWarns()` but also tests that ``regex`` matches
on the message of the triggered warning.

:see: :meth:`unittest.TestCase.assertWarnsRegex()`
"""
with self.assertWarnsRegex(warning, regex):
return (yield from awaitable)
return await awaitable


class FunctionTestCase(TestCase, unittest.FunctionTestCase):
Expand All @@ -441,8 +436,7 @@ def _init_loop(self):
self.loop.time = functools.wraps(self.loop.time)(lambda: self._time)
self._time = 0

@asyncio.coroutine
def advance(self, seconds):
async def advance(self, seconds):
"""
Fast forward time by a number of ``seconds``.

Expand All @@ -463,7 +457,7 @@ def advance(self, seconds):
raise ValueError(
'Cannot go back in time ({} seconds)'.format(seconds))

yield from self._drain_loop()
await self._drain_loop()

target_time = self._time + seconds
while True:
Expand All @@ -472,26 +466,25 @@ def advance(self, seconds):
break

self._time = next_time
yield from self._drain_loop()
await self._drain_loop()

self._time = target_time
yield from self._drain_loop()
await self._drain_loop()

def _next_scheduled(self):
try:
return self.loop._scheduled[0]._when
except IndexError:
return None

@asyncio.coroutine
def _drain_loop(self):
async def _drain_loop(self):
while True:
next_time = self._next_scheduled()
if not self.loop._ready and (next_time is None or
next_time > self._time):
break

yield from asyncio.sleep(0)
await asyncio.sleep(0)
self.loop._TestCase_asynctest_ran = True


Expand Down
5 changes: 2 additions & 3 deletions asynctest/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
import asyncio


@asyncio.coroutine
def exhaust_callbacks(loop):
async def exhaust_callbacks(loop):
"""
Run the loop until all ready callbacks are executed.

Expand All @@ -21,4 +20,4 @@ def exhaust_callbacks(loop):
:param loop: event loop
"""
while loop._ready:
yield from asyncio.sleep(0, loop=loop)
await asyncio.sleep(0, loop=loop)
55 changes: 31 additions & 24 deletions asynctest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def _get_async_iter(mock):

See: https://www.python.org/dev/peps/pep-0525/#id23
"""
def __aiter__():
def callback():
return_value = mock.__aiter__._mock_return_value
if return_value is DEFAULT:
iterator = iter([])
Expand All @@ -82,7 +82,11 @@ def __aiter__():
return _AsyncIterator(iterator)

if asyncio.iscoroutinefunction(mock.__aiter__):
return asyncio.coroutine(__aiter__)
async def __aiter__():
return await callback()
else:
def __aiter__():
return callback()

return __aiter__

Expand Down Expand Up @@ -369,8 +373,7 @@ class Mock(unittest.mock.Mock, metaclass=MockMetaMixin):
For instance:

>>> class Foo:
... @asyncio.coroutine
... def foo(self):
... async def foo(self):
... pass
...
... def bar(self):
Expand Down Expand Up @@ -430,8 +433,7 @@ def __init__(self, mock):
self._mock = mock
self._condition = None

@asyncio.coroutine
def wait(self, skip=0):
async def wait(self, skip=0):
"""
Wait for await.

Expand All @@ -442,10 +444,9 @@ def wait(self, skip=0):
def predicate(mock):
return mock.await_count > skip

return (yield from self.wait_for(predicate))
return await self.wait_for(predicate)

@asyncio.coroutine
def wait_next(self, skip=0):
async def wait_next(self, skip=0):
"""
Wait for the next await.

Expand All @@ -462,10 +463,9 @@ def wait_next(self, skip=0):
def predicate(mock):
return mock.await_count > await_count + skip

return (yield from self.wait_for(predicate))
return await self.wait_for(predicate)

@asyncio.coroutine
def wait_for(self, predicate):
async def wait_for(self, predicate):
"""
Wait for a given predicate to become True.

Expand All @@ -476,21 +476,20 @@ def wait_for(self, predicate):
condition = self._get_condition()

try:
yield from condition.acquire()
await condition.acquire()

def _predicate():
return predicate(self._mock)

return (yield from condition.wait_for(_predicate))
return await condition.wait_for(_predicate)
finally:
condition.release()

@asyncio.coroutine
def _notify(self):
async def _notify(self):
condition = self._get_condition()

try:
yield from condition.acquire()
await condition.acquire()
condition.notify_all()
finally:
condition.release()
Expand Down Expand Up @@ -582,31 +581,37 @@ def __init__(self, *args, **kwargs):
self.__dict__['_mock_await_args_list'] = unittest.mock._CallList()

def _mock_call(_mock_self, *args, **kwargs):
"""Note:
This will return a coroutine that must be awaited. Not awaiting it
will result in a :class:`RuntimeWarning`_.
"""
async def handle_error(error):
return await _raise(error)

try:
result = super()._mock_call(*args, **kwargs)
except StopIteration as e:
side_effect = _mock_self.side_effect
if side_effect is not None and not callable(side_effect):
raise

result = asyncio.coroutine(_raise)(e)
result = handle_error(e)
except BaseException as e:
result = asyncio.coroutine(_raise)(e)
result = handle_error(e)

_call = _mock_self.call_args

@asyncio.coroutine
def proxy():
async def proxy():
try:
if inspect.isawaitable(result):
return (yield from result)
return await result
else:
return result
finally:
_mock_self.await_count += 1
_mock_self.await_args = _call
_mock_self.await_args_list.append(_call)
yield from _mock_self.awaited._notify()
await _mock_self.awaited._notify()

return proxy()

Expand Down Expand Up @@ -1005,7 +1010,9 @@ def patched_generator(*args, **kwargs):

if is_coroutine_func:
# asyncio.iscoroutinefunction() returns True
patched = asyncio.coroutine(patched)
async def async_patched(*args, **kwargs):
return patched(*args, **kwargs)

else:
patched = patched_factory

Expand Down
21 changes: 13 additions & 8 deletions test/test_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,22 @@ def test_subclass(self, klass):


@inject_class
class _Test_called_coroutine:
class _Test_called_coroutine(asynctest.TestCase):
# Ensure that an object mocking as a coroutine works
def test_returns_coroutine(self, klass):
async def test_returns_coroutine(self, klass):
mock = klass()

coro = mock()
# Suppress debug warning about non-running coroutine
if isinstance(coro, asyncio.coroutines.CoroWrapper):
coro.gen = None

self.assertTrue(asyncio.iscoroutine(coro))
try:
# Suppress debug warning about non-running coroutine
if isinstance(coro, asyncio.coroutines.CoroWrapper):
coro.gen = None

self.assertTrue(asyncio.iscoroutine(coro))
finally:
# Prevent runtime warning
await coro

def test_returns_coroutine_from_return_value(self, klass):
mock = klass()
Expand Down Expand Up @@ -769,11 +774,11 @@ def test_assert_not_awaited(self):
with self.assertRaises(AssertionError):
mock.assert_not_awaited()

def test_create_autospec_on_coroutine_and_using_assert_methods(self):
async def test_create_autospec_on_coroutine_and_using_assert_methods(self):
mock = asynctest.create_autospec(Test.a_coroutine_with_args)
mock.assert_not_awaited()

yield from mock("arg0", "arg1", "arg2")
await mock("arg0", "arg1", "arg2")
mock.assert_awaited() # calls assert not awaited
mock.assert_awaited_once()
mock.assert_awaited_with("arg0", "arg1", "arg2")
Expand Down