Blob Blame History Raw
From c5eb00d4151e204cab32a3026583326745054419 Mon Sep 17 00:00:00 2001
From: Stefan Tjarks <stefan.tjarks@eventbase.com>
Date: Tue, 17 Jul 2018 13:53:05 -0700
Subject: [PATCH] Drop support for Python 3.4 to support aiohttp>3.3

aiohttp dropped support for Python 3.4 and with it `asyncio.coroutine`
decorated generators.
To support latest aiohttp Python 3.4 support is dropped and all notion
of `asyncio.coroutine` is replaced with `async def`.

Signed-off-by: Randy Barlow <randy@electronsweatshop.com>
---
 .coveragerc-py34 => .coveragerc-py35          |   0
 .travis.yml                                   |   1 -
 Makefile                                      |  10 +-
 README.rst                                    |  17 +-
 backoff/_async.py                             |  33 ++--
 .../test_backoff_async.py                     | 167 +++++++-----------
 6 files changed, 84 insertions(+), 144 deletions(-)
 rename .coveragerc-py34 => .coveragerc-py35 (100%)
 rename tests/{python34 => python35}/test_backoff_async.py (82%)

diff --git a/.coveragerc-py34 b/.coveragerc-py35
similarity index 100%
rename from .coveragerc-py34
rename to .coveragerc-py35
diff --git a/.travis.yml b/.travis.yml
index 1c0c7fd..b5cb8de 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@ language: python
 python:
   - "2.6"
   - "2.7"
-  - "3.4"
   - "3.5"
   - "3.6"
 matrix:
diff --git a/Makefile b/Makefile
index 66526bd..eb5f188 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 PY_VERSION := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1)))
 PY_MAJOR := $(word 1,${PY_VERSION})
 PY_MINOR := $(word 2,${PY_VERSION})
-PY_GTE_34 = $(shell echo $(PY_MAJOR).$(PY_MINOR)\>=3.4 | bc)
+PY_GTE_35 = $(shell echo $(PY_MAJOR).$(PY_MINOR)\>=3.5 | bc)
 PY_GTE_27 = $(shell echo $(PY_MAJOR).$(PY_MINOR)\>=2.7 | bc)
 
 
@@ -18,10 +18,10 @@ pep8:
 	@pep8 backoff tests
 
 flake8:
-ifeq ($(PY_GTE_34),1)
+ifeq ($(PY_GTE_35),1)
 	@flake8 backoff tests
 else ifeq ($(PY_GTE_27),1)
-	@flake8 --exclude tests/python34,backoff/_async.py backoff tests
+	@flake8 --exclude tests/python35,backoff/_async.py backoff tests
 else
 	@echo 'Not running flake8 for Python < 2.7'
 endif
@@ -32,8 +32,8 @@ clean:
 	@rm -rf build dist .coverage MANIFEST
 
 test: clean
-ifeq ($(PY_GTE_34),1)
-	@PYTHONPATH=. py.test --cov-config .coveragerc-py34 --cov backoff tests
+ifeq ($(PY_GTE_35),1)
+	@PYTHONPATH=. py.test --cov-config .coveragerc-py35 --cov backoff tests
 else
 	@PYTHONPATH=. py.test --cov-config .coveragerc-py2 --cov backoff tests/test_*.py
 endif
diff --git a/README.rst b/README.rst
index ee535e7..fee5723 100644
--- a/README.rst
+++ b/README.rst
@@ -284,22 +284,7 @@ On Python 3.5 and above with ``async def`` and ``await`` syntax:
             async with session.get(url) as response:
                 return await response.text()
 
-In case you use Python 3.4 you can use `@asyncio.coroutine` and `yield from`:
-
-.. code-block:: python
-
-    @backoff.on_exception(backoff.expo, aiohttp.ClientError, max_time=60)
-    @asyncio.coroutine
-    def get_url_py34(url):
-        with aiohttp.ClientSession() as session:
-            response = yield from session.get(url)
-            try:
-                return (yield from response.text())
-            except Exception:
-                response.close()
-                raise
-            finally:
-                yield from response.release()
+Python 3.4 is not supported.
 
 Logging configuration
 ---------------------
diff --git a/backoff/_async.py b/backoff/_async.py
index e1b70d0..2cd33a8 100644
--- a/backoff/_async.py
+++ b/backoff/_async.py
@@ -20,8 +20,7 @@ def _ensure_coroutines(coros_or_funcs):
     return [_ensure_coroutine(f) for f in coros_or_funcs]
 
 
-@asyncio.coroutine
-def _call_handlers(hdlrs, target, args, kwargs, tries, elapsed, **extra):
+async def _call_handlers(hdlrs, target, args, kwargs, tries, elapsed, **extra):
     details = {
         'target': target,
         'args': args,
@@ -31,7 +30,7 @@ def _call_handlers(hdlrs, target, args, kwargs, tries, elapsed, **extra):
     }
     details.update(extra)
     for hdlr in hdlrs:
-        yield from hdlr(details)
+        await hdlr(details)
 
 
 def retry_predicate(target, wait_gen, predicate,
@@ -49,8 +48,7 @@ def retry_predicate(target, wait_gen, predicate,
     assert asyncio.iscoroutinefunction(target)
 
     @functools.wraps(target)
-    @asyncio.coroutine
-    def retry(*args, **kwargs):
+    async def retry(*args, **kwargs):
 
         # change names because python 2.x doesn't have nonlocal
         max_tries_ = _maybe_call(max_tries)
@@ -64,20 +62,20 @@ def retry_predicate(target, wait_gen, predicate,
             elapsed = _total_seconds(datetime.datetime.now() - start)
             details = (target, args, kwargs, tries, elapsed)
 
-            ret = yield from target(*args, **kwargs)
+            ret = await target(*args, **kwargs)
             if predicate(ret):
                 max_tries_exceeded = (tries == max_tries_)
                 max_time_exceeded = (max_time_ is not None and
                                      elapsed >= max_time_)
 
                 if max_tries_exceeded or max_time_exceeded:
-                    yield from _call_handlers(
+                    await _call_handlers(
                         giveup_hdlrs, *details, value=ret)
                     break
 
                 seconds = _next_wait(wait, jitter, elapsed, max_time_)
 
-                yield from _call_handlers(
+                await _call_handlers(
                     backoff_hdlrs, *details, value=ret, wait=seconds)
 
                 # Note: there is no convenient way to pass explicit event
@@ -89,10 +87,10 @@ def retry_predicate(target, wait_gen, predicate,
                 # See for details:
                 #   <https://groups.google.com/forum/#!topic/python-tulip/yF9C-rFpiKk>
                 #   <https://bugs.python.org/issue28613>
-                yield from asyncio.sleep(seconds)
+                await asyncio.sleep(seconds)
                 continue
             else:
-                yield from _call_handlers(success_hdlrs, *details, value=ret)
+                await _call_handlers(success_hdlrs, *details, value=ret)
                 break
 
         return ret
@@ -114,8 +112,7 @@ def retry_exception(target, wait_gen, exception,
     assert not asyncio.iscoroutinefunction(jitter)
 
     @functools.wraps(target)
-    @asyncio.coroutine
-    def retry(*args, **kwargs):
+    async def retry(*args, **kwargs):
         # change names because python 2.x doesn't have nonlocal
         max_tries_ = _maybe_call(max_tries)
         max_time_ = _maybe_call(max_time)
@@ -129,20 +126,20 @@ def retry_exception(target, wait_gen, exception,
             details = (target, args, kwargs, tries, elapsed)
 
             try:
-                ret = yield from target(*args, **kwargs)
+                ret = await target(*args, **kwargs)
             except exception as e:
-                giveup_result = yield from giveup(e)
+                giveup_result = await giveup(e)
                 max_tries_exceeded = (tries == max_tries_)
                 max_time_exceeded = (max_time_ is not None and
                                      elapsed >= max_time_)
 
                 if giveup_result or max_tries_exceeded or max_time_exceeded:
-                    yield from _call_handlers(giveup_hdlrs, *details)
+                    await _call_handlers(giveup_hdlrs, *details)
                     raise
 
                 seconds = _next_wait(wait, jitter, elapsed, max_time_)
 
-                yield from _call_handlers(
+                await _call_handlers(
                     backoff_hdlrs, *details, wait=seconds)
 
                 # Note: there is no convenient way to pass explicit event
@@ -154,9 +151,9 @@ def retry_exception(target, wait_gen, exception,
                 # See for details:
                 #   <https://groups.google.com/forum/#!topic/python-tulip/yF9C-rFpiKk>
                 #   <https://bugs.python.org/issue28613>
-                yield from asyncio.sleep(seconds)
+                await asyncio.sleep(seconds)
             else:
-                yield from _call_handlers(success_hdlrs, *details)
+                await _call_handlers(success_hdlrs, *details)
 
                 return ret
     return retry
diff --git a/tests/python34/test_backoff_async.py b/tests/python35/test_backoff_async.py
similarity index 82%
rename from tests/python34/test_backoff_async.py
rename to tests/python35/test_backoff_async.py
index 0917c6b..c1a30f8 100644
--- a/tests/python34/test_backoff_async.py
+++ b/tests/python35/test_backoff_async.py
@@ -8,47 +8,41 @@ import random
 from tests.common import _log_hdlrs, _save_target
 
 
-@pytest.mark.asyncio
-def test_on_predicate(monkeypatch):
+async def test_on_predicate(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     @backoff.on_predicate(backoff.expo)
-    @asyncio.coroutine
-    def return_true(log, n):
+    async def return_true(log, n):
         val = (len(log) == n - 1)
         log.append(val)
         return val
 
     log = []
-    ret = yield from return_true(log, 3)
+    ret = await return_true(log, 3)
     assert ret is True
     assert 3 == len(log)
 
 
-@pytest.mark.asyncio
-def test_on_predicate_max_tries(monkeypatch):
+async def test_on_predicate_max_tries(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     @backoff.on_predicate(backoff.expo, jitter=None, max_tries=3)
-    @asyncio.coroutine
-    def return_true(log, n):
+    async def return_true(log, n):
         val = (len(log) == n)
         log.append(val)
         return val
 
     log = []
-    ret = yield from return_true(log, 10)
+    ret = await return_true(log, 10)
     assert ret is False
     assert 3 == len(log)
 
 
-@pytest.mark.asyncio
-def test_on_exception(monkeypatch):
+async def test_on_exception(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     @backoff.on_exception(backoff.expo, KeyError)
-    @asyncio.coroutine
-    def keyerror_then_true(log, n):
+    async def keyerror_then_true(log, n):
         if len(log) == n:
             return True
         e = KeyError()
@@ -56,17 +50,15 @@ def test_on_exception(monkeypatch):
         raise e
 
     log = []
-    assert (yield from keyerror_then_true(log, 3)) is True
+    assert (await keyerror_then_true(log, 3)) is True
     assert 3 == len(log)
 
 
-@pytest.mark.asyncio
-def test_on_exception_tuple(monkeypatch):
+async def test_on_exception_tuple(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     @backoff.on_exception(backoff.expo, (KeyError, ValueError))
-    @asyncio.coroutine
-    def keyerror_valueerror_then_true(log):
+    async def keyerror_valueerror_then_true(log):
         if len(log) == 2:
             return True
         if len(log) == 0:
@@ -77,19 +69,17 @@ def test_on_exception_tuple(monkeypatch):
         raise e
 
     log = []
-    assert (yield from keyerror_valueerror_then_true(log)) is True
+    assert (await keyerror_valueerror_then_true(log)) is True
     assert 2 == len(log)
     assert isinstance(log[0], KeyError)
     assert isinstance(log[1], ValueError)
 
 
-@pytest.mark.asyncio
-def test_on_exception_max_tries(monkeypatch):
+async def test_on_exception_max_tries(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     @backoff.on_exception(backoff.expo, KeyError, jitter=None, max_tries=3)
-    @asyncio.coroutine
-    def keyerror_then_true(log, n, foo=None):
+    async def keyerror_then_true(log, n, foo=None):
         if len(log) == n:
             return True
         e = KeyError()
@@ -98,13 +88,12 @@ def test_on_exception_max_tries(monkeypatch):
 
     log = []
     with pytest.raises(KeyError):
-        yield from keyerror_then_true(log, 10, foo="bar")
+        await keyerror_then_true(log, 10, foo="bar")
 
     assert 3 == len(log)
 
 
-@pytest.mark.asyncio
-def test_on_exception_success_random_jitter(monkeypatch):
+async def test_on_exception_success_random_jitter(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
@@ -117,13 +106,12 @@ def test_on_exception_success_random_jitter(monkeypatch):
                           jitter=backoff.random_jitter,
                           factor=0.5)
     @_save_target
-    @asyncio.coroutine
-    def succeeder(*args, **kwargs):
+    async def succeeder(*args, **kwargs):
         # succeed after we've backed off twice
         if len(log['backoff']) < 2:
             raise ValueError("catch me")
 
-    yield from succeeder(1, 2, 3, foo=1, bar=2)
+    await succeeder(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -135,8 +123,7 @@ def test_on_exception_success_random_jitter(monkeypatch):
         assert details['wait'] >= 0.5 * 2 ** i
 
 
-@pytest.mark.asyncio
-def test_on_exception_success_full_jitter(monkeypatch):
+async def test_on_exception_success_full_jitter(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
@@ -149,13 +136,12 @@ def test_on_exception_success_full_jitter(monkeypatch):
                           jitter=backoff.full_jitter,
                           factor=0.5)
     @_save_target
-    @asyncio.coroutine
-    def succeeder(*args, **kwargs):
+    async def succeeder(*args, **kwargs):
         # succeed after we've backed off twice
         if len(log['backoff']) < 2:
             raise ValueError("catch me")
 
-    yield from succeeder(1, 2, 3, foo=1, bar=2)
+    await succeeder(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -167,8 +153,7 @@ def test_on_exception_success_full_jitter(monkeypatch):
         assert details['wait'] <= 0.5 * 2 ** i
 
 
-@pytest.mark.asyncio
-def test_on_exception_success():
+async def test_on_exception_success():
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
 
     @backoff.on_exception(backoff.constant,
@@ -179,13 +164,12 @@ def test_on_exception_success():
                           jitter=lambda: 0,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
     def succeeder(*args, **kwargs):
         # succeed after we've backed off twice
         if len(log['backoff']) < 2:
             raise ValueError("catch me")
 
-    yield from succeeder(1, 2, 3, foo=1, bar=2)
+    await succeeder(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -211,8 +195,7 @@ def test_on_exception_success():
                        'tries': 3}
 
 
-@pytest.mark.asyncio
-def test_on_exception_giveup():
+async def test_on_exception_giveup():
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
 
     @backoff.on_exception(backoff.constant,
@@ -224,12 +207,11 @@ def test_on_exception_giveup():
                           jitter=lambda: 0,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def exceptor(*args, **kwargs):
+    async def exceptor(*args, **kwargs):
         raise ValueError("catch me")
 
     with pytest.raises(ValueError):
-        yield from exceptor(1, 2, 3, foo=1, bar=2)
+        await exceptor(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice and giving up once
     assert len(log['success']) == 0
@@ -245,8 +227,7 @@ def test_on_exception_giveup():
                        'tries': 3}
 
 
-@pytest.mark.asyncio
-def test_on_exception_giveup_predicate(monkeypatch):
+async def test_on_exception_giveup_predicate(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     def on_baz(e):
@@ -257,22 +238,19 @@ def test_on_exception_giveup_predicate(monkeypatch):
     @backoff.on_exception(backoff.constant,
                           ValueError,
                           giveup=on_baz)
-    @asyncio.coroutine
-    def foo_bar_baz():
+    async def foo_bar_baz():
         raise ValueError(vals.pop())
 
     with pytest.raises(ValueError):
-        yield from foo_bar_baz()
+        await foo_bar_baz()
 
     assert not vals
 
 
-@pytest.mark.asyncio
-def test_on_exception_giveup_coro(monkeypatch):
+async def test_on_exception_giveup_coro(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
-    @asyncio.coroutine
-    def on_baz(e):
+    async def on_baz(e):
         return str(e) == "baz"
 
     vals = ["baz", "bar", "foo"]
@@ -280,18 +258,16 @@ def test_on_exception_giveup_coro(monkeypatch):
     @backoff.on_exception(backoff.constant,
                           ValueError,
                           giveup=on_baz)
-    @asyncio.coroutine
-    def foo_bar_baz():
+    async def foo_bar_baz():
         raise ValueError(vals.pop())
 
     with pytest.raises(ValueError):
-        yield from foo_bar_baz()
+        await foo_bar_baz()
 
     assert not vals
 
 
-@pytest.mark.asyncio
-def test_on_predicate_success():
+async def test_on_predicate_success():
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
 
     @backoff.on_predicate(backoff.constant,
@@ -301,12 +277,11 @@ def test_on_predicate_success():
                           jitter=lambda: 0,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def success(*args, **kwargs):
+    async def success(*args, **kwargs):
         # succeed after we've backed off twice
         return len(log['backoff']) == 2
 
-    yield from success(1, 2, 3, foo=1, bar=2)
+    await success(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -334,8 +309,7 @@ def test_on_predicate_success():
                        'value': True}
 
 
-@pytest.mark.asyncio
-def test_on_predicate_giveup():
+async def test_on_predicate_giveup():
     log, log_success, log_backoff, log_giveup = _log_hdlrs()
 
     @backoff.on_predicate(backoff.constant,
@@ -346,11 +320,10 @@ def test_on_predicate_giveup():
                           jitter=lambda: 0,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def emptiness(*args, **kwargs):
+    async def emptiness(*args, **kwargs):
         pass
 
-    yield from emptiness(1, 2, 3, foo=1, bar=2)
+    await emptiness(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice and giving up once
     assert len(log['success']) == 0
@@ -367,8 +340,7 @@ def test_on_predicate_giveup():
                        'value': None}
 
 
-@pytest.mark.asyncio
-def test_on_predicate_iterable_handlers():
+async def test_on_predicate_iterable_handlers():
     hdlrs = [_log_hdlrs() for _ in range(3)]
 
     @backoff.on_predicate(backoff.constant,
@@ -379,11 +351,10 @@ def test_on_predicate_iterable_handlers():
                           jitter=lambda: 0,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def emptiness(*args, **kwargs):
+    async def emptiness(*args, **kwargs):
         pass
 
-    yield from emptiness(1, 2, 3, foo=1, bar=2)
+    await emptiness(1, 2, 3, foo=1, bar=2)
 
     for i in range(3):
         assert len(hdlrs[i][0]['success']) == 0
@@ -402,8 +373,7 @@ def test_on_predicate_iterable_handlers():
 
 # To maintain backward compatibility,
 # on_predicate should support 0-argument jitter function.
-@pytest.mark.asyncio
-def test_on_exception_success_0_arg_jitter(monkeypatch):
+async def test_on_exception_success_0_arg_jitter(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
     monkeypatch.setattr('random.random', lambda: 0)
 
@@ -417,13 +387,12 @@ def test_on_exception_success_0_arg_jitter(monkeypatch):
                           jitter=random.random,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def succeeder(*args, **kwargs):
+    async def succeeder(*args, **kwargs):
         # succeed after we've backed off twice
         if len(log['backoff']) < 2:
             raise ValueError("catch me")
 
-    yield from succeeder(1, 2, 3, foo=1, bar=2)
+    await succeeder(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -451,8 +420,7 @@ def test_on_exception_success_0_arg_jitter(monkeypatch):
 
 # To maintain backward compatibility,
 # on_predicate should support 0-argument jitter function.
-@pytest.mark.asyncio
-def test_on_predicate_success_0_arg_jitter(monkeypatch):
+async def test_on_predicate_success_0_arg_jitter(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
     monkeypatch.setattr('random.random', lambda: 0)
 
@@ -465,12 +433,11 @@ def test_on_predicate_success_0_arg_jitter(monkeypatch):
                           jitter=random.random,
                           interval=0)
     @_save_target
-    @asyncio.coroutine
-    def success(*args, **kwargs):
+    async def success(*args, **kwargs):
         # succeed after we've backed off twice
         return len(log['backoff']) == 2
 
-    yield from success(1, 2, 3, foo=1, bar=2)
+    await success(1, 2, 3, foo=1, bar=2)
 
     # we try 3 times, backing off twice before succeeding
     assert len(log['success']) == 1
@@ -498,8 +465,7 @@ def test_on_predicate_success_0_arg_jitter(monkeypatch):
                        'value': True}
 
 
-@pytest.mark.asyncio
-def test_on_exception_callable_max_tries(monkeypatch):
+async def test_on_exception_callable_max_tries(monkeypatch):
     monkeypatch.setattr('asyncio.sleep', asyncio.coroutine(lambda x: None))
 
     def lookup_max_tries():
@@ -510,19 +476,17 @@ def test_on_exception_callable_max_tries(monkeypatch):
     @backoff.on_exception(backoff.constant,
                           ValueError,
                           max_tries=lookup_max_tries)
-    @asyncio.coroutine
-    def exceptor():
+    async def exceptor():
         log.append(True)
         raise ValueError()
 
     with pytest.raises(ValueError):
-        yield from exceptor()
+        await exceptor()
 
     assert len(log) == 3
 
 
-@pytest.mark.asyncio
-def test_on_exception_callable_gen_kwargs():
+async def test_on_exception_callable_gen_kwargs():
 
     def lookup_foo():
         return "foo"
@@ -539,25 +503,22 @@ def test_on_exception_callable_gen_kwargs():
                           max_tries=2,
                           foo=lookup_foo,
                           bar="bar")
-    @asyncio.coroutine
-    def exceptor():
+    async def exceptor():
         raise ValueError("aah")
 
     with pytest.raises(ValueError):
-        yield from exceptor()
+        await exceptor()
 
 
-@pytest.mark.asyncio
-def test_on_exception_coro_cancelling(event_loop):
+async def test_on_exception_coro_cancelling(event_loop):
     sleep_started_event = asyncio.Event()
 
     @backoff.on_predicate(backoff.expo)
-    @asyncio.coroutine
-    def coro():
+    async def coro():
         sleep_started_event.set()
 
         try:
-            yield from asyncio.sleep(10)
+            await asyncio.sleep(10)
         except asyncio.CancelledError:
             return True
 
@@ -565,17 +526,16 @@ def test_on_exception_coro_cancelling(event_loop):
 
     task = event_loop.create_task(coro())
 
-    yield from sleep_started_event.wait()
+    await sleep_started_event.wait()
 
     task.cancel()
 
-    assert (yield from task)
+    assert (await task)
 
 
-@pytest.mark.asyncio
-def test_on_exception_on_regular_function():
+async def test_on_exception_on_regular_function():
     # Force this function to be a running coroutine.
-    yield from asyncio.sleep(0)
+    await asyncio.sleep(0)
 
     with pytest.raises(TypeError) as excinfo:
         @backoff.on_exception(backoff.expo, ValueError)
@@ -584,10 +544,9 @@ def test_on_exception_on_regular_function():
     assert "applied to a regular function" in str(excinfo.value)
 
 
-@pytest.mark.asyncio
-def test_on_predicate_on_regular_function():
+async def test_on_predicate_on_regular_function():
     # Force this function to be a running coroutine.
-    yield from asyncio.sleep(0)
+    await asyncio.sleep(0)
 
     with pytest.raises(TypeError) as excinfo:
         @backoff.on_predicate(backoff.expo)
-- 
2.18.0