diff --git a/README.rst b/README.rst index bdee5adb..b5769dca 100644 --- a/README.rst +++ b/README.rst @@ -1,12 +1,8 @@ pytest-asyncio: pytest support for asyncio ========================================== -.. image:: https://img.shields.io/pypi/v/pytest-asyncio.svg - :target: https://pypi.python.org/pypi/pytest-asyncio -.. image:: https://travis-ci.org/pytest-dev/pytest-asyncio.svg?branch=master - :target: https://travis-ci.org/pytest-dev/pytest-asyncio -.. image:: https://coveralls.io/repos/pytest-dev/pytest-asyncio/badge.svg - :target: https://coveralls.io/r/pytest-dev/pytest-asyncio +.. image:: https://travis-ci.org/malinoff/pytest-asyncio.svg?branch=master + :target: https://travis-ci.org/malinoff/pytest-asyncio pytest-asyncio is an Apache2 licensed library, written in Python, for testing asyncio code with pytest. @@ -15,30 +11,115 @@ asyncio code is usually written in the form of coroutines, which makes it slightly more difficult to test using normal testing tools. pytest-asyncio provides useful fixtures and markers to make testing easier. +Original readme can be found in original `pytest-asyncio`_ repository. + +This fork completely changes how ``pytest-asyncio`` works with coroutine-based +tests and loops: + + * No more closing the loop after each test coroutine function. It's up + to the developer to choose when the loop is closed. + + * The use of global event loop is now forbidden by default. You can accept + it by providing ``accept_global_loop=True`` to ``@asyncio.mark.asyncio`` + + * No more implicit loops defined by the plugin. In order to use a loop, + you must explicitly create and request ``loop`` fixture, otherwise + the plugin will raise a ``MissingLoopFixture`` exception. This fixture + can be named anything, but requires to return an instance of + ``asyncio.AbstractEventLoop``. There is one exception: if + ``accept_global_loop`` is ``True`` AND a ``loop`` fixture is not requested, + the plugin will use the global loop. + +The advantages are: + + * You do not rely on implicit event loops created by the plugin. + Want to use ``concurrent.futures.ThreadPoolExecutor``? Easy! + + .. code-block:: python + + @pytest.yield_fixture + def threadpooled_loop(): + loop = asyncio.get_event_loop_policy().new_event_loop() + loop.set_default_executor(concurrent.futures.ThreadPoolExecutor()) + yield loop + loop.close() + + * Lifetimes of loop fixtures can be expanded to ``module`` or ``session`` + scopes easily (in the original plugin it is not possible because the loop + closes after each test coroutine function): + + .. code-block:: python + + @pytest.yield_fixture(scope='module') + def loop(): + ... + +You can also create coroutine-based fixtures: + + .. code-block:: python + + @pytest_asyncio.async_fixture + async def async_fixture(loop): + await asyncio.sleep(1, loop=loop) + return 'something' + +By default, using a global asyncio loop is forbidden by default, similarly +to the test coroutine functions. To accept it, provide ``accept_global_loop=True`` +to the ``@pytest_asyncio.async_fixture`` decorator. + +Examples compared to the original examples: + .. code-block:: python + # Original @pytest.mark.asyncio async def test_some_asyncio_code(): res = await library.do_something() assert b'expected result' == res + # Fork + import asyncio + @pytest.yield_fixture + def loop(): + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + @pytest.mark.asyncio + async def test_some_asyncio_code(loop): + res = await library.do_something(loop=loop) + assert b'expected result' == res + or, if you're using the pre-Python 3.5 syntax: .. code-block:: python + # Original @pytest.mark.asyncio def test_some_asyncio_code(): res = yield from library.do_something() assert b'expected result' == res + # Fork + import asyncio + @pytest.fixture + def loop(): + return asyncio.get_event_loop_policy().new_event_loop() + + @pytest.mark.asyncio + async def test_some_asyncio_code(loop): + res = await library.do_something(loop=loop) + assert b'expected result' == res + pytest-asyncio has been strongly influenced by pytest-tornado_. +.. _pytest-asyncio: https://github.com/pytest-dev/pytest-asyncio/blob/master/README.rst .. _pytest-tornado: https://github.com/eugeniy/pytest-tornado Features -------- -- fixtures for creating and injecting versions of the asyncio event loop +- pluggable fixtures of the asyncio event loops - fixtures for injecting unused tcp ports - pytest markers for treating tests as asyncio coroutines - easy testing with non-default event loops @@ -51,48 +132,13 @@ To install pytest-asyncio, simply: .. code-block:: bash - $ pip install pytest-asyncio + $ pip install git+https://github.com/malinoff/pytest-asyncio This is enough for pytest to pick up pytest-asyncio. Fixtures -------- -``event_loop`` -~~~~~~~~~~~~~~ -Creates and injects a new instance of the default asyncio event loop. The loop -will be closed at the end of the test. - -Note that just using the ``event_loop`` fixture won't make your test function -a coroutine. You'll need to interact with the event loop directly, using methods -like ``event_loop.run_until_complete``. See the ``pytest.mark.asyncio`` marker -for treating test functions like coroutines. - -.. code-block:: python - - def test_http_client(event_loop): - url = 'http://httpbin.org/get' - resp = event_loop.run_until_complete(http_client(url)) - assert b'HTTP/1.1 200 OK' in resp - -This fixture can be easily overridden in any of the standard pytest locations -(e.g. directly in the test file, or in ``conftest.py``) to use a non-default -event loop. This will take effect even if you're using the -``pytest.mark.asyncio`` marker and not the ``event_loop`` fixture directly. - -.. code-block:: python - - @pytest.fixture() - def event_loop(): - return MyCustomLoop() - - -``event_loop_process_pool`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``event_loop_process_pool`` fixture is almost identical to the -``event_loop`` fixture, except the created event loop will have a -``concurrent.futures.ProcessPoolExecutor`` set as the default executor. - ``unused_tcp_port`` ~~~~~~~~~~~~~~~~~~~ Finds and yields a single unused TCP port on the localhost interface. Useful for @@ -112,25 +158,17 @@ when several unused TCP ports are required in a test. Markers ------- -``pytest.mark.asyncio(forbid_global_loop=False)`` +``pytest.mark.asyncio(accept_global_loop=False)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mark your test coroutine with this marker and pytest will execute it as an -asyncio task using the event loop provided by the ``event_loop`` fixture. See +asyncio task using the event loop provided by a ``loop`` fixture. See the introductory section for an example. -The event loop used can be overriden by overriding the ``event_loop`` fixture -(see above). +A different event loop can be provided easily, see the introductory section. -If ``forbid_global_loop`` is true, ``asyncio.get_event_loop()`` will result +If ``accept_global_loop`` is false, ``asyncio.get_event_loop()`` will result in exceptions, ensuring your tests are always passing the event loop explicitly. -``pytest.mark.asyncio_process_pool(forbid_global_loop=False)`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``asyncio_process_pool`` marker is almost identical to the ``asyncio`` -marker, except the event loop used will have a -``concurrent.futures.ProcessPoolExecutor`` set as the default executor. - - Contributing ------------ Contributions are very welcome. Tests can be run with ``tox``, please ensure diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index abeeedbf..07b27ef1 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1 +1,3 @@ +from .fixture import async_fixture + __version__ = '0.4.0' diff --git a/pytest_asyncio/exceptions.py b/pytest_asyncio/exceptions.py new file mode 100644 index 00000000..f2555fd3 --- /dev/null +++ b/pytest_asyncio/exceptions.py @@ -0,0 +1,3 @@ +class MissingLoopFixture(Exception): + """Raised if a test coroutine function does not request a loop fixture.""" + pass diff --git a/pytest_asyncio/fixture.py b/pytest_asyncio/fixture.py new file mode 100644 index 00000000..599945b6 --- /dev/null +++ b/pytest_asyncio/fixture.py @@ -0,0 +1,44 @@ +import asyncio +import itertools +import functools + +import pytest # noqa +import _pytest.python + +from .utils import find_loop, maybe_accept_global_loop + + +class AsyncFixtureFunctionMarker(_pytest.python.FixtureFunctionMarker): + + def __init__(self, *args, accept_global_loop, **kwargs): + super().__init__(*args, **kwargs) + self.accept_global_loop = accept_global_loop + + def __call__(self, coroutine): + if not asyncio.iscoroutinefunction(coroutine): + raise ValueError('Only coroutine functions supported') + + @functools.wraps(coroutine) + def inner(*args, **kwargs): + event_loop = find_loop(itertools.chain(args, kwargs.values())) + with maybe_accept_global_loop( + event_loop, self.accept_global_loop) as loop: + return loop.run_until_complete(coroutine(*args, **kwargs)) + + inner._pytestfixturefunction = self + return inner + + +def async_fixture(scope='function', params=None, autouse=False, ids=None, + accept_global_loop=False): + if callable(scope) and params is None and not autouse: + # direct invocation + marker = AsyncFixtureFunctionMarker( + 'function', params, autouse, accept_global_loop=accept_global_loop, + ) + return marker(scope) + if params is not None and not isinstance(params, (list, tuple)): + params = list(params) + return AsyncFixtureFunctionMarker( + scope, params, autouse, ids=ids, accept_global_loop=accept_global_loop, + ) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 52338294..a054c099 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -1,14 +1,11 @@ +import socket import asyncio -from concurrent.futures import ProcessPoolExecutor -from contextlib import closing import inspect -import socket -import pytest +import contextlib +import pytest -class ForbiddenEventLoopPolicy(asyncio.AbstractEventLoopPolicy): - """An event loop policy that raises errors on any operation.""" - pass +from .utils import find_loop, maybe_accept_global_loop def _is_coroutine(obj): @@ -32,8 +29,7 @@ def pytest_configure(config): def pytest_pycollect_makeitem(collector, name, obj): if collector.funcnamefilter(name) and _is_coroutine(obj): item = pytest.Function(name, parent=collector) - if ('asyncio' in item.keywords or - 'asyncio_process_pool' in item.keywords): + if 'asyncio' in item.keywords: return list(collector._genfunctions(name, obj)) @@ -43,66 +39,26 @@ def pytest_pyfunc_call(pyfuncitem): Run asyncio marked test functions in an event loop instead of a normal function call. """ - for marker_name, fixture_name in _markers_2_fixtures.items(): - if marker_name in pyfuncitem.keywords: - event_loop = pyfuncitem.funcargs[fixture_name] - - forbid_global_loop = pyfuncitem.keywords[marker_name].kwargs.get('forbid_global_loop') - - policy = asyncio.get_event_loop_policy() - if forbid_global_loop: - asyncio.set_event_loop_policy(ForbiddenEventLoopPolicy()) - else: - policy.set_event_loop(event_loop) - - funcargs = pyfuncitem.funcargs - testargs = {arg: funcargs[arg] - for arg in pyfuncitem._fixtureinfo.argnames} - try: - event_loop.run_until_complete( - asyncio.async(pyfuncitem.obj(**testargs), loop=event_loop)) - finally: - if forbid_global_loop: - asyncio.set_event_loop_policy(policy) - event_loop.close() - return True - - -def pytest_runtest_setup(item): - for marker, fixture in _markers_2_fixtures.items(): - if marker in item.keywords and fixture not in item.fixturenames: - # inject an event loop fixture for all async tests - item.fixturenames.append(fixture) - - -# maps marker to the name of the event loop fixture that will be available -# to marked test functions -_markers_2_fixtures = { - 'asyncio': 'event_loop', - 'asyncio_process_pool': 'event_loop_process_pool', -} - + if 'asyncio' in pyfuncitem.keywords: + marker_kwargs = pyfuncitem.keywords['asyncio'].kwargs + accept_global_loop = marker_kwargs.get('accept_global_loop', False) -@pytest.fixture -def event_loop(request): - """Create an instance of the default event loop for each test case.""" - policy = asyncio.get_event_loop_policy() - return policy.new_event_loop() - - -@pytest.fixture -def event_loop_process_pool(event_loop): - """Create a fresh instance of the default event loop. + event_loop = find_loop(pyfuncitem.funcargs.values()) - The event loop will have a process pool set as the default executor.""" - event_loop.set_default_executor(ProcessPoolExecutor()) - return event_loop + funcargs = pyfuncitem.funcargs + testargs = {arg: funcargs[arg] + for arg in pyfuncitem._fixtureinfo.argnames} + with maybe_accept_global_loop( + event_loop, accept_global_loop) as loop: + loop.run_until_complete(asyncio.async(pyfuncitem.obj(**testargs), + loop=loop)) + return True @pytest.fixture def unused_tcp_port(): """Find an unused localhost TCP port from 1024-65535 and return it.""" - with closing(socket.socket()) as sock: + with contextlib.closing(socket.socket()) as sock: sock.bind(('127.0.0.1', 0)) return sock.getsockname()[1] diff --git a/pytest_asyncio/utils.py b/pytest_asyncio/utils.py new file mode 100644 index 00000000..b797df56 --- /dev/null +++ b/pytest_asyncio/utils.py @@ -0,0 +1,39 @@ +import asyncio +import contextlib + +from .exceptions import MissingLoopFixture + + +class ForbiddenEventLoopPolicy(asyncio.AbstractEventLoopPolicy): + """An event loop policy that raises errors on any operation.""" + pass + + +@contextlib.contextmanager +def maybe_accept_global_loop(event_loop, accept_global_loop): + if not accept_global_loop and event_loop is None: + raise MissingLoopFixture('A loop fixture must be provided' + ' when a global loop is forbidden') + + policy = asyncio.get_event_loop_policy() + try: + global_event_loop = policy.get_event_loop() + if accept_global_loop and event_loop is None: + event_loop = global_event_loop + + if not accept_global_loop: + asyncio.set_event_loop_policy(ForbiddenEventLoopPolicy()) + else: + policy.set_event_loop(event_loop) + + yield event_loop + + finally: + if not accept_global_loop: + asyncio.set_event_loop_policy(policy) + + +def find_loop(iterable): + for item in iterable: + if isinstance(item, asyncio.AbstractEventLoop): + return item diff --git a/tests/conftest.py b/tests/conftest.py index b943874d..2c7a0901 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,23 @@ import sys +import pytest +import asyncio +import concurrent.futures collect_ignore = [] if sys.version_info[:2] < (3, 5): collect_ignore.append("test_simple_35.py") + collect_ignore.append("test_async_fixture_35.py") + + +@pytest.yield_fixture +def loop(): + policy = asyncio.get_event_loop_policy() + loop = policy.new_event_loop() + yield loop + loop.close() + + +@pytest.fixture +def loop_process_pool(loop): + loop.set_default_executor(concurrent.futures.ProcessPoolExecutor()) + return loop diff --git a/tests/multiloop/conftest.py b/tests/multiloop/conftest.py index 72527fa3..1d6b8507 100644 --- a/tests/multiloop/conftest.py +++ b/tests/multiloop/conftest.py @@ -9,6 +9,6 @@ class CustomSelectorLoop(asyncio.SelectorEventLoop): @pytest.fixture() -def event_loop(): +def loop(): """Create an instance of the default event loop for each test case.""" return CustomSelectorLoop() diff --git a/tests/multiloop/test_alternative_loops.py b/tests/multiloop/test_alternative_loops.py index f8c5595d..6bfdcd16 100644 --- a/tests/multiloop/test_alternative_loops.py +++ b/tests/multiloop/test_alternative_loops.py @@ -5,15 +5,33 @@ @pytest.mark.asyncio -def test_for_custom_loop(): +def test_for_custom_loop(loop): """This test should be executed using the custom loop.""" - yield from asyncio.sleep(0.01) - assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoop" + yield from asyncio.sleep(0.01, loop=loop) + assert type(loop).__name__ == "CustomSelectorLoop" -@pytest.mark.asyncio(forbid_global_loop=True) -def test_forbid_global_loop(event_loop): +@pytest.mark.asyncio +def test_forbid_global_loop(loop): """Test forbidding fetching the global loop using get_event_loop.""" - yield from asyncio.sleep(0.01, loop=event_loop) - with pytest.raises(Exception): + yield from asyncio.sleep(0.01, loop=loop) + with pytest.raises(NotImplementedError): asyncio.get_event_loop() + + +@pytest.mark.asyncio(accept_global_loop=True) +def test_accept_global_loop(loop): + """Test accepting fetching the global loop using get_event_loop.""" + yield from asyncio.sleep(0.01, loop=loop) + global_loop = asyncio.get_event_loop() + assert global_loop is loop + + +@pytest.mark.asyncio(accept_global_loop=True) +def test_no_loop_fixture(): + """Test accepting running the test coroutine when using the global loop + is accepted and a loop fixture is not provided. + """ + global_loop = asyncio.get_event_loop() + yield from asyncio.sleep(0.01) + assert True diff --git a/tests/test_async_fixture.py b/tests/test_async_fixture.py new file mode 100644 index 00000000..9606a12e --- /dev/null +++ b/tests/test_async_fixture.py @@ -0,0 +1,45 @@ +import asyncio +import pytest +import pytest_asyncio + +pytest_plugins = "pytester" + + +@pytest_asyncio.async_fixture +@asyncio.coroutine +def hello(loop): + yield from asyncio.sleep(0, loop=loop) + return 'hello' + + +def test_async_fixture(hello): + assert hello == 'hello' + + +def test_forbidden_global_loop_raises(testdir): + testdir.makepyfile(""" + import asyncio + import pytest_asyncio + + @pytest_asyncio.async_fixture + @asyncio.coroutine + def should_raise(): + yield from asyncio.sleep(0) + + def test_should_raise(should_raise): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines(["*pytest_asyncio.exceptions.MissingLoopFixture*"]) + + + +@pytest_asyncio.async_fixture(accept_global_loop=True) +@asyncio.coroutine +def using_global_loop(): + yield from asyncio.sleep(0) + return 'ok' + + +def test_accepted_global_loop(using_global_loop): + assert using_global_loop == 'ok' diff --git a/tests/test_async_fixture_35.py b/tests/test_async_fixture_35.py new file mode 100644 index 00000000..2d8d2f09 --- /dev/null +++ b/tests/test_async_fixture_35.py @@ -0,0 +1,13 @@ +import asyncio +import pytest +import pytest_asyncio + + +@pytest_asyncio.async_fixture +async def hello(loop): + await asyncio.sleep(0, loop=loop) + return 'hello' + + +def test_async_fixture(hello): + assert hello == 'hello' diff --git a/tests/test_simple.py b/tests/test_simple.py index 6ada9361..1ea438a5 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,6 +1,6 @@ """Quick'n'dirty unit tests for provided fixtures and markers.""" -import asyncio import os +import asyncio import pytest import pytest_asyncio.plugin @@ -12,48 +12,44 @@ def async_coro(loop): return 'ok' -def test_event_loop_fixture(event_loop): - """Test the injection of the event_loop fixture.""" - assert event_loop - ret = event_loop.run_until_complete(async_coro(event_loop)) +def test_loop_fixture(loop): + assert loop + ret = loop.run_until_complete(async_coro(loop)) assert ret == 'ok' -def test_event_loop_processpool_fixture(event_loop_process_pool): - """Test the injection of the event_loop with a process pool fixture.""" - assert event_loop_process_pool - - ret = event_loop_process_pool.run_until_complete( - async_coro(event_loop_process_pool)) +def test_loop_process_pool_fixture(loop_process_pool): + assert loop_process_pool + ret = loop_process_pool.run_until_complete( + async_coro(loop_process_pool)) assert ret == 'ok' this_pid = os.getpid() - future = event_loop_process_pool.run_in_executor(None, os.getpid) - pool_pid = event_loop_process_pool.run_until_complete(future) + future = loop_process_pool.run_in_executor(None, os.getpid) + pool_pid = loop_process_pool.run_until_complete(future) assert this_pid != pool_pid @pytest.mark.asyncio -def test_asyncio_marker(): +def test_asyncio_marker(loop): """Test the asyncio pytest marker.""" yield # sleep(0) @pytest.mark.asyncio -def test_asyncio_marker_with_default_param(a_param=None): +def test_asyncio_marker_with_default_param(loop, a_param=None): """Test the asyncio pytest marker.""" yield # sleep(0) -@pytest.mark.asyncio_process_pool -def test_asyncio_process_pool_marker(event_loop): - """Test the asyncio pytest marker.""" - ret = yield from async_coro(event_loop) +@pytest.mark.asyncio +def test_asyncio_process_pool(loop_process_pool): + ret = yield from async_coro(loop_process_pool) assert ret == 'ok' @pytest.mark.asyncio -def test_unused_port_fixture(unused_tcp_port, event_loop): +def test_unused_port_fixture(unused_tcp_port, loop): """Test the unused TCP port fixture.""" @asyncio.coroutine @@ -62,19 +58,19 @@ def closer(_, writer): server1 = yield from asyncio.start_server(closer, host='localhost', port=unused_tcp_port, - loop=event_loop) + loop=loop) with pytest.raises(IOError): yield from asyncio.start_server(closer, host='localhost', port=unused_tcp_port, - loop=event_loop) + loop=loop) server1.close() yield from server1.wait_closed() @pytest.mark.asyncio -def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop): +def test_unused_port_factory_fixture(unused_tcp_port_factory, loop): """Test the unused TCP port factory fixture.""" @asyncio.coroutine @@ -86,19 +82,19 @@ def closer(_, writer): server1 = yield from asyncio.start_server(closer, host='localhost', port=port1, - loop=event_loop) + loop=loop) server2 = yield from asyncio.start_server(closer, host='localhost', port=port2, - loop=event_loop) + loop=loop) server3 = yield from asyncio.start_server(closer, host='localhost', port=port3, - loop=event_loop) + loop=loop) for port in port1, port2, port3: with pytest.raises(IOError): yield from asyncio.start_server(closer, host='localhost', port=port, - loop=event_loop) + loop=loop) server1.close() yield from server1.wait_closed() @@ -132,7 +128,7 @@ class Test: """Test that asyncio marked functions work in test methods.""" @pytest.mark.asyncio - def test_asyncio_marker_method(self, event_loop): + def test_asyncio_marker_method(self, loop): """Test the asyncio pytest marker in a Test class.""" - ret = yield from async_coro(event_loop) + ret = yield from async_coro(loop) assert ret == 'ok' diff --git a/tests/test_simple_35.py b/tests/test_simple_35.py index cfc9ec5e..2e7161d9 100644 --- a/tests/test_simple_35.py +++ b/tests/test_simple_35.py @@ -11,36 +11,36 @@ async def async_coro(loop): @pytest.mark.asyncio -async def test_asyncio_marker(): +async def test_asyncio_marker(loop): """Test the asyncio pytest marker.""" @pytest.mark.asyncio -async def test_asyncio_marker_with_default_param(a_param=None): +async def test_asyncio_marker_with_default_param(loop, a_param=None): """Test the asyncio pytest marker.""" -@pytest.mark.asyncio_process_pool -async def test_asyncio_process_pool_marker(event_loop): - ret = await async_coro(event_loop) +@pytest.mark.asyncio +async def test_asyncio_process_pool(loop_process_pool): + ret = await async_coro(loop_process_pool) assert ret == 'ok' @pytest.mark.asyncio -async def test_unused_port_fixture(unused_tcp_port, event_loop): +async def test_unused_port_fixture(unused_tcp_port, loop): """Test the unused TCP port fixture.""" async def closer(_, writer): writer.close() server1 = await asyncio.start_server(closer, host='localhost', port=unused_tcp_port, - loop=event_loop) + loop=loop) server1.close() await server1.wait_closed() -def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop): +def test_unused_port_factory_fixture(unused_tcp_port_factory, loop): """Test the unused TCP port factory fixture.""" async def closer(_, writer): @@ -52,19 +52,19 @@ async def closer(_, writer): async def run_test(): server1 = await asyncio.start_server(closer, host='localhost', port=port1, - loop=event_loop) + loop=loop) server2 = await asyncio.start_server(closer, host='localhost', port=port2, - loop=event_loop) + loop=loop) server3 = await asyncio.start_server(closer, host='localhost', port=port3, - loop=event_loop) + loop=loop) for port in port1, port2, port3: with pytest.raises(IOError): await asyncio.start_server(closer, host='localhost', port=port, - loop=event_loop) + loop=loop) server1.close() await server1.wait_closed() @@ -73,22 +73,22 @@ async def run_test(): server3.close() await server3.wait_closed() - event_loop.run_until_complete(run_test()) + loop.run_until_complete(run_test()) - event_loop.stop() - event_loop.close() + loop.stop() + loop.close() class Test: """Test that asyncio marked functions work in test methods.""" @pytest.mark.asyncio - async def test_asyncio_marker_method(self, event_loop): + async def test_asyncio_marker_method(self, loop): """Test the asyncio pytest marker in a Test class.""" - ret = await async_coro(event_loop) + ret = await async_coro(loop) assert ret == 'ok' -def test_async_close_loop(event_loop): - event_loop.close() +def test_async_close_loop(loop): + loop.close() return 'ok'