Skip to content

Python 3.7 support #88

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

Merged
merged 2 commits into from
Jul 28, 2018
Merged
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
17 changes: 13 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
language: python
python:
- "3.5"
- "3.6"
matrix:
include:
- python: 3.5
env: TOX_ENV=py35
- python: 3.6
env: TOX_ENV=py36
- python: 3.7
env: TOX_ENV=py37
# TODO: the dist and sudo keys are currently needed to use Python 3.7.
# They should be removed once Travis-CI supports 3.7 on the default image.
dist: xenial
sudo: true

install: pip install tox-travis coveralls

script: tox
script: tox -e $TOX_ENV

after_success:
- tox -e coverage-report
Expand Down
16 changes: 4 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,6 @@ If the ``pytest.mark.asyncio`` marker is applied, a pytest hook will
ensure the produced loop is set as the default global loop.
Fixtures depending on the ``event_loop`` fixture can expect the policy to be properly modified when they run.

``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
Expand Down Expand Up @@ -176,17 +170,15 @@ Only test coroutines will be affected (by default, coroutines prefixed by
.. |pytestmark| replace:: ``pytestmark``
.. _pytestmark: http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules

``pytest.mark.asyncio_process_pool``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.

Changelog
---------

0.9.0 (UNRELEASED)
~~~~~~~~~~~~~~~~~~
- Python 3.7 support
- Remove ``event_loop_process_pool`` fixture and
``pytest.mark.asyncio_process_pool`` marker (see
https://bugs.python.org/issue34075 for deprecation and removal details)

0.8.0 (2017-09-23)
~~~~~~~~~~~~~~~~~~
Expand Down
19 changes: 1 addition & 18 deletions pytest_asyncio/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import contextlib
import inspect
import socket
from concurrent.futures import ProcessPoolExecutor

import pytest
from _pytest.python import transfer_markers
Expand All @@ -25,11 +24,6 @@ def pytest_configure(config):
"asyncio: "
"mark the test as a coroutine, it will be "
"run using an asyncio event loop")
config.addinivalue_line("markers",
"asyncio_process_pool: "
"mark the test as a coroutine, it will be "
"run using an asyncio event loop with a process "
"pool")


@pytest.mark.tryfirst
Expand All @@ -44,8 +38,7 @@ def pytest_pycollect_makeitem(collector, name, obj):
transfer_markers(obj, item.cls, item.module)
item = pytest.Function(name, parent=collector) # To reload keywords.

if ('asyncio' in item.keywords or
'asyncio_process_pool' in item.keywords):
if 'asyncio' in item.keywords:
return list(collector._genfunctions(name, obj))


Expand Down Expand Up @@ -170,7 +163,6 @@ def pytest_runtest_setup(item):
# to marked test functions
_markers_2_fixtures = {
'asyncio': 'event_loop',
'asyncio_process_pool': 'event_loop_process_pool',
}


Expand All @@ -182,15 +174,6 @@ def event_loop(request):
loop.close()


@pytest.fixture
def event_loop_process_pool(event_loop):
"""Create a fresh instance of the default event loop.

The event loop will have a process pool set as the default executor."""
event_loop.set_default_executor(ProcessPoolExecutor())
return event_loop


@pytest.fixture
def unused_tcp_port():
"""Find an unused localhost TCP port from 1024-65535 and return it."""
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def find_version():
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Software Development :: Testing",
"Framework :: Pytest",
],
Expand Down
10 changes: 4 additions & 6 deletions tests/async_fixtures/test_coroutine_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ def mock():


@pytest.fixture
@asyncio.coroutine
def coroutine_fixture(mock):
yield from asyncio.sleep(0.1, result=mock(START))
async def coroutine_fixture(mock):
await asyncio.sleep(0.1, result=mock(START))


@pytest.mark.asyncio
@asyncio.coroutine
def test_coroutine_fixture(coroutine_fixture, mock):
async def test_coroutine_fixture(coroutine_fixture, mock):
assert mock.call_count == 1
assert mock.call_args_list[-1] == unittest.mock.call(START)
assert coroutine_fixture is RETVAL
assert coroutine_fixture is RETVAL
5 changes: 2 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ def dependent_fixture(event_loop):
"""A fixture dependent on the event_loop fixture, doing some cleanup."""
counter = 0

@asyncio.coroutine
def just_a_sleep():
async def just_a_sleep():
"""Just sleep a little while."""
nonlocal event_loop
yield from asyncio.sleep(0.1, loop=event_loop)
await asyncio.sleep(0.1, loop=event_loop)
nonlocal counter
counter += 1

Expand Down
9 changes: 4 additions & 5 deletions tests/multiloop/test_alternative_loops.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@


@pytest.mark.asyncio
def test_for_custom_loop():
async def test_for_custom_loop():
"""This test should be executed using the custom loop."""
yield from asyncio.sleep(0.01)
await asyncio.sleep(0.01)
assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoop"


@pytest.mark.asyncio
@asyncio.coroutine
def test_dependent_fixture(dependent_fixture):
yield from asyncio.sleep(0.1)
async def test_dependent_fixture(dependent_fixture):
await asyncio.sleep(0.1)
5 changes: 2 additions & 3 deletions tests/test_dependent_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@


@pytest.mark.asyncio
@asyncio.coroutine
def test_dependent_fixture(dependent_fixture):
async def test_dependent_fixture(dependent_fixture):
"""Test a dependent fixture."""
yield from asyncio.sleep(0.1)
await asyncio.sleep(0.1)
88 changes: 32 additions & 56 deletions tests/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import pytest_asyncio.plugin


@asyncio.coroutine
def async_coro(loop=None):
async def async_coro(loop=None):
"""A very simple coroutine."""
yield from asyncio.sleep(0, loop=loop)
await asyncio.sleep(0, loop=loop)
return 'ok'


Expand All @@ -20,20 +19,6 @@ def test_event_loop_fixture(event_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))
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)
assert this_pid != pool_pid


@pytest.mark.asyncio
def test_asyncio_marker():
"""Test the asyncio pytest marker."""
Expand All @@ -52,67 +37,58 @@ def test_asyncio_marker_with_default_param(a_param=None):
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)
assert ret == 'ok'


@pytest.mark.asyncio
def test_unused_port_fixture(unused_tcp_port, event_loop):
async def test_unused_port_fixture(unused_tcp_port, event_loop):
"""Test the unused TCP port fixture."""

@asyncio.coroutine
def closer(_, writer):
async def closer(_, writer):
writer.close()

server1 = yield from asyncio.start_server(closer, host='localhost',
port=unused_tcp_port,
loop=event_loop)
server1 = await asyncio.start_server(closer, host='localhost',
port=unused_tcp_port,
loop=event_loop)

with pytest.raises(IOError):
yield from asyncio.start_server(closer, host='localhost',
port=unused_tcp_port,
loop=event_loop)
await asyncio.start_server(closer, host='localhost',
port=unused_tcp_port,
loop=event_loop)

server1.close()
yield from server1.wait_closed()
await server1.wait_closed()


@pytest.mark.asyncio
def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop):
async def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop):
"""Test the unused TCP port factory fixture."""

@asyncio.coroutine
def closer(_, writer):
async def closer(_, writer):
writer.close()

port1, port2, port3 = (unused_tcp_port_factory(), unused_tcp_port_factory(),
unused_tcp_port_factory())

server1 = yield from asyncio.start_server(closer, host='localhost',
port=port1,
loop=event_loop)
server2 = yield from asyncio.start_server(closer, host='localhost',
port=port2,
loop=event_loop)
server3 = yield from asyncio.start_server(closer, host='localhost',
port=port3,
loop=event_loop)
server1 = await asyncio.start_server(closer, host='localhost',
port=port1,
loop=event_loop)
server2 = await asyncio.start_server(closer, host='localhost',
port=port2,
loop=event_loop)
server3 = await asyncio.start_server(closer, host='localhost',
port=port3,
loop=event_loop)

for port in port1, port2, port3:
with pytest.raises(IOError):
yield from asyncio.start_server(closer, host='localhost',
port=port,
loop=event_loop)
await asyncio.start_server(closer, host='localhost',
port=port,
loop=event_loop)

server1.close()
yield from server1.wait_closed()
await server1.wait_closed()
server2.close()
yield from server2.wait_closed()
await server2.wait_closed()
server3.close()
yield from server3.wait_closed()
await server3.wait_closed()


def test_unused_port_factory_duplicate(unused_tcp_port_factory, monkeypatch):
Expand All @@ -139,9 +115,9 @@ class Test:
"""Test that asyncio marked functions work in test methods."""

@pytest.mark.asyncio
def test_asyncio_marker_method(self, event_loop):
async def test_asyncio_marker_method(self, event_loop):
"""Test the asyncio pytest marker in a Test class."""
ret = yield from async_coro(event_loop)
ret = await async_coro(event_loop)
assert ret == 'ok'


Expand All @@ -154,7 +130,7 @@ def remove_loop(self):
asyncio.set_event_loop(old_loop)

@pytest.mark.asyncio
def test_asyncio_marker_without_loop(self, remove_loop):
async def test_asyncio_marker_without_loop(self, remove_loop):
"""Test the asyncio pytest marker in a Test class."""
ret = yield from async_coro()
ret = await async_coro()
assert ret == 'ok'
8 changes: 1 addition & 7 deletions tests/test_simple_35.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest


@asyncio.coroutine
@pytest.mark.asyncio
async def async_coro(loop):
await asyncio.sleep(0, loop=loop)
return 'ok'
Expand All @@ -20,12 +20,6 @@ async def test_asyncio_marker_with_default_param(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)
assert ret == 'ok'


@pytest.mark.asyncio
async def test_unused_port_fixture(unused_tcp_port, event_loop):
"""Test the unused TCP port fixture."""
Expand Down
14 changes: 6 additions & 8 deletions tests/test_subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,18 @@


@pytest.mark.asyncio(forbid_global_loop=False)
@asyncio.coroutine
def test_subprocess(event_loop):
async def test_subprocess(event_loop):
"""Starting a subprocess should be possible."""
proc = yield from asyncio.subprocess.create_subprocess_exec(
proc = await asyncio.subprocess.create_subprocess_exec(
sys.executable, '--version', stdout=asyncio.subprocess.PIPE,
loop=event_loop)
yield from proc.communicate()
await proc.communicate()


@pytest.mark.asyncio(forbid_global_loop=True)
@asyncio.coroutine
def test_subprocess_forbid(event_loop):
async def test_subprocess_forbid(event_loop):
"""Starting a subprocess should be possible."""
proc = yield from asyncio.subprocess.create_subprocess_exec(
proc = await asyncio.subprocess.create_subprocess_exec(
sys.executable, '--version', stdout=asyncio.subprocess.PIPE,
loop=event_loop)
yield from proc.communicate()
await proc.communicate()
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py35, py36
envlist = py35, py36, py37
minversion = 2.5.0

[testenv]
Expand All @@ -11,4 +11,4 @@ deps = coverage
skip_install = true
commands =
coverage combine
coverage report
coverage report