diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3d93214d..3b249ffb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ jobs: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" env: - USING_COVERAGE: "3.6,3.7,3.8,3.9" + USING_COVERAGE: "3.6,3.7,3.8,3.9,3.10" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"] steps: - uses: "actions/checkout@v2" diff --git a/README.rst b/README.rst index 3b62d7eb..02e7b634 100644 --- a/README.rst +++ b/README.rst @@ -166,6 +166,7 @@ Changelog --------- 0.16.0 (UNRELEASED) ~~~~~~~~~~~~~~~~~~~ +- Add support for Python 3.10 0.15.1 (2021-04-22) ~~~~~~~~~~~~~~~~~~~ diff --git a/setup.py b/setup.py index 2df6faee..e15080fe 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ def find_version(): "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Software Development :: Testing", "Framework :: Pytest", ], diff --git a/tests/async_fixtures/test_async_fixtures_with_finalizer.py b/tests/async_fixtures/test_async_fixtures_with_finalizer.py index c602d908..c90a0124 100644 --- a/tests/async_fixtures/test_async_fixtures_with_finalizer.py +++ b/tests/async_fixtures/test_async_fixtures_with_finalizer.py @@ -44,11 +44,14 @@ async def port_afinalizer(): async def port_with_get_event_loop_finalizer(request, event_loop): def port_finalizer(finalizer): async def port_afinalizer(): - # await task using loop provided by asyncio.get_event_loop() - # RuntimeError is raised if task is created on a different loop + # await task using current loop retrieved from the event loop policy + # RuntimeError is raised if task is created on a different loop. + # This can happen when pytest_fixture_setup does not set up the loop correctly, + # for example when policy.set_event_loop() is called with a wrong argument await finalizer - asyncio.get_event_loop().run_until_complete(port_afinalizer()) + current_loop = asyncio.get_event_loop_policy().get_event_loop() + current_loop.run_until_complete(port_afinalizer()) worker = asyncio.ensure_future(asyncio.sleep(0.2)) request.addfinalizer(functools.partial(port_finalizer, worker)) diff --git a/tests/test_event_loop_scope.py b/tests/test_event_loop_scope.py index ccfeffe6..8ae4eb1e 100644 --- a/tests/test_event_loop_scope.py +++ b/tests/test_event_loop_scope.py @@ -1,4 +1,4 @@ -"""Test the event loop fixture is properly disposed of. +"""Test the event loop fixture provides a separate loop for each test. These tests need to be run together. """ @@ -6,17 +6,26 @@ import pytest +loop: asyncio.AbstractEventLoop + def test_1(): - loop = asyncio.get_event_loop() - assert not loop.is_closed() + global loop + # The main thread should have a default event loop. + loop = asyncio.get_event_loop_policy().get_event_loop() @pytest.mark.asyncio async def test_2(): - pass + global loop + running_loop = asyncio.get_event_loop_policy().get_event_loop() + # Make sure this test case received a different loop + assert running_loop is not loop + loop = running_loop # Store the loop reference for later def test_3(): - loop = asyncio.get_event_loop() - assert not loop.is_closed() + global loop + current_loop = asyncio.get_event_loop_policy().get_event_loop() + # Now the event loop from test_2 should have been cleaned up + assert loop is not current_loop diff --git a/tests/test_hypothesis_integration.py b/tests/test_hypothesis_integration.py index 9c97e06c..39cb6075 100644 --- a/tests/test_hypothesis_integration.py +++ b/tests/test_hypothesis_integration.py @@ -10,8 +10,9 @@ @pytest.fixture(scope="module") def event_loop(): - loop = asyncio.get_event_loop() + loop = asyncio.get_event_loop_policy().new_event_loop() yield loop + loop.close() @given(st.integers()) diff --git a/tests/test_simple.py b/tests/test_simple.py index b5b57ed5..854faaf3 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -99,27 +99,18 @@ def mock_unused_tcp_port(): assert unused_tcp_port_factory() > 10000 -class Test: - """Test that asyncio marked functions work in test methods.""" +class TestMarkerInClassBasedTests: + """Test that asyncio marked functions work for methods of test classes.""" @pytest.mark.asyncio - async def test_asyncio_marker_method(self, event_loop): - """Test the asyncio pytest marker in a Test class.""" + async def test_asyncio_marker_with_explicit_loop_fixture(self, event_loop): + """Test the "asyncio" marker works on a method in a class-based test with explicit loop fixture.""" ret = await async_coro() assert ret == "ok" - -class TestUnexistingLoop: - @pytest.fixture - def remove_loop(self): - old_loop = asyncio.get_event_loop() - asyncio.set_event_loop(None) - yield - asyncio.set_event_loop(old_loop) - @pytest.mark.asyncio - async def test_asyncio_marker_without_loop(self, remove_loop): - """Test the asyncio pytest marker in a Test class.""" + async def test_asyncio_marker_with_implicit_loop_fixture(self): + """Test the "asyncio" marker works on a method in a class-based test with implicit loop fixture.""" ret = await async_coro() assert ret == "ok" diff --git a/tox.ini b/tox.ini index 72cfafc2..ef60cba0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py36, py37, py38, py39, lint +envlist = py36, py37, py38, py39, py310, lint skip_missing_interpreters = true [testenv] @@ -30,4 +30,5 @@ python = 3.7: py37 3.8: py38 3.9: py39, lint + 3.10: py310 pypy3: pypy3