From 4e2e6bd16682f6d3f8597cf5d7a86521a847e7ba Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Wed, 24 Jun 2020 00:13:11 +0200 Subject: [PATCH 001/198] 0.15 open for business --- README.rst | 5 ++++- pytest_asyncio/__init__.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6ea6014c..917dd52f 100644 --- a/README.rst +++ b/README.rst @@ -175,7 +175,10 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- -0.13.0 (2020-06-24) +0.15.0 (UNRELEASED) +~~~~~~~~~~~~~~~~~~~ + +0.14.0 (2020-06-24) ~~~~~~~~~~~~~~~~~~~ - Fix `#162 `_, and ``event_loop`` fixture behavior now is coherent on all scopes. `#164 `_ diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index 61c5f43b..11e6bcdc 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.14.0" +__version__ = "0.15.0dev0" From 03eed51d92e448532b57df606aab0977916dc111 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 5 Oct 2020 11:01:30 +0200 Subject: [PATCH 002/198] Added Python 3.9 to the tested interpreters. Signed-off-by: Michael Seifert --- .travis.yml | 2 ++ README.rst | 1 + setup.py | 1 + tox.ini | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b93377ad..db43fefd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ matrix: env: TOX_ENV=py37 - python: 3.8 env: TOX_ENV=py38 + - python: 3.9-dev + env: TOX_ENV=py39 install: pip install tox-travis coveralls diff --git a/README.rst b/README.rst index 917dd52f..64698c69 100644 --- a/README.rst +++ b/README.rst @@ -177,6 +177,7 @@ Changelog --------- 0.15.0 (UNRELEASED) ~~~~~~~~~~~~~~~~~~~ +- Add support for Python 3.9 0.14.0 (2020-06-24) ~~~~~~~~~~~~~~~~~~~ diff --git a/setup.py b/setup.py index 61757113..ff3855c0 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ def find_version(): "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Testing", "Framework :: Pytest", ], diff --git a/tox.ini b/tox.ini index eed6fb67..6cc4a82a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py35, py36, py37, py38 +envlist = py35, py36, py37, py38, py39 skip_missing_interpreters = true [testenv] From 057562f8aaf9f18d97326a86dbdb9587e866bfe0 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 6 Oct 2020 11:00:21 +0200 Subject: [PATCH 003/198] feat!: Removed support for Python 3.5. This commit: - Removes Python 3.5 from the tested environments in CI and tox - Removes instructions specific to Python 3.5 from the README - Updates the Changelog - Removes the dependency on async_generator - Removes instructions in conftest that skip certain test cases if the Python version is smaller than 3.6 Signed-off-by: Michael Seifert --- .travis.yml | 2 - README.rst | 14 +------ pytest_asyncio/plugin.py | 5 +-- setup.py | 5 +-- .../test_async_gen_fixtures_35.py | 40 ------------------- tests/conftest.py | 6 --- tox.ini | 2 +- 7 files changed, 4 insertions(+), 70 deletions(-) delete mode 100644 tests/async_fixtures/test_async_gen_fixtures_35.py diff --git a/.travis.yml b/.travis.yml index db43fefd..a19d5d73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: python matrix: include: - - python: 3.5 - env: TOX_ENV=py35 - python: 3.6 env: TOX_ENV=py36 - python: 3.7 diff --git a/README.rst b/README.rst index 64698c69..2f282b5e 100644 --- a/README.rst +++ b/README.rst @@ -127,19 +127,6 @@ to redefine the ``event_loop`` fixture to have the same or broader scope. Async fixtures need the event loop, and so must have the same or narrower scope than the ``event_loop`` fixture. -If you want to do this with Python 3.5, the ``yield`` statement must be replaced with ``await yield_()`` and the coroutine -function must be decorated with ``@async_generator``, like so: - -.. code-block:: python3 - - from async_generator import yield_, async_generator - - @pytest.fixture - @async_generator - async def async_gen_fixture(): - await asyncio.sleep(0.1) - await yield_('a value') - Markers ------- @@ -178,6 +165,7 @@ Changelog 0.15.0 (UNRELEASED) ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.9 +- Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. 0.14.0 (2020-06-24) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 2fdc5f4e..4b7d6fd0 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -13,10 +13,7 @@ def transfer_markers(*args, **kwargs): # noqa """Noop when over pytest 4.1.0""" pass -try: - from async_generator import isasyncgenfunction -except ImportError: - from inspect import isasyncgenfunction +from inspect import isasyncgenfunction def _is_coroutine(obj): diff --git a/setup.py b/setup.py index ff3855c0..2df6faee 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,6 @@ def find_version(): "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -41,13 +40,11 @@ def find_version(): "Topic :: Software Development :: Testing", "Framework :: Pytest", ], - python_requires=">= 3.5", + python_requires=">= 3.6", install_requires=["pytest >= 5.4.0"], extras_require={ - ':python_version == "3.5"': "async_generator >= 1.3", "testing": [ "coverage", - "async_generator >= 1.3", "hypothesis >= 5.7.1", ], }, diff --git a/tests/async_fixtures/test_async_gen_fixtures_35.py b/tests/async_fixtures/test_async_gen_fixtures_35.py deleted file mode 100644 index 3b552fab..00000000 --- a/tests/async_fixtures/test_async_gen_fixtures_35.py +++ /dev/null @@ -1,40 +0,0 @@ -import unittest.mock - -import pytest -from async_generator import yield_, async_generator - -START = object() -END = object() -RETVAL = object() - - -@pytest.fixture(scope='module') -def mock(): - return unittest.mock.Mock(return_value=RETVAL) - - -@pytest.fixture -@async_generator -async def async_gen_fixture(mock): - try: - await yield_(mock(START)) - except Exception as e: - mock(e) - else: - mock(END) - - -@pytest.mark.asyncio -async def test_async_gen_fixture(async_gen_fixture, mock): - assert mock.called - assert mock.call_args_list[-1] == unittest.mock.call(START) - assert async_gen_fixture is RETVAL - - -@pytest.mark.asyncio -async def test_async_gen_fixture_finalized(mock): - try: - assert mock.called - assert mock.call_args_list[-1] == unittest.mock.call(END) - finally: - mock.reset_mock() diff --git a/tests/conftest.py b/tests/conftest.py index cc2ec163..1ca63fe5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,7 @@ import asyncio -import sys import pytest -collect_ignore = [] -if sys.version_info[:2] < (3, 6): - collect_ignore.append("async_fixtures/test_async_gen_fixtures_36.py") - collect_ignore.append("async_fixtures/test_nested_36.py") - @pytest.fixture def dependent_fixture(event_loop): diff --git a/tox.ini b/tox.ini index 6cc4a82a..f739cc51 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py35, py36, py37, py38, py39 +envlist = py36, py37, py38, py39 skip_missing_interpreters = true [testenv] From b40de0d79087572ea59a85ba9903ab364175d796 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 6 Oct 2020 11:15:03 +0200 Subject: [PATCH 004/198] refactor: Removed duplicate module test_simple_35.py. The test cases in this module are duplicates of test_simple.py, except for test_async_close_loop which was moved to test_simple.py. Signed-off-by: Michael Seifert --- tests/test_simple.py | 5 +++ tests/test_simple_35.py | 83 ----------------------------------------- 2 files changed, 5 insertions(+), 83 deletions(-) delete mode 100644 tests/test_simple_35.py diff --git a/tests/test_simple.py b/tests/test_simple.py index c8dccaf8..62b4036e 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -154,3 +154,8 @@ async def test_event_loop_before_fixture(self, event_loop, loop): @pytest.mark.asyncio async def test_no_warning_on_skip(): pytest.skip("Test a skip error inside asyncio") + + +def test_async_close_loop(event_loop): + event_loop.close() + return 'ok' diff --git a/tests/test_simple_35.py b/tests/test_simple_35.py deleted file mode 100644 index 4141fb0b..00000000 --- a/tests/test_simple_35.py +++ /dev/null @@ -1,83 +0,0 @@ -"""Quick'n'dirty unit tests using async and await syntax.""" -import asyncio - -import pytest - - -@pytest.mark.asyncio -async def async_coro(loop): - await asyncio.sleep(0) - return 'ok' - - -@pytest.mark.asyncio -async def test_asyncio_marker(): - """Test the asyncio pytest marker.""" - - -@pytest.mark.asyncio -async def test_asyncio_marker_with_default_param(a_param=None): - """Test the asyncio pytest marker.""" - - -@pytest.mark.asyncio -async def test_unused_port_fixture(unused_tcp_port, event_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) - - server1.close() - await server1.wait_closed() - - -def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop): - """Test the unused TCP port factory fixture.""" - - async def closer(_, writer): - writer.close() - - port1, port2, port3 = (unused_tcp_port_factory(), unused_tcp_port_factory(), - unused_tcp_port_factory()) - - async def run_test(): - server1 = await asyncio.start_server(closer, host='localhost', - port=port1) - server2 = await asyncio.start_server(closer, host='localhost', - port=port2) - server3 = await asyncio.start_server(closer, host='localhost', - port=port3) - - for port in port1, port2, port3: - with pytest.raises(IOError): - await asyncio.start_server(closer, host='localhost', - port=port) - - server1.close() - await server1.wait_closed() - server2.close() - await server2.wait_closed() - server3.close() - await server3.wait_closed() - - event_loop.run_until_complete(run_test()) - - event_loop.stop() - event_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): - """Test the asyncio pytest marker in a Test class.""" - ret = await async_coro(event_loop) - assert ret == 'ok' - - -def test_async_close_loop(event_loop): - event_loop.close() - return 'ok' From 1bb7f300f4f5c31d47675ed018e9a46ecd4d8496 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 6 Oct 2020 11:17:32 +0200 Subject: [PATCH 005/198] refactor: Removed the "_35" and "_36" suffixes from test modules. Test modules suffixed with "_35" or "_36" give the impression that they are specific to a Python version. This is no longer the case, though. The renamed modules are not specific to any Python version. Signed-off-by: Michael Seifert --- .../{test_async_fixtures_35.py => test_async_fixtures.py} | 0 .../{test_async_gen_fixtures_36.py => test_async_gen_fixtures.py} | 0 tests/async_fixtures/{test_nested_36.py => test_nested.py} | 0 tests/markers/{test_class_marker_35.py => test_class_marker.py} | 0 tests/markers/{test_module_marker_35.py => test_module_marker.py} | 0 tests/{test_event_loop_scope_35.py => test_event_loop_scope.py} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/async_fixtures/{test_async_fixtures_35.py => test_async_fixtures.py} (100%) rename tests/async_fixtures/{test_async_gen_fixtures_36.py => test_async_gen_fixtures.py} (100%) rename tests/async_fixtures/{test_nested_36.py => test_nested.py} (100%) rename tests/markers/{test_class_marker_35.py => test_class_marker.py} (100%) rename tests/markers/{test_module_marker_35.py => test_module_marker.py} (100%) rename tests/{test_event_loop_scope_35.py => test_event_loop_scope.py} (100%) diff --git a/tests/async_fixtures/test_async_fixtures_35.py b/tests/async_fixtures/test_async_fixtures.py similarity index 100% rename from tests/async_fixtures/test_async_fixtures_35.py rename to tests/async_fixtures/test_async_fixtures.py diff --git a/tests/async_fixtures/test_async_gen_fixtures_36.py b/tests/async_fixtures/test_async_gen_fixtures.py similarity index 100% rename from tests/async_fixtures/test_async_gen_fixtures_36.py rename to tests/async_fixtures/test_async_gen_fixtures.py diff --git a/tests/async_fixtures/test_nested_36.py b/tests/async_fixtures/test_nested.py similarity index 100% rename from tests/async_fixtures/test_nested_36.py rename to tests/async_fixtures/test_nested.py diff --git a/tests/markers/test_class_marker_35.py b/tests/markers/test_class_marker.py similarity index 100% rename from tests/markers/test_class_marker_35.py rename to tests/markers/test_class_marker.py diff --git a/tests/markers/test_module_marker_35.py b/tests/markers/test_module_marker.py similarity index 100% rename from tests/markers/test_module_marker_35.py rename to tests/markers/test_module_marker.py diff --git a/tests/test_event_loop_scope_35.py b/tests/test_event_loop_scope.py similarity index 100% rename from tests/test_event_loop_scope_35.py rename to tests/test_event_loop_scope.py From a5161343442fb64b7fcb91dfc5841b9f79698989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Romain=20L=C3=A9tendart?= Date: Mon, 18 May 2020 17:06:21 +0200 Subject: [PATCH 006/198] plugin: Set unused_tcp_port_factory scope to 'session' Factories in pytest usually have a scope greater than 'function' to let one use the same factory within bigger scopes. Let us allow unused_tcp_port_factory to be used throughout the same session scope. This will let other session-scoped factories depend on unused_tcp_port_factory without getting a "ScopeMismatch" error. --- README.rst | 2 ++ pytest_asyncio/plugin.py | 2 +- tests/conftest.py | 7 +++++++ tests/test_dependent_fixtures.py | 5 +++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2f282b5e..aa757b68 100644 --- a/README.rst +++ b/README.rst @@ -166,6 +166,8 @@ Changelog ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.9 - Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. +- Set ``unused_tcp_port_factory`` fixture scope to 'session'. + `#163 `_ 0.14.0 (2020-06-24) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 4b7d6fd0..0f29be12 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -219,7 +219,7 @@ def unused_tcp_port(): return _unused_tcp_port() -@pytest.fixture +@pytest.fixture(scope='session') def unused_tcp_port_factory(): """A factory function, producing different unused TCP ports.""" produced = set() diff --git a/tests/conftest.py b/tests/conftest.py index 1ca63fe5..9e046123 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,3 +20,10 @@ async def just_a_sleep(): event_loop.run_until_complete(just_a_sleep()) assert counter == 2 + + +@pytest.fixture(scope='session', name='factory_involving_factories') +def factory_involving_factories_fixture(unused_tcp_port_factory): + def factory(): + return unused_tcp_port_factory() + return factory diff --git a/tests/test_dependent_fixtures.py b/tests/test_dependent_fixtures.py index db2252b2..2876255b 100644 --- a/tests/test_dependent_fixtures.py +++ b/tests/test_dependent_fixtures.py @@ -6,3 +6,8 @@ async def test_dependent_fixture(dependent_fixture): """Test a dependent fixture.""" await asyncio.sleep(0.1) + + +@pytest.mark.asyncio +async def test_factory_involving_factories(factory_involving_factories): + factory_involving_factories() From 740af1843f1dafb47ba6db236c1e354731993949 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:38:54 +0200 Subject: [PATCH 007/198] Close event loops when replacing them --- Makefile | 21 +++++++ README.rst | 2 + pytest_asyncio/plugin.py | 77 +++++++++++++++---------- tests/sessionloop/conftest.py | 19 ++++++ tests/sessionloop/test_session_loops.py | 16 +++++ tests/test_event_loop_scope.py | 1 + 6 files changed, 107 insertions(+), 29 deletions(-) create mode 100644 Makefile create mode 100644 tests/sessionloop/conftest.py create mode 100644 tests/sessionloop/test_session_loops.py diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..e22e0449 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +.PHONY: clean clean-build clean-pyc clean-test + +clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts + +clean-build: ## remove build artifacts + rm -fr build/ + rm -fr dist/ + rm -fr .eggs/ + find . -name '*.egg-info' -exec rm -fr {} + + find . -name '*.egg' -exec rm -f {} + + +clean-pyc: ## remove Python file artifacts + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + +clean-test: ## remove test and coverage artifacts + rm -fr .tox/ + rm -f .coverage + rm -fr htmlcov/ diff --git a/README.rst b/README.rst index aa757b68..2d080158 100644 --- a/README.rst +++ b/README.rst @@ -168,6 +168,8 @@ Changelog - Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. - Set ``unused_tcp_port_factory`` fixture scope to 'session'. `#163 `_ +- Properly close event loops when replacing them. + `#208 `_ 0.14.0 (2020-06-24) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 0f29be12..61101e85 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -6,13 +6,16 @@ import socket import pytest + try: from _pytest.python import transfer_markers except ImportError: # Pytest 4.1.0 removes the transfer_marker api (#104) + def transfer_markers(*args, **kwargs): # noqa """Noop when over pytest 4.1.0""" pass + from inspect import isasyncgenfunction @@ -23,10 +26,12 @@ def _is_coroutine(obj): def pytest_configure(config): """Inject documentation.""" - config.addinivalue_line("markers", - "asyncio: " - "mark the test as a coroutine, it will be " - "run using an asyncio event loop") + config.addinivalue_line( + "markers", + "asyncio: " + "mark the test as a coroutine, it will be " + "run using an asyncio event loop", + ) @pytest.mark.tryfirst @@ -41,12 +46,13 @@ def pytest_pycollect_makeitem(collector, name, obj): transfer_markers(obj, item.cls, item.module) item = pytest.Function.from_parent(collector, name=name) # To reload keywords. - if 'asyncio' in item.keywords: + if "asyncio" in item.keywords: return list(collector._genfunctions(name, obj)) class FixtureStripper: """Include additional Fixture, and then strip them""" + REQUEST = "request" EVENT_LOOP = "event_loop" @@ -59,7 +65,7 @@ def add(self, name): and record in to_strip list (If not previously included)""" if name in self.fixturedef.argnames: return - self.fixturedef.argnames += (name, ) + self.fixturedef.argnames += (name,) self.to_strip.add(name) def get_and_strip_from(self, name, data_dict): @@ -69,6 +75,7 @@ def get_and_strip_from(self, name, data_dict): del data_dict[name] return result + @pytest.hookimpl(trylast=True) def pytest_fixture_post_finalizer(fixturedef, request): """Called after fixture teardown""" @@ -77,7 +84,6 @@ def pytest_fixture_post_finalizer(fixturedef, request): asyncio.set_event_loop_policy(None) - @pytest.hookimpl(hookwrapper=True) def pytest_fixture_setup(fixturedef, request): """Adjust the event loop policy when an event loop is produced.""" @@ -85,6 +91,9 @@ def pytest_fixture_setup(fixturedef, request): outcome = yield loop = outcome.get_result() policy = asyncio.get_event_loop_policy() + old_loop = policy.get_event_loop() + if old_loop is not loop: + old_loop.close() policy.set_event_loop(loop) return @@ -96,10 +105,13 @@ def pytest_fixture_setup(fixturedef, request): fixture_stripper.add(FixtureStripper.EVENT_LOOP) fixture_stripper.add(FixtureStripper.REQUEST) - def wrapper(*args, **kwargs): - loop = fixture_stripper.get_and_strip_from(FixtureStripper.EVENT_LOOP, kwargs) - request = fixture_stripper.get_and_strip_from(FixtureStripper.REQUEST, kwargs) + loop = fixture_stripper.get_and_strip_from( + FixtureStripper.EVENT_LOOP, kwargs + ) + request = fixture_stripper.get_and_strip_from( + FixtureStripper.REQUEST, kwargs + ) gen_obj = generator(*args, **kwargs) @@ -109,6 +121,7 @@ async def setup(): def finalizer(): """Yield again, to finalize.""" + async def async_finalizer(): try: await gen_obj.__anext__() @@ -118,6 +131,7 @@ async def async_finalizer(): msg = "Async generator fixture didn't stop." msg += "Yield only once." raise ValueError(msg) + loop.run_until_complete(async_finalizer()) request.addfinalizer(finalizer) @@ -131,7 +145,9 @@ async def async_finalizer(): fixture_stripper.add(FixtureStripper.EVENT_LOOP) def wrapper(*args, **kwargs): - loop = fixture_stripper.get_and_strip_from(FixtureStripper.EVENT_LOOP, kwargs) + loop = fixture_stripper.get_and_strip_from( + FixtureStripper.EVENT_LOOP, kwargs + ) async def setup(): res = await coro(*args, **kwargs) @@ -149,16 +165,15 @@ def pytest_pyfunc_call(pyfuncitem): Run asyncio marked test functions in an event loop instead of a normal function call. """ - if 'asyncio' in pyfuncitem.keywords: - if getattr(pyfuncitem.obj, 'is_hypothesis_test', False): + if "asyncio" in pyfuncitem.keywords: + if getattr(pyfuncitem.obj, "is_hypothesis_test", False): pyfuncitem.obj.hypothesis.inner_test = wrap_in_sync( pyfuncitem.obj.hypothesis.inner_test, - _loop=pyfuncitem.funcargs['event_loop'] + _loop=pyfuncitem.funcargs["event_loop"], ) else: pyfuncitem.obj = wrap_in_sync( - pyfuncitem.obj, - _loop=pyfuncitem.funcargs['event_loop'] + pyfuncitem.obj, _loop=pyfuncitem.funcargs["event_loop"] ) yield @@ -181,22 +196,25 @@ def inner(**kwargs): if task.done() and not task.cancelled(): task.exception() raise + return inner def pytest_runtest_setup(item): - if 'asyncio' in item.keywords: + if "asyncio" in item.keywords: # inject an event loop fixture for all async tests - if 'event_loop' in item.fixturenames: - item.fixturenames.remove('event_loop') - item.fixturenames.insert(0, 'event_loop') - if item.get_closest_marker("asyncio") is not None \ - and not getattr(item.obj, 'hypothesis', False) \ - and getattr(item.obj, 'is_hypothesis_test', False): - pytest.fail( - 'test function `%r` is using Hypothesis, but pytest-asyncio ' - 'only works with Hypothesis 3.64.0 or later.' % item - ) + if "event_loop" in item.fixturenames: + item.fixturenames.remove("event_loop") + item.fixturenames.insert(0, "event_loop") + if ( + item.get_closest_marker("asyncio") is not None + and not getattr(item.obj, "hypothesis", False) + and getattr(item.obj, "is_hypothesis_test", False) + ): + pytest.fail( + "test function `%r` is using Hypothesis, but pytest-asyncio " + "only works with Hypothesis 3.64.0 or later." % item + ) @pytest.fixture @@ -210,7 +228,7 @@ def event_loop(request): def _unused_tcp_port(): """Find an unused localhost TCP port from 1024-65535 and return it.""" with contextlib.closing(socket.socket()) as sock: - sock.bind(('127.0.0.1', 0)) + sock.bind(("127.0.0.1", 0)) return sock.getsockname()[1] @@ -219,7 +237,7 @@ def unused_tcp_port(): return _unused_tcp_port() -@pytest.fixture(scope='session') +@pytest.fixture(scope="session") def unused_tcp_port_factory(): """A factory function, producing different unused TCP ports.""" produced = set() @@ -234,4 +252,5 @@ def factory(): produced.add(port) return port + return factory diff --git a/tests/sessionloop/conftest.py b/tests/sessionloop/conftest.py new file mode 100644 index 00000000..6c657688 --- /dev/null +++ b/tests/sessionloop/conftest.py @@ -0,0 +1,19 @@ +import asyncio + +import pytest + + +class CustomSelectorLoopSession(asyncio.SelectorEventLoop): + """A subclass with no overrides, just to test for presence.""" + + pass + + +loop = CustomSelectorLoopSession() + + +@pytest.fixture(scope="package") +def event_loop(): + """Create an instance of the default event loop for each test case.""" + yield loop + loop.close() diff --git a/tests/sessionloop/test_session_loops.py b/tests/sessionloop/test_session_loops.py new file mode 100644 index 00000000..acb67165 --- /dev/null +++ b/tests/sessionloop/test_session_loops.py @@ -0,0 +1,16 @@ +"""Unit tests for overriding the event loop with a session scoped one.""" +import asyncio + +import pytest + + +@pytest.mark.asyncio +async def test_for_custom_loop(): + """This test should be executed using the custom loop.""" + await asyncio.sleep(0.01) + assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoopSession" + + +@pytest.mark.asyncio +async def test_dependent_fixture(dependent_fixture): + await asyncio.sleep(0.1) diff --git a/tests/test_event_loop_scope.py b/tests/test_event_loop_scope.py index ed07d98d..ccfeffe6 100644 --- a/tests/test_event_loop_scope.py +++ b/tests/test_event_loop_scope.py @@ -3,6 +3,7 @@ These tests need to be run together. """ import asyncio + import pytest From 70cbdeff9f9b04635714b2347ebdbea71acd93a6 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:42:18 +0200 Subject: [PATCH 008/198] Travis -> GitHub Actions --- .github/workflows/main.yml | 68 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 20 ----------- tox.ini | 8 +++++ 3 files changed, 76 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..7db4a00f --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,68 @@ +--- +name: CI + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + workflow_dispatch: + +jobs: + tests: + name: "Python ${{ matrix.python-version }}" + runs-on: "ubuntu-latest" + env: + USING_COVERAGE: "3.6,3.7,3.8,3.9" + + strategy: + matrix: + python-version: ["3.6", "3.7", "3.8", "3.9"] + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v2" + with: + python-version: "${{ matrix.python-version }}" + - name: "Install dependencies" + run: | + set -xe + python -VV + python -m site + python -m pip install --upgrade pip wheel poetry + python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions + - name: "Run tox targets for ${{ matrix.python-version }}" + run: "python -m tox" + + # We always use a modern Python version for combining coverage to prevent + # parsing errors in older versions for modern code. + - uses: "actions/setup-python@v2" + with: + python-version: "3.9" + + - name: "Upload coverage to Codecov" + if: "contains(env.USING_COVERAGE, matrix.python-version)" + uses: "codecov/codecov-action@v1" + with: + fail_ci_if_error: true + + package: + name: "Build & verify package" + runs-on: "ubuntu-latest" + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v2" + with: + python-version: "3.9" + + - name: "Install poetry, check-wheel-content, and twine" + run: "python -m pip install twine check-wheel-contents" + - name: "Build package" + run: "python setup.py sdist bdist_wheel" + - name: "List result" + run: "ls -l dist" + - name: "Check wheel contents" + run: "check-wheel-contents dist/*.whl" + - name: "Check long_description" + run: "python -m twine check dist/*" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a19d5d73..00000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: python - -matrix: - include: - - python: 3.6 - env: TOX_ENV=py36 - - python: 3.7 - env: TOX_ENV=py37 - - python: 3.8 - env: TOX_ENV=py38 - - python: 3.9-dev - env: TOX_ENV=py39 - -install: pip install tox-travis coveralls - -script: tox -e $TOX_ENV - -after_success: - - tox -e coverage-report - - coveralls diff --git a/tox.ini b/tox.ini index f739cc51..c61bd4c0 100644 --- a/tox.ini +++ b/tox.ini @@ -13,3 +13,11 @@ skip_install = true commands = coverage combine coverage report + +[gh-actions] +python = + 3.6: py36 + 3.7: py37 + 3.8: py38 + 3.9: py39, lint + pypy3: pypy3 From 22e338a4dbf67a08146757cc3a2320b7e88c7eae Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:43:48 +0200 Subject: [PATCH 009/198] Fix CI --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7db4a00f..f5cb2260 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: python-version: "3.9" - name: "Install poetry, check-wheel-content, and twine" - run: "python -m pip install twine check-wheel-contents" + run: "python -m pip install wheel twine check-wheel-contents" - name: "Build package" run: "python setup.py sdist bdist_wheel" - name: "List result" From 5c47b78ebfab7a42a9450b88e4a13bf5b135e228 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:50:22 +0200 Subject: [PATCH 010/198] Covecov --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2d080158..0862705a 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ pytest-asyncio: pytest support for asyncio :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://codecov.io/gh/pytest-dev/pytest-asyncio/branch/master/graph/badge.svg + :target: https://codecov.io/gh/pytest-dev/pytest-asyncio .. image:: https://img.shields.io/pypi/pyversions/pytest-asyncio.svg :target: https://github.com/pytest-dev/pytest-asyncio :alt: Supported Python versions From 22d91b2a6df1b3557cfc0370736d7cad4ba8bef4 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:57:20 +0200 Subject: [PATCH 011/198] Black linting --- Makefile | 6 ++- README.rst | 2 + pytest_asyncio/plugin.py | 2 +- setup.cfg | 3 ++ .../test_async_fixtures_scope.py | 5 ++- .../test_async_fixtures_with_finalizer.py | 5 +++ .../async_fixtures/test_async_gen_fixtures.py | 3 +- .../async_fixtures/test_coroutine_fixtures.py | 4 +- tests/async_fixtures/test_nested.py | 11 ++--- tests/conftest.py | 3 +- tests/markers/test_class_marker.py | 2 + tests/markers/test_module_marker.py | 2 + tests/multiloop/conftest.py | 1 + tests/test_simple.py | 43 ++++++++----------- tests/test_subprocess.py | 11 ++--- tox.ini | 10 +++++ 16 files changed, 71 insertions(+), 42 deletions(-) diff --git a/Makefile b/Makefile index e22e0449..425015de 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean clean-build clean-pyc clean-test +.PHONY: clean clean-build clean-pyc clean-test lint clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts @@ -19,3 +19,7 @@ clean-test: ## remove test and coverage artifacts rm -fr .tox/ rm -f .coverage rm -fr htmlcov/ + +lint: ## check style with flake8 + flake8 pytest_asyncio tests + black --check --verbose pytest_asyncio tests diff --git a/README.rst b/README.rst index 0862705a..ee5119f0 100644 --- a/README.rst +++ b/README.rst @@ -10,6 +10,8 @@ pytest-asyncio: pytest support for asyncio .. image:: https://img.shields.io/pypi/pyversions/pytest-asyncio.svg :target: https://github.com/pytest-dev/pytest-asyncio :alt: Supported Python versions +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black pytest-asyncio is an Apache2 licensed library, written in Python, for testing asyncio code with pytest. diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 61101e85..80cce291 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -62,7 +62,7 @@ def __init__(self, fixturedef): def add(self, name): """Add fixture name to fixturedef - and record in to_strip list (If not previously included)""" + and record in to_strip list (If not previously included)""" if name in self.fixturedef.argnames: return self.fixturedef.argnames += (name,) diff --git a/setup.cfg b/setup.cfg index 4a0e3005..01610865 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,3 +12,6 @@ filterwarnings = error [metadata] # ensure LICENSE is included in wheel metadata license_file = LICENSE + +[flake8] +ignore = E203, E501, W503 diff --git a/tests/async_fixtures/test_async_fixtures_scope.py b/tests/async_fixtures/test_async_fixtures_scope.py index 0d8682cc..b150f8a8 100644 --- a/tests/async_fixtures/test_async_fixtures_scope.py +++ b/tests/async_fixtures/test_async_fixtures_scope.py @@ -3,16 +3,17 @@ module-scoped too. """ import asyncio + import pytest -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def event_loop(): """A module-scoped event loop.""" return asyncio.new_event_loop() -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") async def async_fixture(): await asyncio.sleep(0.1) return 1 diff --git a/tests/async_fixtures/test_async_fixtures_with_finalizer.py b/tests/async_fixtures/test_async_fixtures_with_finalizer.py index 44b5bbe4..c602d908 100644 --- a/tests/async_fixtures/test_async_fixtures_with_finalizer.py +++ b/tests/async_fixtures/test_async_fixtures_with_finalizer.py @@ -1,5 +1,6 @@ import asyncio import functools + import pytest @@ -8,11 +9,13 @@ async def test_module_with_event_loop_finalizer(port_with_event_loop_finalizer): await asyncio.sleep(0.01) assert port_with_event_loop_finalizer + @pytest.mark.asyncio async def test_module_with_get_event_loop_finalizer(port_with_get_event_loop_finalizer): await asyncio.sleep(0.01) assert port_with_get_event_loop_finalizer + @pytest.fixture(scope="module") def event_loop(): """Change event_loop fixture to module level.""" @@ -29,6 +32,7 @@ async def port_afinalizer(): # await task using loop provided by event_loop fixture # RuntimeError is raised if task is created on a different loop await finalizer + event_loop.run_until_complete(port_afinalizer()) worker = asyncio.ensure_future(asyncio.sleep(0.2)) @@ -43,6 +47,7 @@ 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 finalizer + asyncio.get_event_loop().run_until_complete(port_afinalizer()) worker = asyncio.ensure_future(asyncio.sleep(0.2)) diff --git a/tests/async_fixtures/test_async_gen_fixtures.py b/tests/async_fixtures/test_async_gen_fixtures.py index 81b21949..0bea7458 100644 --- a/tests/async_fixtures/test_async_gen_fixtures.py +++ b/tests/async_fixtures/test_async_gen_fixtures.py @@ -1,4 +1,3 @@ -import asyncio import unittest.mock import pytest @@ -8,7 +7,7 @@ RETVAL = object() -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def mock(): return unittest.mock.Mock(return_value=RETVAL) diff --git a/tests/async_fixtures/test_coroutine_fixtures.py b/tests/async_fixtures/test_coroutine_fixtures.py index 77f203c9..65dabab5 100644 --- a/tests/async_fixtures/test_coroutine_fixtures.py +++ b/tests/async_fixtures/test_coroutine_fixtures.py @@ -7,7 +7,9 @@ END = object() RETVAL = object() -pytestmark = pytest.mark.skip(reason='@asyncio.coroutine fixtures are not supported yet') +pytestmark = pytest.mark.skip( + reason="@asyncio.coroutine fixtures are not supported yet" +) @pytest.fixture diff --git a/tests/async_fixtures/test_nested.py b/tests/async_fixtures/test_nested.py index 86e45b6b..e81e7824 100644 --- a/tests/async_fixtures/test_nested.py +++ b/tests/async_fixtures/test_nested.py @@ -1,25 +1,26 @@ import asyncio + import pytest @pytest.fixture() async def async_inner_fixture(): await asyncio.sleep(0.01) - print('inner start') + print("inner start") yield True - print('inner stop') + print("inner stop") @pytest.fixture() async def async_fixture_outer(async_inner_fixture, event_loop): await asyncio.sleep(0.01) - print('outer start') + print("outer start") assert async_inner_fixture is True yield True - print('outer stop') + print("outer stop") @pytest.mark.asyncio async def test_async_fixture(async_fixture_outer): assert async_fixture_outer is True - print('test_async_fixture') + print("test_async_fixture") diff --git a/tests/conftest.py b/tests/conftest.py index 9e046123..03fd33f2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,8 +22,9 @@ async def just_a_sleep(): assert counter == 2 -@pytest.fixture(scope='session', name='factory_involving_factories') +@pytest.fixture(scope="session", name="factory_involving_factories") def factory_involving_factories_fixture(unused_tcp_port_factory): def factory(): return unused_tcp_port_factory() + return factory diff --git a/tests/markers/test_class_marker.py b/tests/markers/test_class_marker.py index df137e7c..d46c3af7 100644 --- a/tests/markers/test_class_marker.py +++ b/tests/markers/test_class_marker.py @@ -1,5 +1,6 @@ """Test if pytestmark works when defined on a class.""" import asyncio + import pytest @@ -14,6 +15,7 @@ async def inc(): nonlocal counter counter += 1 await asyncio.sleep(0) + await asyncio.ensure_future(inc()) assert counter == 2 diff --git a/tests/markers/test_module_marker.py b/tests/markers/test_module_marker.py index c5ce0b04..2f69dbc9 100644 --- a/tests/markers/test_module_marker.py +++ b/tests/markers/test_module_marker.py @@ -24,10 +24,12 @@ async def inc(): async def test_is_asyncio(event_loop, sample_fixture): assert asyncio.get_event_loop() counter = 1 + async def inc(): nonlocal counter counter += 1 await asyncio.sleep(0) + await asyncio.ensure_future(inc()) assert counter == 2 diff --git a/tests/multiloop/conftest.py b/tests/multiloop/conftest.py index 1b62a1d0..9c74a509 100644 --- a/tests/multiloop/conftest.py +++ b/tests/multiloop/conftest.py @@ -5,6 +5,7 @@ class CustomSelectorLoop(asyncio.SelectorEventLoop): """A subclass with no overrides, just to test for presence.""" + pass diff --git a/tests/test_simple.py b/tests/test_simple.py index 62b4036e..b5b57ed5 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,20 +1,20 @@ """Quick'n'dirty unit tests for provided fixtures and markers.""" import asyncio -import pytest +import pytest import pytest_asyncio.plugin async def async_coro(): await asyncio.sleep(0) - return 'ok' + 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()) - assert ret == 'ok' + assert ret == "ok" @pytest.mark.asyncio @@ -23,7 +23,7 @@ async def test_asyncio_marker(): await asyncio.sleep(0) -@pytest.mark.xfail(reason='need a failure', strict=True) +@pytest.mark.xfail(reason="need a failure", strict=True) @pytest.mark.asyncio def test_asyncio_marker_fail(): assert False @@ -42,12 +42,10 @@ async def test_unused_port_fixture(unused_tcp_port, event_loop): async def closer(_, writer): writer.close() - server1 = await asyncio.start_server(closer, host='localhost', - port=unused_tcp_port) + server1 = await asyncio.start_server(closer, host="localhost", port=unused_tcp_port) with pytest.raises(IOError): - await asyncio.start_server(closer, host='localhost', - port=unused_tcp_port) + await asyncio.start_server(closer, host="localhost", port=unused_tcp_port) server1.close() await server1.wait_closed() @@ -60,20 +58,19 @@ async def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop): async def closer(_, writer): writer.close() - port1, port2, port3 = (unused_tcp_port_factory(), unused_tcp_port_factory(), - unused_tcp_port_factory()) + port1, port2, port3 = ( + unused_tcp_port_factory(), + unused_tcp_port_factory(), + unused_tcp_port_factory(), + ) - server1 = await asyncio.start_server(closer, host='localhost', - port=port1) - server2 = await asyncio.start_server(closer, host='localhost', - port=port2) - server3 = await asyncio.start_server(closer, host='localhost', - port=port3) + server1 = await asyncio.start_server(closer, host="localhost", port=port1) + server2 = await asyncio.start_server(closer, host="localhost", port=port2) + server3 = await asyncio.start_server(closer, host="localhost", port=port3) for port in port1, port2, port3: with pytest.raises(IOError): - await asyncio.start_server(closer, host='localhost', - port=port) + await asyncio.start_server(closer, host="localhost", port=port) server1.close() await server1.wait_closed() @@ -96,8 +93,7 @@ def mock_unused_tcp_port(): else: return 10000 + counter - monkeypatch.setattr(pytest_asyncio.plugin, '_unused_tcp_port', - mock_unused_tcp_port) + monkeypatch.setattr(pytest_asyncio.plugin, "_unused_tcp_port", mock_unused_tcp_port) assert unused_tcp_port_factory() == 10000 assert unused_tcp_port_factory() > 10000 @@ -110,7 +106,7 @@ class Test: async def test_asyncio_marker_method(self, event_loop): """Test the asyncio pytest marker in a Test class.""" ret = await async_coro() - assert ret == 'ok' + assert ret == "ok" class TestUnexistingLoop: @@ -125,7 +121,7 @@ def remove_loop(self): async def test_asyncio_marker_without_loop(self, remove_loop): """Test the asyncio pytest marker in a Test class.""" ret = await async_coro() - assert ret == 'ok' + assert ret == "ok" class TestEventLoopStartedBeforeFixtures: @@ -150,7 +146,6 @@ async def test_event_loop_before_fixture(self, event_loop, loop): assert await loop.run_in_executor(None, self.foo) == 1 - @pytest.mark.asyncio async def test_no_warning_on_skip(): pytest.skip("Test a skip error inside asyncio") @@ -158,4 +153,4 @@ async def test_no_warning_on_skip(): def test_async_close_loop(event_loop): event_loop.close() - return 'ok' + return "ok" diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py index 069c6c22..88ea29ab 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -1,12 +1,11 @@ """Tests for using subprocesses in tests.""" -import sys import asyncio import asyncio.subprocess +import sys import pytest - -if sys.platform == 'win32': +if sys.platform == "win32": # The default asyncio event loop implementation on Windows does not # support subprocesses. Subprocesses are available for Windows if a # ProactorEventLoop is used. @@ -21,7 +20,8 @@ def event_loop(): async def test_subprocess(event_loop): """Starting a subprocess should be possible.""" proc = await asyncio.subprocess.create_subprocess_exec( - sys.executable, '--version', stdout=asyncio.subprocess.PIPE) + sys.executable, "--version", stdout=asyncio.subprocess.PIPE + ) await proc.communicate() @@ -29,5 +29,6 @@ async def test_subprocess(event_loop): async def test_subprocess_forbid(event_loop): """Starting a subprocess should be possible.""" proc = await asyncio.subprocess.create_subprocess_exec( - sys.executable, '--version', stdout=asyncio.subprocess.PIPE) + sys.executable, "--version", stdout=asyncio.subprocess.PIPE + ) await proc.communicate() diff --git a/tox.ini b/tox.ini index c61bd4c0..5b057d75 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,16 @@ skip_missing_interpreters = true extras = testing commands = coverage run -m pytest {posargs} +[testenv:lint] +skip_install = true +basepython = python3.9 +extras = tests +deps = + flake8 + black +commands = + make lint + [testenv:coverage-report] deps = coverage skip_install = true From d4b79ea6481cb498a2fd3feb8a05f48249559d55 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 00:59:04 +0200 Subject: [PATCH 012/198] Lint --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5b057d75..72cfafc2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py36, py37, py38, py39 +envlist = py36, py37, py38, py39, lint skip_missing_interpreters = true [testenv] From dadff91937e03c9cc08b290d14c8bc72aa793f20 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 01:00:51 +0200 Subject: [PATCH 013/198] Remove poetry --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f5cb2260..3d93214d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: set -xe python -VV python -m site - python -m pip install --upgrade pip wheel poetry + python -m pip install --upgrade pip wheel python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" From 7aa574af1830665be23b983407fdff8f5fcf3ccc Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 01:02:05 +0200 Subject: [PATCH 014/198] 0.15.0 --- README.rst | 2 +- pytest_asyncio/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ee5119f0..02f8317c 100644 --- a/README.rst +++ b/README.rst @@ -164,7 +164,7 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- -0.15.0 (UNRELEASED) +0.15.0 (2021-04-19) ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.9 - Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index 11e6bcdc..daaeac51 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.15.0dev0" +__version__ = "0.15.0" From 6f5053bcb2ec06ecd153ad35f1ff355fc7c93de5 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Mon, 19 Apr 2021 01:03:11 +0200 Subject: [PATCH 015/198] 0.16.0 open for business --- README.rst | 4 ++++ pytest_asyncio/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 02f8317c..d96489e2 100644 --- a/README.rst +++ b/README.rst @@ -164,6 +164,10 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- +0.16.0 (UNRELEASED) +~~~~~~~~~~~~~~~~~~~ + + 0.15.0 (2021-04-19) ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.9 diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index daaeac51..21c4d843 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.15.0" +__version__ = "0.16.dev0" From 94c2560a1e4407258c59cb137d11bc2724611eaa Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Tue, 20 Apr 2021 01:04:59 +0200 Subject: [PATCH 016/198] More robust loop replacement --- pytest_asyncio/plugin.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 80cce291..7665ff4d 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -91,9 +91,13 @@ def pytest_fixture_setup(fixturedef, request): outcome = yield loop = outcome.get_result() policy = asyncio.get_event_loop_policy() - old_loop = policy.get_event_loop() - if old_loop is not loop: - old_loop.close() + try: + old_loop = policy.get_event_loop() + if old_loop is not loop: + old_loop.close() + except RuntimeError: + # Swallow this, since it's probably bad event loop hygiene. + pass policy.set_event_loop(loop) return From da50ce539a9c8f090b753a2d872aa1ccf920db0e Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Thu, 22 Apr 2021 01:04:04 +0200 Subject: [PATCH 017/198] 0.15.1 --- README.rst | 6 ++++-- pytest_asyncio/__init__.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index d96489e2..2650c2fb 100644 --- a/README.rst +++ b/README.rst @@ -164,9 +164,11 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- -0.16.0 (UNRELEASED) +0.15.1 (2021-04-22) ~~~~~~~~~~~~~~~~~~~ - +- Hotfix for errors while closing event loops while replacing them. + `#209 `_ + `#210 `_ 0.15.0 (2021-04-19) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index 21c4d843..c802163a 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.16.dev0" +__version__ = "0.15.1" From 29a42651d8577a33ca5567c45df66ccf879e4d7c Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Thu, 22 Apr 2021 01:06:33 +0200 Subject: [PATCH 018/198] Bump to 0.16.0 --- README.rst | 3 +++ pytest_asyncio/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2650c2fb..3b62d7eb 100644 --- a/README.rst +++ b/README.rst @@ -164,6 +164,9 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- +0.16.0 (UNRELEASED) +~~~~~~~~~~~~~~~~~~~ + 0.15.1 (2021-04-22) ~~~~~~~~~~~~~~~~~~~ - Hotfix for errors while closing event loops while replacing them. diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index c802163a..fddaf22f 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.15.1" +__version__ = "0.16.0dev0" From e3ec312c1d55b3688e4ce115df7791a0478582d1 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 17 May 2021 16:08:54 +0200 Subject: [PATCH 019/198] Adjusted Hypothesis integration test to use the same event loop initialization as in the plugin. The plugin code creates a new event loop from the current event loop policy, whereas the fixture in the Hypothesis test uses get_event_loop. In Python 3.10 the use of get_event_loop was deprecated and causes the Hypothesis tests to fail. Signed-off-by: Michael Seifert --- tests/test_hypothesis_integration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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()) From b27abe8d138998a75cc4eb519be810439d3ed0d9 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 17 May 2021 16:54:11 +0200 Subject: [PATCH 020/198] refactor: Removed TestUnexistingLoop.remove_loop fixture, because it has no effect. Under Python 3.10, the remove_loop fixture raises: "DeprecationWarning: There is no current event loop" This means that the remove_loop fixture effectively does nothing. The test case is still kept, because it seemingly aims to test that the "asyncio" marker works inside test classes when no "event_loop" fixture is explicitly specified. Signed-off-by: Michael Seifert --- tests/test_simple.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tests/test_simple.py b/tests/test_simple.py index b5b57ed5..27a8184a 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -110,15 +110,8 @@ async def test_asyncio_marker_method(self, event_loop): 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): + async def test_asyncio_marker_without_loop(self): """Test the asyncio pytest marker in a Test class.""" ret = await async_coro() assert ret == "ok" From 70989fd7b626a86db4f75acc40057f982f2c76dd Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 17 May 2021 17:00:26 +0200 Subject: [PATCH 021/198] refactor: Grouped test cases together that are related to the use of the asyncio marker in class-based tests. Rephrased test names and comments to make the test intention more clear. Signed-off-by: Michael Seifert --- tests/test_simple.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_simple.py b/tests/test_simple.py index 27a8184a..854faaf3 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -99,20 +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.mark.asyncio - async def test_asyncio_marker_without_loop(self): - """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" From 2751982f3a84d55aad103ea039cc779537e90720 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 17 May 2021 19:43:53 +0200 Subject: [PATCH 022/198] refactor: Replaced tests asserting that the event loop is properly closed. Under Python 3.10, the tests raise: "DeprecationWarning: There is no current event loop" This means that the asyncio.get_event_loop does not return any existing loop. It creates a new loop as a side effect instead. Therefore, test_1 and test_3 will always be successful. However, it would be wrong to simply delete the tests without a replacement. Although, we cannot retrieve the default loop with get_event_loop, we can still retrieve it from the event loop policy. The new tests do exactly that and assert that the loop is a different object than in the tests before. Signed-off-by: Michael Seifert --- tests/test_event_loop_scope.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) 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 From 1c283bd821249ee3c695ae59bb022d31a1473ae2 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 May 2021 08:15:03 +0200 Subject: [PATCH 023/198] refactor: test_async_fixtures_with_finalizer no longer trigger a DeprecationWarning on Python 3.10. The code was adjusted to use asyncio.get_event_loop_policy().get_event_loop() rather than the deprecated asyncio.get_event_loop(). Some additional comments were added to clarify the circumstances under which the test can fail. Signed-off-by: Michael Seifert --- .../async_fixtures/test_async_fixtures_with_finalizer.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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)) From be3b32777b32774c288b604f0d95eacb32a4d1a2 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 May 2021 08:16:19 +0200 Subject: [PATCH 024/198] build: Include Python 3.10 in Tox test runs. Signed-off-by: Michael Seifert --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From 42ff5d176b2be5aa77a43f586179d563ae2196b5 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 May 2021 08:18:28 +0200 Subject: [PATCH 025/198] ci: Include Python 3.10 in the CI test run. Signed-off-by: Michael Seifert --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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" From 6ec76477061ea14394cadbf2cef673b04971ef4d Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 May 2021 08:21:13 +0200 Subject: [PATCH 026/198] feat: Add support for Python 3.10. Adjusted changelog and setup.py accordingly. Signed-off-by: Michael Seifert --- README.rst | 1 + setup.py | 1 + 2 files changed, 2 insertions(+) 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", ], From 4e1df3191aee1a902c873901b35d82363e13b08c Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 16 Oct 2021 01:26:56 +0200 Subject: [PATCH 027/198] Remove obsolete test, add make test --- Makefile | 5 +++- .../async_fixtures/test_coroutine_fixtures.py | 29 ------------------- 2 files changed, 4 insertions(+), 30 deletions(-) delete mode 100644 tests/async_fixtures/test_coroutine_fixtures.py diff --git a/Makefile b/Makefile index 425015de..8cf88841 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: clean clean-build clean-pyc clean-test lint +.PHONY: clean clean-build clean-pyc clean-test lint test clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts @@ -23,3 +23,6 @@ clean-test: ## remove test and coverage artifacts lint: ## check style with flake8 flake8 pytest_asyncio tests black --check --verbose pytest_asyncio tests + +test: + pytest tests diff --git a/tests/async_fixtures/test_coroutine_fixtures.py b/tests/async_fixtures/test_coroutine_fixtures.py deleted file mode 100644 index 65dabab5..00000000 --- a/tests/async_fixtures/test_coroutine_fixtures.py +++ /dev/null @@ -1,29 +0,0 @@ -import asyncio -import unittest.mock - -import pytest - -START = object() -END = object() -RETVAL = object() - -pytestmark = pytest.mark.skip( - reason="@asyncio.coroutine fixtures are not supported yet" -) - - -@pytest.fixture -def mock(): - return unittest.mock.Mock(return_value=RETVAL) - - -@pytest.fixture -async def coroutine_fixture(mock): - await asyncio.sleep(0.1, result=mock(START)) - - -@pytest.mark.asyncio -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 From f2fe98e5cbc4a25e31c24f5932d66f9c903f0fe5 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 16 Oct 2021 01:28:39 +0200 Subject: [PATCH 028/198] 0.16.0 --- README.rst | 2 +- pytest_asyncio/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 02e7b634..7e6c975d 100644 --- a/README.rst +++ b/README.rst @@ -164,7 +164,7 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- -0.16.0 (UNRELEASED) +0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.10 diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index fddaf22f..b16159e7 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,2 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.16.0dev0" +__version__ = "0.16.0" From dcebf1fe82067bbddeec24c97d11a6e4e0364063 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 16 Oct 2021 01:54:12 +0200 Subject: [PATCH 029/198] Update CI badge --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 7e6c975d..dd9459c2 100644 --- a/README.rst +++ b/README.rst @@ -3,10 +3,10 @@ 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://github.com/Tinche/cattrs/workflows/CI/badge.svg + :target: https://github.com/Tinche/cattrs/actions?workflow=CI .. image:: https://codecov.io/gh/pytest-dev/pytest-asyncio/branch/master/graph/badge.svg - :target: https://codecov.io/gh/pytest-dev/pytest-asyncio + :target: https://codecov.io/gh/pytest-dev/pytest-asyncio .. image:: https://img.shields.io/pypi/pyversions/pytest-asyncio.svg :target: https://github.com/pytest-dev/pytest-asyncio :alt: Supported Python versions From f21e0da345f877755b89ff87b6dcea70815b4497 Mon Sep 17 00:00:00 2001 From: Tin Tvrtkovic Date: Sat, 16 Oct 2021 01:55:22 +0200 Subject: [PATCH 030/198] Durr --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index dd9459c2..d3c155ee 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,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://github.com/Tinche/cattrs/workflows/CI/badge.svg - :target: https://github.com/Tinche/cattrs/actions?workflow=CI +.. image:: https://github.com/pytest-dev/pytest-asyncio/workflows/CI/badge.svg + :target: https://github.com/pytest-dev/pytest-asyncio/actions?workflow=CI .. image:: https://codecov.io/gh/pytest-dev/pytest-asyncio/branch/master/graph/badge.svg :target: https://codecov.io/gh/pytest-dev/pytest-asyncio .. image:: https://img.shields.io/pypi/pyversions/pytest-asyncio.svg From b521f40787067cc42edf8dfafab2bb7870a8bfeb Mon Sep 17 00:00:00 2001 From: "Kian-Meng, Ang" Date: Wed, 29 Dec 2021 13:51:14 +0800 Subject: [PATCH 031/198] Fix typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d3c155ee..a4525476 100644 --- a/README.rst +++ b/README.rst @@ -139,7 +139,7 @@ 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 the introductory section for an example. -The event loop used can be overriden by overriding the ``event_loop`` fixture +The event loop used can be overridden by overriding the ``event_loop`` fixture (see above). In order to make your test code a little more concise, the pytest |pytestmark|_ From dceeb686ce1e7b24761e21cf09951ec013066ccd Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Fri, 31 Dec 2021 19:57:19 +0300 Subject: [PATCH 032/198] Use `python@3.10` in CI --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3b249ffb..96f26196 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10-dev"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] steps: - uses: "actions/checkout@v2" From a6758a1c55c71e2a229905ee1b2ba9d7e8010b69 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 5 Oct 2020 14:23:28 +0200 Subject: [PATCH 033/198] Teardown of the event_loop fixture no longer replaces the event loop policy. Signed-off-by: Michael Seifert --- README.rst | 4 ++++ pytest_asyncio/plugin.py | 7 +++++-- tests/respect_event_loop_policy/conftest.py | 16 ++++++++++++++++ .../test_respects_event_loop_policy.py | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/respect_event_loop_policy/conftest.py create mode 100644 tests/respect_event_loop_policy/test_respects_event_loop_policy.py diff --git a/README.rst b/README.rst index a4525476..b1eaa0b1 100644 --- a/README.rst +++ b/README.rst @@ -164,6 +164,10 @@ Only test coroutines will be affected (by default, coroutines prefixed by Changelog --------- +0.17.0 (UNRELEASED) +~~~~~~~~~~~~~~~~~~~ +- `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ + 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ - Add support for Python 3.10 diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 7665ff4d..4fbabfd1 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -80,8 +80,11 @@ def get_and_strip_from(self, name, data_dict): def pytest_fixture_post_finalizer(fixturedef, request): """Called after fixture teardown""" if fixturedef.argname == "event_loop": - # Set empty loop policy, so that subsequent get_event_loop() provides a new loop - asyncio.set_event_loop_policy(None) + policy = asyncio.get_event_loop_policy() + policy.get_event_loop().close() # Clean up existing loop to avoid ResourceWarnings + new_loop = policy.new_event_loop() # Replace existing event loop + # Ensure subsequent calls to get_event_loop() succeed + policy.set_event_loop(new_loop) @pytest.hookimpl(hookwrapper=True) diff --git a/tests/respect_event_loop_policy/conftest.py b/tests/respect_event_loop_policy/conftest.py new file mode 100644 index 00000000..2c5cef24 --- /dev/null +++ b/tests/respect_event_loop_policy/conftest.py @@ -0,0 +1,16 @@ +"""Defines and sets a custom event loop policy""" +import asyncio +from asyncio import DefaultEventLoopPolicy, SelectorEventLoop + + +class TestEventLoop(SelectorEventLoop): + pass + + +class TestEventLoopPolicy(DefaultEventLoopPolicy): + def new_event_loop(self): + return TestEventLoop() + + +# This statement represents a code which sets a custom event loop policy +asyncio.set_event_loop_policy(TestEventLoopPolicy()) diff --git a/tests/respect_event_loop_policy/test_respects_event_loop_policy.py b/tests/respect_event_loop_policy/test_respects_event_loop_policy.py new file mode 100644 index 00000000..2537ca24 --- /dev/null +++ b/tests/respect_event_loop_policy/test_respects_event_loop_policy.py @@ -0,0 +1,16 @@ +"""Tests that any externally provided event loop policy remains unaltered.""" +import asyncio + +import pytest + + +@pytest.mark.asyncio +async def test_uses_loop_provided_by_custom_policy(): + """Asserts that test cases use the event loop provided by the custom event loop policy""" + assert type(asyncio.get_event_loop()).__name__ == "TestEventLoop" + + +@pytest.mark.asyncio +async def test_custom_policy_is_not_overwritten(): + """Asserts that any custom event loop policy stays the same across test cases""" + assert type(asyncio.get_event_loop()).__name__ == "TestEventLoop" From 5079642c7de82ff8dfe5b1dcd1544017dfb6c196 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Wed, 5 Jan 2022 11:18:45 +0100 Subject: [PATCH 034/198] refactor: Removed use of obsolete transfer_markers during test collection phase. transfer_markers was removed in Pytest 4.1. The minimum required pytest version for pytest-asyncio is currently v5.4.0. That means that `transfer_markers` is always a no-op. Signed-off-by: Michael Seifert --- pytest_asyncio/plugin.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 4fbabfd1..70564ff8 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -7,15 +7,6 @@ import pytest -try: - from _pytest.python import transfer_markers -except ImportError: # Pytest 4.1.0 removes the transfer_marker api (#104) - - def transfer_markers(*args, **kwargs): # noqa - """Noop when over pytest 4.1.0""" - pass - - from inspect import isasyncgenfunction @@ -39,13 +30,6 @@ def pytest_pycollect_makeitem(collector, name, obj): """A pytest hook to collect asyncio coroutines.""" if collector.funcnamefilter(name) and _is_coroutine(obj): item = pytest.Function.from_parent(collector, name=name) - - # Due to how pytest test collection works, module-level pytestmarks - # are applied after the collection step. Since this is the collection - # step, we look ourselves. - transfer_markers(obj, item.cls, item.module) - item = pytest.Function.from_parent(collector, name=name) # To reload keywords. - if "asyncio" in item.keywords: return list(collector._genfunctions(name, obj)) From f6fe76849c26a53f9702a3fadd3b5863c4656e72 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 2 Aug 2020 10:41:37 -0300 Subject: [PATCH 035/198] Add note about unittest.TestCase not being supported --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index b1eaa0b1..53a270ee 100644 --- a/README.rst +++ b/README.rst @@ -162,6 +162,12 @@ 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 +Note about unittest +------------------- + +Test classes subclassing the standard `unittest `__ library are not supported, users +are recommended to use one of the async frameworks available for that such as `asynctest `__. + Changelog --------- 0.17.0 (UNRELEASED) From f56021d8ac5eeb8187b06cd69d39e3b58733a274 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sun, 2 Aug 2020 13:50:42 -0300 Subject: [PATCH 036/198] Mention IsolatedAsyncioTestCase --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 53a270ee..e15f3acf 100644 --- a/README.rst +++ b/README.rst @@ -166,7 +166,8 @@ Note about unittest ------------------- Test classes subclassing the standard `unittest `__ library are not supported, users -are recommended to use one of the async frameworks available for that such as `asynctest `__. +are recommended to use `unitest.IsolatedAsyncioTestCase `__ +or an async framework such as `asynctest `__. Changelog --------- From 7b2bcc000034b0850abc15877bce2007a2cfad34 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 6 Jan 2022 14:27:56 +0100 Subject: [PATCH 037/198] feat!: Drop support for Python 3.6. CPython 3.6 reached end-of-life on 2021-12-23 [1]. Future releases of pytest will no longer support Python 3.6 [2]. [1] https://www.python.org/dev/peps/pep-0494/ [2] https://github.com/pytest-dev/pytest/pull/9437 Signed-off-by: Michael Seifert --- .github/workflows/main.yml | 4 ++-- README.rst | 1 + setup.py | 3 +-- tox.ini | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 96f26196..b448cd6c 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,3.10" + USING_COVERAGE: "3.7,3.8,3.9,3.10" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: "actions/checkout@v2" diff --git a/README.rst b/README.rst index e15f3acf..f2d64987 100644 --- a/README.rst +++ b/README.rst @@ -174,6 +174,7 @@ Changelog 0.17.0 (UNRELEASED) ~~~~~~~~~~~~~~~~~~~ - `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ +- Drop support for Python 3.6 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ diff --git a/setup.py b/setup.py index e15080fe..ad3877ca 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,6 @@ def find_version(): "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -41,7 +40,7 @@ def find_version(): "Topic :: Software Development :: Testing", "Framework :: Pytest", ], - python_requires=">= 3.6", + python_requires=">= 3.7", install_requires=["pytest >= 5.4.0"], extras_require={ "testing": [ diff --git a/tox.ini b/tox.ini index ef60cba0..edae7dec 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py36, py37, py38, py39, py310, lint +envlist = py37, py38, py39, py310, lint skip_missing_interpreters = true [testenv] @@ -26,7 +26,6 @@ commands = [gh-actions] python = - 3.6: py36 3.7: py37 3.8: py38 3.9: py39, lint From 9f59e28298d17dbf88b9ec23142316c63926aaa7 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 6 Jan 2022 17:36:24 +0200 Subject: [PATCH 038/198] Add 'Framework :: Asyncio' trove classifier --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index ad3877ca..684e315e 100644 --- a/setup.py +++ b/setup.py @@ -38,6 +38,7 @@ def find_version(): "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Software Development :: Testing", + "Framework :: Asyncio", "Framework :: Pytest", ], python_requires=">= 3.7", From 57ccbc79f816313411227bdfeef08556a0468c76 Mon Sep 17 00:00:00 2001 From: wjsi Date: Sat, 10 Jul 2021 16:11:09 +0800 Subject: [PATCH 039/198] Support flaky on async tests --- .gitignore | 3 ++- pytest_asyncio/plugin.py | 7 +++++++ setup.py | 1 + tests/test_flaky_integration.py | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/test_flaky_integration.py diff --git a/.gitignore b/.gitignore index 09758085..447dbc4d 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,5 @@ docs/_build/ target/ .venv* -.idea \ No newline at end of file +.idea +.vscode \ No newline at end of file diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 70564ff8..461bbe5f 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -173,6 +173,12 @@ def wrap_in_sync(func, _loop): """Return a sync wrapper around an async function executing it in the current event loop.""" + # if the function is already wrapped, we rewrap using the original one + # not using __wrapped__ because the original function may already be + # a wrapped one + if hasattr(func, '_raw_test_func'): + func = func._raw_test_func + @functools.wraps(func) def inner(**kwargs): coro = func(**kwargs) @@ -188,6 +194,7 @@ def inner(**kwargs): task.exception() raise + inner._raw_test_func = func return inner diff --git a/setup.py b/setup.py index 684e315e..a0e4aa3e 100644 --- a/setup.py +++ b/setup.py @@ -47,6 +47,7 @@ def find_version(): "testing": [ "coverage", "hypothesis >= 5.7.1", + "flaky >= 3.5.0" ], }, entry_points={"pytest11": ["asyncio = pytest_asyncio.plugin"]}, diff --git a/tests/test_flaky_integration.py b/tests/test_flaky_integration.py new file mode 100644 index 00000000..4628c6a0 --- /dev/null +++ b/tests/test_flaky_integration.py @@ -0,0 +1,17 @@ +"""Tests for the Flaky integration, which retries failed tests. +""" +import asyncio + +import flaky +import pytest + +_threshold = -1 + + +@flaky.flaky(3, 2) +@pytest.mark.asyncio +async def test_asyncio_flaky_thing_that_fails_then_succeeds(): + global _threshold + await asyncio.sleep(0.1) + _threshold += 1 + assert _threshold != 1 From 4ec2b8f944472e66807b831c796429c76184a9d7 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Fri, 7 Jan 2022 12:56:43 +0200 Subject: [PATCH 040/198] Reformat with black --- pytest_asyncio/plugin.py | 2 +- setup.py | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 461bbe5f..81ac2e3f 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -176,7 +176,7 @@ def wrap_in_sync(func, _loop): # if the function is already wrapped, we rewrap using the original one # not using __wrapped__ because the original function may already be # a wrapped one - if hasattr(func, '_raw_test_func'): + if hasattr(func, "_raw_test_func"): func = func._raw_test_func @functools.wraps(func) diff --git a/setup.py b/setup.py index a0e4aa3e..1cd1415c 100644 --- a/setup.py +++ b/setup.py @@ -6,13 +6,9 @@ def find_version(): version_file = ( - Path(__file__) - .parent.joinpath("pytest_asyncio", "__init__.py") - .read_text() - ) - version_match = re.search( - r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M + Path(__file__).parent.joinpath("pytest_asyncio", "__init__.py").read_text() ) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) if version_match: return version_match.group(1) @@ -44,11 +40,7 @@ def find_version(): python_requires=">= 3.7", install_requires=["pytest >= 5.4.0"], extras_require={ - "testing": [ - "coverage", - "hypothesis >= 5.7.1", - "flaky >= 3.5.0" - ], + "testing": ["coverage", "hypothesis >= 5.7.1", "flaky >= 3.5.0"], }, entry_points={"pytest11": ["asyncio = pytest_asyncio.plugin"]}, ) From ff497f7ad6e4e866f0d19c2d02317d47cb85bf14 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 6 Jan 2022 18:39:02 +0100 Subject: [PATCH 041/198] refactor: Moved test_hypothesis_integration to "hypothesis" subfolder and renamed it to "test_base". This allows us to add more tests for the Hypothesis integration while at the same time keep different tests tidy by using different files. Signed-off-by: Michael Seifert --- tests/{test_hypothesis_integration.py => hypothesis/test_base.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{test_hypothesis_integration.py => hypothesis/test_base.py} (100%) diff --git a/tests/test_hypothesis_integration.py b/tests/hypothesis/test_base.py similarity index 100% rename from tests/test_hypothesis_integration.py rename to tests/hypothesis/test_base.py From 7fea8635b00aedd4e42e3c855f71cc6eedf16159 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 6 Jan 2022 18:56:00 +0100 Subject: [PATCH 042/198] fix: Fixed double wrapping of inherited Hypothesis tests. Pytest-asyncio identifies Hypothesis test cases by their `is_hypothesis_test` flag. When setting up an async Hypothesis test pytest-asyncio replaces the function's `hypothesis.inner_test` attribute. The the top level function never changes. When a Hypothesis test case is defined in a base class and inherited by subclasses, the test is collected in each subclass. Since the top-level Hypothesis test never changes, its inner test will be wrapped multiple times. Double wrapping leads to execution errors caused by stale (closed) event loops in all test executions after the first. This change adds an `original_test_function` attribute to the async function wrapper, in order to keep track of the original Hypothesis test. When re-wrapping would occur in subclasses pytest-asyncio wraps the original test function rather than the wrapper function. Closes #231 Signed-off-by: Michael Seifert --- README.rst | 1 + pytest_asyncio/plugin.py | 2 +- tests/hypothesis/test_inherited_test.py | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/hypothesis/test_inherited_test.py diff --git a/README.rst b/README.rst index f2d64987..0faac438 100644 --- a/README.rst +++ b/README.rst @@ -175,6 +175,7 @@ Changelog ~~~~~~~~~~~~~~~~~~~ - `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ - Drop support for Python 3.6 +- Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 461bbe5f..81ac2e3f 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -176,7 +176,7 @@ def wrap_in_sync(func, _loop): # if the function is already wrapped, we rewrap using the original one # not using __wrapped__ because the original function may already be # a wrapped one - if hasattr(func, '_raw_test_func'): + if hasattr(func, "_raw_test_func"): func = func._raw_test_func @functools.wraps(func) diff --git a/tests/hypothesis/test_inherited_test.py b/tests/hypothesis/test_inherited_test.py new file mode 100644 index 00000000..86e92efd --- /dev/null +++ b/tests/hypothesis/test_inherited_test.py @@ -0,0 +1,22 @@ +import hypothesis.strategies as st +from hypothesis import given +import pytest + + +class BaseClass: + @pytest.mark.asyncio + @given(value=st.integers()) + async def test_hypothesis(self, value: int) -> None: + assert True + + +class TestOne(BaseClass): + """During the first execution the Hypothesis test is wrapped in a synchronous function.""" + + pass + + +class TestTwo(BaseClass): + """Execute the test a second time to ensure that the test receives a fresh event loop.""" + + pass From 1af571ed83bf86a15884fd8ba4962435a7d53040 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 6 Jan 2022 19:49:04 +0100 Subject: [PATCH 043/198] doc: Updated docstring of pytest_pyfunc_call. Signed-off-by: Michael Seifert --- pytest_asyncio/plugin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 81ac2e3f..634d1fb7 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -153,8 +153,9 @@ async def setup(): @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_pyfunc_call(pyfuncitem): """ - Run asyncio marked test functions in an event loop instead of a normal - function call. + Pytest hook called before a test case is run. + + Wraps marked tests in a synchronous function where the wrapped test coroutine is executed in an event loop. """ if "asyncio" in pyfuncitem.keywords: if getattr(pyfuncitem.obj, "is_hypothesis_test", False): From 430d69af4bb3d3413e9f796e77011843c2299cc7 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 7 Jan 2022 08:38:03 +0100 Subject: [PATCH 044/198] doc: Mentioned additional test dependency on flaky in the changelog. This is an important information for downstream packagers. Signed-off-by: Michael Seifert --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 0faac438..4d264ce2 100644 --- a/README.rst +++ b/README.rst @@ -176,6 +176,7 @@ Changelog - `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ - Drop support for Python 3.6 - Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ +- Added `flaky `_ to test dependencies 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ From d48569eee5703a845ce189ed6cee10d003cb2660 Mon Sep 17 00:00:00 2001 From: "Dominik S. Buse" Date: Fri, 7 Jan 2022 13:25:14 +0100 Subject: [PATCH 045/198] Add unused port helpers for UDP (#99) * Add unused port helpers for UDP Extends the unused_tcp_port and unused_tcp_port_factory mechanisms for UDP ports. * Update pytest_asyncio/plugin.py * Add changenote Co-authored-by: Andrew Svetlov --- README.rst | 8 +++- pytest_asyncio/plugin.py | 36 ++++++++++++--- tests/test_simple.py | 96 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 4d264ce2..7330e1a9 100644 --- a/README.rst +++ b/README.rst @@ -109,6 +109,11 @@ when several unused TCP ports are required in a test. port1, port2 = unused_tcp_port_factory(), unused_tcp_port_factory() ... +``unused_udp_port`` and ``unused_udp_port_factory`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Work just like their TCP counterparts but return unused UDP ports. + + Async fixtures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Asynchronous fixtures are defined just like ordinary pytest fixtures, except they should be coroutines or asynchronous generators. @@ -166,7 +171,7 @@ Note about unittest ------------------- Test classes subclassing the standard `unittest `__ library are not supported, users -are recommended to use `unitest.IsolatedAsyncioTestCase `__ +are recommended to use `unitest.IsolatedAsyncioTestCase `__ or an async framework such as `asynctest `__. Changelog @@ -177,6 +182,7 @@ Changelog - Drop support for Python 3.6 - Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ - Added `flaky `_ to test dependencies +- Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 634d1fb7..dcaf429b 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -224,16 +224,21 @@ def event_loop(request): loop.close() -def _unused_tcp_port(): - """Find an unused localhost TCP port from 1024-65535 and return it.""" - with contextlib.closing(socket.socket()) as sock: +def _unused_port(socket_type): + """Find an unused localhost port from 1024-65535 and return it.""" + with contextlib.closing(socket.socket(type=socket_type)) as sock: sock.bind(("127.0.0.1", 0)) return sock.getsockname()[1] @pytest.fixture def unused_tcp_port(): - return _unused_tcp_port() + return _unused_port(socket.SOCK_STREAM) + + +@pytest.fixture +def unused_udp_port(): + return _unused_port(socket.SOCK_DGRAM) @pytest.fixture(scope="session") @@ -243,10 +248,29 @@ def unused_tcp_port_factory(): def factory(): """Return an unused port.""" - port = _unused_tcp_port() + port = _unused_port(socket.SOCK_STREAM) + + while port in produced: + port = _unused_port(socket.SOCK_STREAM) + + produced.add(port) + + return port + + return factory + + +@pytest.fixture(scope="session") +def unused_udp_port_factory(): + """A factory function, producing different unused UDP ports.""" + produced = set() + + def factory(): + """Return an unused port.""" + port = _unused_port(socket.SOCK_DGRAM) while port in produced: - port = _unused_tcp_port() + port = _unused_port(socket.SOCK_DGRAM) produced.add(port) diff --git a/tests/test_simple.py b/tests/test_simple.py index 854faaf3..42151852 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -51,6 +51,33 @@ async def closer(_, writer): await server1.wait_closed() +@pytest.mark.asyncio +async def test_unused_udp_port_fixture(unused_udp_port, event_loop): + """Test the unused TCP port fixture.""" + + class Closer: + def connection_made(self, transport): + pass + + def connection_lost(self, *arg, **kwd): + pass + + transport1, _ = await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", unused_udp_port), + reuse_port=False, + ) + + with pytest.raises(IOError): + await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", unused_udp_port), + reuse_port=False, + ) + + transport1.abort() + + @pytest.mark.asyncio async def test_unused_port_factory_fixture(unused_tcp_port_factory, event_loop): """Test the unused TCP port factory fixture.""" @@ -80,11 +107,57 @@ async def closer(_, writer): await server3.wait_closed() +@pytest.mark.asyncio +async def test_unused_udp_port_factory_fixture(unused_udp_port_factory, event_loop): + """Test the unused UDP port factory fixture.""" + + class Closer: + def connection_made(self, transport): + pass + + def connection_lost(self, *arg, **kwd): + pass + + port1, port2, port3 = ( + unused_udp_port_factory(), + unused_udp_port_factory(), + unused_udp_port_factory(), + ) + + transport1, _ = await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", port1), + reuse_port=False, + ) + transport2, _ = await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", port2), + reuse_port=False, + ) + transport3, _ = await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", port3), + reuse_port=False, + ) + + for port in port1, port2, port3: + with pytest.raises(IOError): + await event_loop.create_datagram_endpoint( + Closer, + local_addr=("127.0.0.1", port), + reuse_port=False, + ) + + transport1.abort() + transport2.abort() + transport3.abort() + + def test_unused_port_factory_duplicate(unused_tcp_port_factory, monkeypatch): """Test correct avoidance of duplicate ports.""" counter = 0 - def mock_unused_tcp_port(): + def mock_unused_tcp_port(_ignored): """Force some duplicate ports.""" nonlocal counter counter += 1 @@ -93,12 +166,31 @@ def mock_unused_tcp_port(): else: return 10000 + counter - monkeypatch.setattr(pytest_asyncio.plugin, "_unused_tcp_port", mock_unused_tcp_port) + monkeypatch.setattr(pytest_asyncio.plugin, "_unused_port", mock_unused_tcp_port) assert unused_tcp_port_factory() == 10000 assert unused_tcp_port_factory() > 10000 +def test_unused_udp_port_factory_duplicate(unused_udp_port_factory, monkeypatch): + """Test correct avoidance of duplicate UDP ports.""" + counter = 0 + + def mock_unused_udp_port(_ignored): + """Force some duplicate ports.""" + nonlocal counter + counter += 1 + if counter < 5: + return 10000 + else: + return 10000 + counter + + monkeypatch.setattr(pytest_asyncio.plugin, "_unused_port", mock_unused_udp_port) + + assert unused_udp_port_factory() == 10000 + assert unused_udp_port_factory() > 10000 + + class TestMarkerInClassBasedTests: """Test that asyncio marked functions work for methods of test classes.""" From 82261678994cd251d8392508299cb0f75c136951 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sat, 8 Jan 2022 00:10:31 +0200 Subject: [PATCH 046/198] Fix readme, the plugin now provide fixtures for unused udp ports also (#241) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7330e1a9..bfa9785a 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Features -------- - fixtures for creating and injecting versions of the asyncio event loop -- fixtures for injecting unused tcp ports +- fixtures for injecting unused tcp/udp ports - pytest markers for treating tests as asyncio coroutines - easy testing with non-default event loops - support for `async def` fixtures and async generator fixtures From f86d9004f14789f24f60a86ecd15e1906e8276c6 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Sat, 8 Jan 2022 10:41:41 -0700 Subject: [PATCH 047/198] Add mechanism for explicit marking of fixtures which should be run with asyncio (#125) --- README.rst | 82 ++++++++++++++++- pytest_asyncio/__init__.py | 5 ++ pytest_asyncio/plugin.py | 152 ++++++++++++++++++++++++++++++-- setup.cfg | 1 + tests/modes/test_auto_mode.py | 91 +++++++++++++++++++ tests/modes/test_legacy_mode.py | 115 ++++++++++++++++++++++++ tests/modes/test_strict_mode.py | 70 +++++++++++++++ tests/test_asyncio_fixture.py | 39 ++++++++ 8 files changed, 547 insertions(+), 8 deletions(-) create mode 100644 tests/modes/test_auto_mode.py create mode 100644 tests/modes/test_legacy_mode.py create mode 100644 tests/modes/test_strict_mode.py create mode 100644 tests/test_asyncio_fixture.py diff --git a/README.rst b/README.rst index bfa9785a..acaa99b5 100644 --- a/README.rst +++ b/README.rst @@ -39,6 +39,9 @@ Features - pytest markers for treating tests as asyncio coroutines - easy testing with non-default event loops - support for `async def` fixtures and async generator fixtures +- support *auto* mode to handle all async fixtures and tests automatically by asyncio; + provide *strict* mode if a test suite should work with different async frameworks + simultaneously, e.g. ``asyncio`` and ``trio``. Installation ------------ @@ -51,6 +54,70 @@ To install pytest-asyncio, simply: This is enough for pytest to pick up pytest-asyncio. +Modes +----- + +Starting from ``pytest-asyncio>=0.17``, three modes are provided: *auto*, *strict* and +*legacy* (default). + +The mode can be set by ``asyncio_mode`` configuration option in `configuration file +`_: + +.. code-block:: ini + + # pytest.ini + [pytest] + asyncio_mode = auto + +The value can be overriden by command-line option for ``pytest`` invocation: + +.. code-block:: bash + + $ pytest tests --asyncio-mode=strict + +Auto mode +~~~~~~~~~ + +When the mode is auto, all discovered *async* tests are considered *asyncio-driven* even +if they have no ``@pytest.mark.asyncio`` marker. + +All async fixtures are considered *asyncio-driven* as well, even if they are decorated +with a regular ``@pytest.fixture`` decorator instead of dedicated +``@pytest_asyncio.fixture`` counterpart. + +*asyncio-driven* means that tests and fixtures are executed by ``pytest-asyncio`` +plugin. + +This mode requires the simplest tests and fixtures configuration and is +recommended for default usage *unless* the same project and its test suite should +execute tests from different async frameworks, e.g. ``asyncio`` and ``trio``. In this +case, auto-handling can break tests designed for other framework; plase use *strict* +mode instead. + +Strict mode +~~~~~~~~~~~ + +Strict mode enforces ``@pytest.mark.asyncio`` and ``@pytest_asyncio.fixture`` usage. +Without these markers, tests and fixtures are not considered as *asyncio-driven*, other +pytest plugin can handle them. + +Please use this mode if multiple async frameworks should be combined in the same test +suite. + + +Legacy mode +~~~~~~~~~~~ + +This mode follows rules used by ``pytest-asyncio<0.17``: tests are not auto-marked but +fixtures are. + +This mode is used by default for the sake of backward compatibility, deprecation +warnings are emitted with suggestion to either switching to ``auto`` mode or using +``strict`` mode with ``@pytest_asyncio.fixture`` decorators. + +In future, the default will be changed. + + Fixtures -------- @@ -116,16 +183,18 @@ Work just like their TCP counterparts but return unused UDP ports. Async fixtures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Asynchronous fixtures are defined just like ordinary pytest fixtures, except they should be coroutines or asynchronous generators. +Asynchronous fixtures are defined just like ordinary pytest fixtures, except they should be decorated with ``@pytest_asyncio.fixture``. .. code-block:: python3 - @pytest.fixture + import pytest_asyncio + + @pytest_asyncio.fixture async def async_gen_fixture(): await asyncio.sleep(0.1) yield 'a value' - @pytest.fixture(scope='module') + @pytest_asyncio.fixture(scope='module') async def async_fixture(): return await asyncio.sleep(0.1) @@ -134,6 +203,9 @@ to redefine the ``event_loop`` fixture to have the same or broader scope. Async fixtures need the event loop, and so must have the same or narrower scope than the ``event_loop`` fixture. +*auto* and *legacy* mode automatically converts async fixtures declared with the +standard ``@pytest.fixture`` decorator to *asyncio-driven* versions. + Markers ------- @@ -164,6 +236,10 @@ Only test coroutines will be affected (by default, coroutines prefixed by """No marker!""" await asyncio.sleep(0, loop=event_loop) +In *auto* mode, the ``pytest.mark.asyncio`` marker can be omitted, the marker is added +automatically to *async* test functions. + + .. |pytestmark| replace:: ``pytestmark`` .. _pytestmark: http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index b16159e7..0da62156 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,2 +1,7 @@ """The main point for importing pytest-asyncio items.""" __version__ = "0.16.0" + +from .plugin import fixture + + +__all__ = ("fixture",) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index dcaf429b..44165602 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -1,13 +1,88 @@ """pytest-asyncio implementation.""" import asyncio import contextlib +import enum import functools import inspect import socket +import sys +import warnings import pytest -from inspect import isasyncgenfunction + +class Mode(str, enum.Enum): + AUTO = "auto" + STRICT = "strict" + LEGACY = "legacy" + + +LEGACY_MODE = pytest.PytestDeprecationWarning( + "The 'asyncio_mode' default value will change to 'strict' in future, " + "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " + "in pytest configuration file." +) + +LEGACY_ASYNCIO_FIXTURE = ( + "'@pytest.fixture' is applied to {name} " + "in 'legacy' mode, " + "please replace it with '@pytest_asyncio.fixture' as a preparation " + "for switching to 'strict' mode (or use 'auto' mode to seamlessly handle " + "all these fixtures as asyncio-driven)." +) + + +ASYNCIO_MODE_HELP = """\ +'auto' - for automatically handling all async functions by the plugin +'strict' - for autoprocessing disabling (useful if different async frameworks \ +should be tested together, e.g. \ +both pytest-asyncio and pytest-trio are used in the same project) +'legacy' - for keeping compatibility with pytest-asyncio<0.17: \ +auto-handling is disabled but pytest_asyncio.fixture usage is not enforced +""" + + +def pytest_addoption(parser, pluginmanager): + group = parser.getgroup("asyncio") + group.addoption( + "--asyncio-mode", + dest="asyncio_mode", + default=None, + metavar="MODE", + help=ASYNCIO_MODE_HELP, + ) + parser.addini( + "asyncio_mode", + help="default value for --asyncio-mode", + type="string", + default="legacy", + ) + + +def fixture(fixture_function=None, **kwargs): + if fixture_function is not None: + _set_explicit_asyncio_mark(fixture_function) + return pytest.fixture(fixture_function, **kwargs) + + else: + + @functools.wraps(fixture) + def inner(fixture_function): + return fixture(fixture_function, **kwargs) + + return inner + + +def _has_explicit_asyncio_mark(obj): + obj = getattr(obj, "__func__", obj) # instance method maybe? + return getattr(obj, "_force_asyncio_fixture", False) + + +def _set_explicit_asyncio_mark(obj): + if hasattr(obj, "__func__"): + # instance method, check the function object + obj = obj.__func__ + obj._force_asyncio_fixture = True def _is_coroutine(obj): @@ -15,6 +90,17 @@ def _is_coroutine(obj): return asyncio.iscoroutinefunction(obj) or inspect.isgeneratorfunction(obj) +def _is_coroutine_or_asyncgen(obj): + return _is_coroutine(obj) or inspect.isasyncgenfunction(obj) + + +def _get_asyncio_mode(config): + val = config.getoption("asyncio_mode") + if val is None: + val = config.getini("asyncio_mode") + return Mode(val) + + def pytest_configure(config): """Inject documentation.""" config.addinivalue_line( @@ -23,6 +109,22 @@ def pytest_configure(config): "mark the test as a coroutine, it will be " "run using an asyncio event loop", ) + if _get_asyncio_mode(config) == Mode.LEGACY: + _issue_warning_captured(LEGACY_MODE, config.hook, stacklevel=1) + + +def _issue_warning_captured(warning, hook, *, stacklevel=1): + # copy-paste of pytest internal _pytest.warnings._issue_warning_captured function + with warnings.catch_warnings(record=True) as records: + warnings.simplefilter("always", type(warning)) + warnings.warn(LEGACY_MODE, stacklevel=stacklevel) + frame = sys._getframe(stacklevel - 1) + location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name + hook.pytest_warning_recorded.call_historic( + kwargs=dict( + warning_message=records[0], when="config", nodeid="", location=location + ) + ) @pytest.mark.tryfirst @@ -32,6 +134,13 @@ def pytest_pycollect_makeitem(collector, name, obj): item = pytest.Function.from_parent(collector, name=name) if "asyncio" in item.keywords: return list(collector._genfunctions(name, obj)) + else: + if _get_asyncio_mode(item.config) == Mode.AUTO: + # implicitly add asyncio marker if asyncio mode is on + ret = list(collector._genfunctions(name, obj)) + for elem in ret: + elem.add_marker("asyncio") + return ret class FixtureStripper: @@ -88,9 +197,42 @@ def pytest_fixture_setup(fixturedef, request): policy.set_event_loop(loop) return - if isasyncgenfunction(fixturedef.func): + func = fixturedef.func + if not _is_coroutine_or_asyncgen(func): + # Nothing to do with a regular fixture function + yield + return + + config = request.node.config + asyncio_mode = _get_asyncio_mode(config) + + if not _has_explicit_asyncio_mark(func): + if asyncio_mode == Mode.AUTO: + # Enforce asyncio mode if 'auto' + _set_explicit_asyncio_mark(func) + elif asyncio_mode == Mode.LEGACY: + _set_explicit_asyncio_mark(func) + try: + code = func.__code__ + except AttributeError: + code = func.__func__.__code__ + name = ( + f"" + ) + warnings.warn( + LEGACY_ASYNCIO_FIXTURE.format(name=name), + pytest.PytestDeprecationWarning, + ) + else: + # asyncio_mode is STRICT, + # don't handle fixtures that are not explicitly marked + yield + return + + if inspect.isasyncgenfunction(func): # This is an async generator function. Wrap it accordingly. - generator = fixturedef.func + generator = func fixture_stripper = FixtureStripper(fixturedef) fixture_stripper.add(FixtureStripper.EVENT_LOOP) @@ -129,8 +271,8 @@ async def async_finalizer(): return loop.run_until_complete(setup()) fixturedef.func = wrapper - elif inspect.iscoroutinefunction(fixturedef.func): - coro = fixturedef.func + elif inspect.iscoroutinefunction(func): + coro = func fixture_stripper = FixtureStripper(fixturedef) fixture_stripper.add(FixtureStripper.EVENT_LOOP) diff --git a/setup.cfg b/setup.cfg index 01610865..fc18e3d9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,6 +7,7 @@ show_missing = true [tool:pytest] addopts = -rsx --tb=short testpaths = tests +asyncio_mode = auto filterwarnings = error [metadata] diff --git a/tests/modes/test_auto_mode.py b/tests/modes/test_auto_mode.py new file mode 100644 index 00000000..980b0b04 --- /dev/null +++ b/tests/modes/test_auto_mode.py @@ -0,0 +1,91 @@ +from textwrap import dedent + +pytest_plugins = "pytester" + + +def test_auto_mode_cmdline(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) + + +def test_auto_mode_cfg(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = auto\n") + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_auto_mode_async_fixture(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.fixture + async def fixture_a(): + await asyncio.sleep(0) + return 1 + + async def test_a(fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) + + +def test_auto_mode_method_fixture(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + + class TestA: + + @pytest.fixture + async def fixture_a(self): + await asyncio.sleep(0) + return 1 + + async def test_a(self, fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) diff --git a/tests/modes/test_legacy_mode.py b/tests/modes/test_legacy_mode.py new file mode 100644 index 00000000..df9c2cb6 --- /dev/null +++ b/tests/modes/test_legacy_mode.py @@ -0,0 +1,115 @@ +from textwrap import dedent + +pytest_plugins = "pytester" + + +LEGACY_MODE = ( + "The 'asyncio_mode' default value will change to 'strict' in future, " + "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " + "in pytest configuration file." +) + +LEGACY_ASYNCIO_FIXTURE = ( + "'@pytest.fixture' is applied to {name} " + "in 'legacy' mode, " + "please replace it with '@pytest_asyncio.fixture' as a preparation " + "for switching to 'strict' mode (or use 'auto' mode to seamlessly handle " + "all these fixtures as asyncio-driven)." +).format(name="*") + + +def test_warning_for_legacy_mode_cmdline(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=legacy") + assert result.parseoutcomes()["warnings"] == 1 + result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) + + +def test_warning_for_legacy_mode_cfg(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = legacy\n") + result = pytester.runpytest() + assert result.parseoutcomes()["warnings"] == 1 + result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) + result.stdout.no_fnmatch_line("*" + LEGACY_ASYNCIO_FIXTURE + "*") + + +def test_warning_for_legacy_fixture(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.fixture + async def fixture_a(): + await asyncio.sleep(0) + return 1 + + @pytest.mark.asyncio + async def test_a(fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=legacy") + assert result.parseoutcomes()["warnings"] == 2 + result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) + + +def test_warning_for_legacy_method_fixture(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + + class TestA: + + @pytest.fixture + async def fixture_a(self): + await asyncio.sleep(0) + return 1 + + @pytest.mark.asyncio + async def test_a(self, fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=legacy") + assert result.parseoutcomes()["warnings"] == 2 + result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) diff --git a/tests/modes/test_strict_mode.py b/tests/modes/test_strict_mode.py new file mode 100644 index 00000000..7b574012 --- /dev/null +++ b/tests/modes/test_strict_mode.py @@ -0,0 +1,70 @@ +from textwrap import dedent + +pytest_plugins = "pytester" + + +def test_strict_mode_cmdline(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=strict") + result.assert_outcomes(passed=1) + + +def test_strict_mode_cfg(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = strict\n") + result = pytester.runpytest() + result.assert_outcomes(passed=1) + + +def test_strict_mode_method_fixture(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + import pytest_asyncio + + pytest_plugins = 'pytest_asyncio' + + class TestA: + + @pytest_asyncio.fixture + async def fixture_a(self): + await asyncio.sleep(0) + return 1 + + @pytest.mark.asyncio + async def test_a(self, fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) diff --git a/tests/test_asyncio_fixture.py b/tests/test_asyncio_fixture.py new file mode 100644 index 00000000..824956d8 --- /dev/null +++ b/tests/test_asyncio_fixture.py @@ -0,0 +1,39 @@ +import asyncio +import pytest_asyncio +import pytest + + +@pytest_asyncio.fixture +async def fixture_bare(): + await asyncio.sleep(0) + return 1 + + +@pytest.mark.asyncio +async def test_bare_fixture(fixture_bare): + await asyncio.sleep(0) + assert fixture_bare == 1 + + +@pytest_asyncio.fixture(name="new_fixture_name") +async def fixture_with_name(request): + await asyncio.sleep(0) + return request.fixturename + + +@pytest.mark.asyncio +async def test_fixture_with_name(new_fixture_name): + await asyncio.sleep(0) + assert new_fixture_name == "new_fixture_name" + + +@pytest_asyncio.fixture(params=[2, 4]) +async def fixture_with_params(request): + await asyncio.sleep(0) + return request.param + + +@pytest.mark.asyncio +async def test_fixture_with_params(fixture_with_params): + await asyncio.sleep(0) + assert fixture_with_params % 2 == 0 From 47ae437236630080788f7290c524d8ffd22e0492 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 08:37:52 +0200 Subject: [PATCH 048/198] Ignote .python-version file marker --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 447dbc4d..247e4de7 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,7 @@ target/ .venv* .idea -.vscode \ No newline at end of file +.vscode + +# pyenv +.python-version From b785c98f04d4164739cf8e172488a992a5e9dc6c Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 15:02:20 +0200 Subject: [PATCH 049/198] Update changelog for added plugin modes (#243) --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index acaa99b5..c4c3a5b1 100644 --- a/README.rst +++ b/README.rst @@ -259,6 +259,7 @@ Changelog - Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ - Added `flaky `_ to test dependencies - Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ +- Added the plugin modes: *strict*, *auto*, and *legacy*. See `documentation `_ for details. `#125 `_ 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ From 0a143c4356eb121e7ad44fa1f1fbe1a52e7e3a33 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 15:02:47 +0200 Subject: [PATCH 050/198] Avoid non-stantdard approached for warning emitting (#242) --- pytest_asyncio/plugin.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 44165602..813a638e 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -5,7 +5,6 @@ import functools import inspect import socket -import sys import warnings import pytest @@ -17,7 +16,7 @@ class Mode(str, enum.Enum): LEGACY = "legacy" -LEGACY_MODE = pytest.PytestDeprecationWarning( +LEGACY_MODE = DeprecationWarning( "The 'asyncio_mode' default value will change to 'strict' in future, " "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " "in pytest configuration file." @@ -110,21 +109,7 @@ def pytest_configure(config): "run using an asyncio event loop", ) if _get_asyncio_mode(config) == Mode.LEGACY: - _issue_warning_captured(LEGACY_MODE, config.hook, stacklevel=1) - - -def _issue_warning_captured(warning, hook, *, stacklevel=1): - # copy-paste of pytest internal _pytest.warnings._issue_warning_captured function - with warnings.catch_warnings(record=True) as records: - warnings.simplefilter("always", type(warning)) - warnings.warn(LEGACY_MODE, stacklevel=stacklevel) - frame = sys._getframe(stacklevel - 1) - location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name - hook.pytest_warning_recorded.call_historic( - kwargs=dict( - warning_message=records[0], when="config", nodeid="", location=location - ) - ) + config.issue_config_time_warning(LEGACY_MODE, stacklevel=2) @pytest.mark.tryfirst @@ -222,7 +207,7 @@ def pytest_fixture_setup(fixturedef, request): ) warnings.warn( LEGACY_ASYNCIO_FIXTURE.format(name=name), - pytest.PytestDeprecationWarning, + DeprecationWarning, ) else: # asyncio_mode is STRICT, From 5d4954a5743c984af70c4e164c7316974f4cc97d Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 15:03:01 +0200 Subject: [PATCH 051/198] Rewrite flaky integration test (#246) to don't pollute the output with flaky restart warnings --- tests/test_flaky_integration.py | 52 ++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/tests/test_flaky_integration.py b/tests/test_flaky_integration.py index 4628c6a0..2e551aad 100644 --- a/tests/test_flaky_integration.py +++ b/tests/test_flaky_integration.py @@ -1,17 +1,47 @@ """Tests for the Flaky integration, which retries failed tests. """ -import asyncio -import flaky -import pytest -_threshold = -1 +from textwrap import dedent +pytest_plugins = "pytester" -@flaky.flaky(3, 2) -@pytest.mark.asyncio -async def test_asyncio_flaky_thing_that_fails_then_succeeds(): - global _threshold - await asyncio.sleep(0.1) - _threshold += 1 - assert _threshold != 1 + +def test_auto_mode_cmdline(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import flaky + import pytest + + _threshold = -1 + + @flaky.flaky(3, 2) + @pytest.mark.asyncio + async def test_asyncio_flaky_thing_that_fails_then_succeeds(): + global _threshold + await asyncio.sleep(0.1) + _threshold += 1 + assert _threshold != 1 + """ + ) + ) + # runpytest_subprocess() is required to don't pollute the output + # with flaky restart information + result = pytester.runpytest_subprocess() + result.assert_outcomes(passed=1) + result.stdout.fnmatch_lines( + [ + "===Flaky Test Report===", + "test_asyncio_flaky_thing_that_fails_then_succeeds passed 1 " + "out of the required 2 times. Running test again until it passes 2 times.", + "test_asyncio_flaky_thing_that_fails_then_succeeds failed " + "(1 runs remaining out of 3).", + " ", + " assert 1 != 1", + "test_asyncio_flaky_thing_that_fails_then_succeeds passed 2 " + "out of the required 2 times. Success!", + "===End Flaky Test Report===", + ] + ) From 4c7da65d6fcf9d725eccba28ad1ed2083524ee16 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 15:03:32 +0200 Subject: [PATCH 052/198] Setup pre-commit hooks and reformat code (#245) --- .pre-commit-config.yaml | 39 +++++++++++++++++++ LICENSE | 1 - Makefile | 14 +++++-- README.rst | 14 ++++--- pytest_asyncio/__init__.py | 1 - pytest_asyncio/plugin.py | 6 ++- setup.cfg | 2 +- setup.py | 2 +- .../test_async_fixtures_with_finalizer.py | 3 +- tests/hypothesis/test_base.py | 1 - tests/hypothesis/test_inherited_test.py | 14 +++---- tests/multiloop/conftest.py | 2 - .../test_respects_event_loop_policy.py | 3 +- tests/sessionloop/conftest.py | 2 - tests/test_asyncio_fixture.py | 4 +- tests/test_dependent_fixtures.py | 1 + tests/test_simple.py | 9 +++-- tests/test_subprocess.py | 1 - tox.ini | 3 +- 19 files changed, 86 insertions(+), 36 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..cf368171 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,39 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: 'v4.1.0' + hooks: + - id: check-merge-conflict + exclude: "rst$" +- repo: https://github.com/asottile/yesqa + rev: v1.3.0 + hooks: + - id: yesqa +- repo: https://github.com/Zac-HD/shed + rev: 0.6.0 # 0.7 does not support Python 3.7 + hooks: + - id: shed + args: + - --refactor + - --py37-plus + types_or: + - python + - markdown + - rst +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: fix-encoding-pragma + args: [--remove] + - id: check-yaml + - id: debug-statements +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + language_version: python3 +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: python-use-type-annotations diff --git a/LICENSE b/LICENSE index e06d2081..5c304d1a 100644 --- a/LICENSE +++ b/LICENSE @@ -199,4 +199,3 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - diff --git a/Makefile b/Makefile index 8cf88841..fa6d6c0d 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,17 @@ clean-test: ## remove test and coverage artifacts rm -f .coverage rm -fr htmlcov/ -lint: ## check style with flake8 - flake8 pytest_asyncio tests - black --check --verbose pytest_asyncio tests +lint: +# CI env-var is set by GitHub actions +ifdef CI + pre-commit run --all-files --show-diff-on-failure +else + pre-commit run --all-files +endif test: pytest tests + +install: + pip install -U pre-commit + pre-commit install diff --git a/README.rst b/README.rst index c4c3a5b1..0b35000b 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,7 @@ provides useful fixtures and markers to make testing easier. @pytest.mark.asyncio async def test_some_asyncio_code(): res = await library.do_something() - assert b'expected result' == res + assert b"expected result" == res pytest-asyncio has been strongly influenced by pytest-tornado_. @@ -139,9 +139,9 @@ Use ``pytest.mark.asyncio`` for this purpose. .. code-block:: python def test_http_client(event_loop): - url = 'http://httpbin.org/get' + url = "http://httpbin.org/get" resp = event_loop.run_until_complete(http_client(url)) - assert b'HTTP/1.1 200 OK' in resp + 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 @@ -189,12 +189,14 @@ Asynchronous fixtures are defined just like ordinary pytest fixtures, except the import pytest_asyncio + @pytest_asyncio.fixture async def async_gen_fixture(): await asyncio.sleep(0.1) - yield 'a value' + yield "a value" + - @pytest_asyncio.fixture(scope='module') + @pytest_asyncio.fixture(scope="module") async def async_fixture(): return await asyncio.sleep(0.1) @@ -227,11 +229,13 @@ Only test coroutines will be affected (by default, coroutines prefixed by .. code-block:: python import asyncio + import pytest # All test coroutines will be treated as marked. pytestmark = pytest.mark.asyncio + async def test_example(event_loop): """No marker!""" await asyncio.sleep(0, loop=event_loop) diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index 0da62156..2a50727f 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -3,5 +3,4 @@ from .plugin import fixture - __all__ = ("fixture",) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 813a638e..13d7c685 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -159,7 +159,8 @@ def pytest_fixture_post_finalizer(fixturedef, request): """Called after fixture teardown""" if fixturedef.argname == "event_loop": policy = asyncio.get_event_loop_policy() - policy.get_event_loop().close() # Clean up existing loop to avoid ResourceWarnings + # Clean up existing loop to avoid ResourceWarnings + policy.get_event_loop().close() new_loop = policy.new_event_loop() # Replace existing event loop # Ensure subsequent calls to get_event_loop() succeed policy.set_event_loop(new_loop) @@ -282,7 +283,8 @@ def pytest_pyfunc_call(pyfuncitem): """ Pytest hook called before a test case is run. - Wraps marked tests in a synchronous function where the wrapped test coroutine is executed in an event loop. + Wraps marked tests in a synchronous function + where the wrapped test coroutine is executed in an event loop. """ if "asyncio" in pyfuncitem.keywords: if getattr(pyfuncitem.obj, "is_hypothesis_test", False): diff --git a/setup.cfg b/setup.cfg index fc18e3d9..e2804822 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,4 +15,4 @@ filterwarnings = error license_file = LICENSE [flake8] -ignore = E203, E501, W503 +max-line-length = 88 diff --git a/setup.py b/setup.py index 1cd1415c..4b331753 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ import re from pathlib import Path -from setuptools import setup, find_packages +from setuptools import find_packages, setup def find_version(): diff --git a/tests/async_fixtures/test_async_fixtures_with_finalizer.py b/tests/async_fixtures/test_async_fixtures_with_finalizer.py index c90a0124..2e72d5de 100644 --- a/tests/async_fixtures/test_async_fixtures_with_finalizer.py +++ b/tests/async_fixtures/test_async_fixtures_with_finalizer.py @@ -46,7 +46,8 @@ def port_finalizer(finalizer): async def port_afinalizer(): # 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, + # 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 diff --git a/tests/hypothesis/test_base.py b/tests/hypothesis/test_base.py index 39cb6075..e9273d0e 100644 --- a/tests/hypothesis/test_base.py +++ b/tests/hypothesis/test_base.py @@ -4,7 +4,6 @@ import asyncio import pytest - from hypothesis import given, strategies as st diff --git a/tests/hypothesis/test_inherited_test.py b/tests/hypothesis/test_inherited_test.py index 86e92efd..a7762264 100644 --- a/tests/hypothesis/test_inherited_test.py +++ b/tests/hypothesis/test_inherited_test.py @@ -1,22 +1,20 @@ import hypothesis.strategies as st -from hypothesis import given import pytest +from hypothesis import given class BaseClass: @pytest.mark.asyncio @given(value=st.integers()) async def test_hypothesis(self, value: int) -> None: - assert True + pass class TestOne(BaseClass): - """During the first execution the Hypothesis test is wrapped in a synchronous function.""" - - pass + """During the first execution the Hypothesis test + is wrapped in a synchronous function.""" class TestTwo(BaseClass): - """Execute the test a second time to ensure that the test receives a fresh event loop.""" - - pass + """Execute the test a second time to ensure that + the test receives a fresh event loop.""" diff --git a/tests/multiloop/conftest.py b/tests/multiloop/conftest.py index 9c74a509..ebcb627a 100644 --- a/tests/multiloop/conftest.py +++ b/tests/multiloop/conftest.py @@ -6,8 +6,6 @@ class CustomSelectorLoop(asyncio.SelectorEventLoop): """A subclass with no overrides, just to test for presence.""" - pass - @pytest.fixture def event_loop(): diff --git a/tests/respect_event_loop_policy/test_respects_event_loop_policy.py b/tests/respect_event_loop_policy/test_respects_event_loop_policy.py index 2537ca24..610b3388 100644 --- a/tests/respect_event_loop_policy/test_respects_event_loop_policy.py +++ b/tests/respect_event_loop_policy/test_respects_event_loop_policy.py @@ -6,7 +6,8 @@ @pytest.mark.asyncio async def test_uses_loop_provided_by_custom_policy(): - """Asserts that test cases use the event loop provided by the custom event loop policy""" + """Asserts that test cases use the event loop + provided by the custom event loop policy""" assert type(asyncio.get_event_loop()).__name__ == "TestEventLoop" diff --git a/tests/sessionloop/conftest.py b/tests/sessionloop/conftest.py index 6c657688..bb6c1d6c 100644 --- a/tests/sessionloop/conftest.py +++ b/tests/sessionloop/conftest.py @@ -6,8 +6,6 @@ class CustomSelectorLoopSession(asyncio.SelectorEventLoop): """A subclass with no overrides, just to test for presence.""" - pass - loop = CustomSelectorLoopSession() diff --git a/tests/test_asyncio_fixture.py b/tests/test_asyncio_fixture.py index 824956d8..cfe10479 100644 --- a/tests/test_asyncio_fixture.py +++ b/tests/test_asyncio_fixture.py @@ -1,7 +1,9 @@ import asyncio -import pytest_asyncio + import pytest +import pytest_asyncio + @pytest_asyncio.fixture async def fixture_bare(): diff --git a/tests/test_dependent_fixtures.py b/tests/test_dependent_fixtures.py index 2876255b..dc70fe9c 100644 --- a/tests/test_dependent_fixtures.py +++ b/tests/test_dependent_fixtures.py @@ -1,4 +1,5 @@ import asyncio + import pytest diff --git a/tests/test_simple.py b/tests/test_simple.py index 42151852..31204b6c 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -2,6 +2,7 @@ import asyncio import pytest + import pytest_asyncio.plugin @@ -26,7 +27,7 @@ async def test_asyncio_marker(): @pytest.mark.xfail(reason="need a failure", strict=True) @pytest.mark.asyncio def test_asyncio_marker_fail(): - assert False + raise AssertionError @pytest.mark.asyncio @@ -196,13 +197,15 @@ class TestMarkerInClassBasedTests: @pytest.mark.asyncio 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.""" + """Test the "asyncio" marker works on a method in + a class-based test with explicit loop fixture.""" ret = await async_coro() assert ret == "ok" @pytest.mark.asyncio 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.""" + """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/tests/test_subprocess.py b/tests/test_subprocess.py index 88ea29ab..311d67d5 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -1,5 +1,4 @@ """Tests for using subprocesses in tests.""" -import asyncio import asyncio.subprocess import sys diff --git a/tox.ini b/tox.ini index edae7dec..7d551eca 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,7 @@ skip_install = true basepython = python3.9 extras = tests deps = - flake8 - black + pre-commit commands = make lint From 4176c3d0d916c5e4830a423587f0396f7995da54 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 9 Jan 2022 15:48:47 +0200 Subject: [PATCH 053/198] Setup initial codeowners (#244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Andrew Svetlov, Michael Seifert, and Tin Tvrtković are added as reviewers for all pull requests --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..a30293ca --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @asvetlov @seifertm @Tinche From 41420cfc3b0335e256ce5bd7a08dcf03b21b5282 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 11 Jan 2022 12:30:02 +0200 Subject: [PATCH 054/198] Switch to declarative setup (#247) * Switch to declarative setup * Use __main__ guard * Add build-backend * Pin versions --- pyproject.toml | 6 ++++++ setup.cfg | 52 ++++++++++++++++++++++++++++++++++++++++++++++---- setup.py | 48 +++------------------------------------------- 3 files changed, 57 insertions(+), 49 deletions(-) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..31531b9e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=51.0", + "wheel>=0.36", +] +build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg index e2804822..83fdce45 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,51 @@ +[metadata] +name = pytest-asyncio +version = attr: pytest_asyncio.__version__ +url = https://github.com/pytest-dev/pytest-asyncio +project_urls = + GitHub = https://github.com/pytest-dev/pytest-asyncio +description = Pytest support for asyncio +long_description = file: README.rst +long_description_content_type = text/x-rst +author = Tin Tvrtković +author_email = tinchester@gmail.com +license = Apache 2.0 +license_file = LICENSE +classifiers = + Development Status :: 4 - Beta + + Intended Audience :: Developers + + License :: OSI Approved :: Apache Software License + + 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 :: Asyncio + Framework :: Pytest + +[options] +python_requires = >=3.7 +packages = find: +include_package_data = True + +install_requires = + pytest >= 5.4.0 + +[options.extras_require] +testing = + coverage + hypothesis >= 5.7.1 + flaky >= 3.5.0 + +[options.entry_points] +pytest11 = + asyncio = pytest_asyncio.plugin + [coverage:run] source = pytest_asyncio @@ -10,9 +58,5 @@ testpaths = tests asyncio_mode = auto filterwarnings = error -[metadata] -# ensure LICENSE is included in wheel metadata -license_file = LICENSE - [flake8] max-line-length = 88 diff --git a/setup.py b/setup.py index 4b331753..7f1a1763 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,4 @@ -import re -from pathlib import Path +from setuptools import setup -from setuptools import find_packages, setup - - -def find_version(): - version_file = ( - Path(__file__).parent.joinpath("pytest_asyncio", "__init__.py").read_text() - ) - version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) - if version_match: - return version_match.group(1) - - raise RuntimeError("Unable to find version string.") - - -setup( - name="pytest-asyncio", - version=find_version(), - packages=find_packages(), - url="https://github.com/pytest-dev/pytest-asyncio", - license="Apache 2.0", - author="Tin Tvrtković", - author_email="tinchester@gmail.com", - description="Pytest support for asyncio.", - long_description=Path(__file__).parent.joinpath("README.rst").read_text(), - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "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 :: Asyncio", - "Framework :: Pytest", - ], - python_requires=">= 3.7", - install_requires=["pytest >= 5.4.0"], - extras_require={ - "testing": ["coverage", "hypothesis >= 5.7.1", "flaky >= 3.5.0"], - }, - entry_points={"pytest11": ["asyncio = pytest_asyncio.plugin"]}, -) +if __name__ == "__main__": + setup() From 775da951cc30298a26e4d7db062a18d201021ecc Mon Sep 17 00:00:00 2001 From: kriek Date: Tue, 11 Jan 2022 14:58:23 +0100 Subject: [PATCH 055/198] Fixes pytest-dev/pytest-asyncio#219 (#221) Co-authored-by: Andrew Svetlov --- README.rst | 1 + pytest_asyncio/plugin.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0b35000b..59d2ae9c 100644 --- a/README.rst +++ b/README.rst @@ -264,6 +264,7 @@ Changelog - Added `flaky `_ to test dependencies - Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ - Added the plugin modes: *strict*, *auto*, and *legacy*. See `documentation `_ for details. `#125 `_ +- Correctly process ``LeyboardInterrupt`` during async fixture setup phase `#219 `_ 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 13d7c685..49157de5 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -253,8 +253,9 @@ async def async_finalizer(): loop.run_until_complete(async_finalizer()) + result = loop.run_until_complete(setup()) request.addfinalizer(finalizer) - return loop.run_until_complete(setup()) + return result fixturedef.func = wrapper elif inspect.iscoroutinefunction(func): From f0c20dc485800834bc49a1721ec9d59edbbbc995 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 11 Jan 2022 16:02:01 +0200 Subject: [PATCH 056/198] Fix typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 59d2ae9c..42f867db 100644 --- a/README.rst +++ b/README.rst @@ -264,7 +264,7 @@ Changelog - Added `flaky `_ to test dependencies - Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ - Added the plugin modes: *strict*, *auto*, and *legacy*. See `documentation `_ for details. `#125 `_ -- Correctly process ``LeyboardInterrupt`` during async fixture setup phase `#219 `_ +- Correctly process ``KeyboardInterrupt`` during async fixture setup phase `#219 `_ 0.16.0 (2021-10-16) ~~~~~~~~~~~~~~~~~~~ From 37ec756edf0c93b272cfbbcbd485bcb495b0958c Mon Sep 17 00:00:00 2001 From: Imran Hayder Date: Tue, 11 Jan 2022 14:27:47 -0600 Subject: [PATCH 057/198] Switch to setuptools-scm for versioning (#37) * Switch to setuptools-scm for versioning Following other pytest projects like pytest-html, that use setuptool-scm to manage version, it would be nice other projects follow the suit and let setuptools-scm manage version of this project. * Update .gitignore * ci: Install dependency setuptools_scm. Signed-off-by: Michael Seifert * Drop explicit version reference from setup.cfg * Remove setuptools_scm and wheel from `pip install --upgrade` of the test job Co-authored-by: Andrew Svetlov * Replace `setuptools_scm` and `wheel` with `build`in package job Co-authored-by: Andrew Svetlov * Change the packaging command to use `build` Co-authored-by: Andrew Svetlov * build: Added missing dependency declaration on setuptools_scm to setup.cfg. This prevents tools relying on setuptools from picking up the dependency correctly. Signed-off-by: Michael Seifert * build: Added version in metadata. Signed-off-by: Michael Seifert Co-authored-by: maliki Co-authored-by: Bruno Oliveira Co-authored-by: Michael Seifert Co-authored-by: Andrew Svetlov --- .github/workflows/main.yml | 6 +++--- .gitignore | 6 +++++- pyproject.toml | 4 ++++ pytest_asyncio/__init__.py | 3 +-- setup.cfg | 3 +++ 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b448cd6c..3a3e4e44 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: set -xe python -VV python -m site - python -m pip install --upgrade pip wheel + python -m pip install --upgrade pip python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" @@ -57,9 +57,9 @@ jobs: python-version: "3.9" - name: "Install poetry, check-wheel-content, and twine" - run: "python -m pip install wheel twine check-wheel-contents" + run: "python -m pip install build check-wheel-contents twine" - name: "Build package" - run: "python setup.py sdist bdist_wheel" + run: "python -m build" - name: "List result" run: "ls -l dist" - name: "Check wheel contents" diff --git a/.gitignore b/.gitignore index 247e4de7..7dd9b771 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,7 @@ htmlcov/ .tox/ .coverage .coverage.* -.cache +.pytest_cache nosetests.xml coverage.xml *,cover @@ -63,3 +63,7 @@ target/ # pyenv .python-version + + +# generated by setuptools_scm +pytest_asyncio/_version.py diff --git a/pyproject.toml b/pyproject.toml index 31531b9e..189ffa1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,5 +2,9 @@ requires = [ "setuptools>=51.0", "wheel>=0.36", + "setuptools_scm>=6.2" ] build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +write_to = "pytest_asyncio/_version.py" diff --git a/pytest_asyncio/__init__.py b/pytest_asyncio/__init__.py index 2a50727f..1bc2811d 100644 --- a/pytest_asyncio/__init__.py +++ b/pytest_asyncio/__init__.py @@ -1,6 +1,5 @@ """The main point for importing pytest-asyncio items.""" -__version__ = "0.16.0" - +from ._version import version as __version__ # noqa from .plugin import fixture __all__ = ("fixture",) diff --git a/setup.cfg b/setup.cfg index 83fdce45..7c3d8a9c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,9 @@ python_requires = >=3.7 packages = find: include_package_data = True +setup_requires = + setuptools_scm >= 6.2 + install_requires = pytest >= 5.4.0 From 2f523bad98ee1256c26ffe94c78ebcd8a1d03688 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 12 Jan 2022 08:58:58 +0200 Subject: [PATCH 058/198] Configure dependabot version updater (#250) --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..10c63edc --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 + target-branch: master +- package-ecosystem: github-actions + directory: / + schedule: + interval: daily + open-pull-requests-limit: 10 From d28b826b8acb329401cceed286ef3b42dc82df05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jan 2022 09:36:15 +0200 Subject: [PATCH 059/198] Bump codecov/codecov-action from 1 to 2.1.0 (#251) * Bump codecov/codecov-action from 1 to 2.1.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 2.1.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v1...v2.1.0) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Tune coverage report Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Svetlov --- .github/workflows/main.yml | 25 +++++++++++++++---------- Makefile | 4 +++- setup.cfg | 4 +++- tox.ini | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a3e4e44..784ea5e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: jobs: - tests: + test: name: "Python ${{ matrix.python-version }}" runs-on: "ubuntu-latest" env: @@ -34,17 +34,22 @@ jobs: - name: "Run tox targets for ${{ matrix.python-version }}" run: "python -m tox" - # We always use a modern Python version for combining coverage to prevent - # parsing errors in older versions for modern code. - - uses: "actions/setup-python@v2" - with: - python-version: "3.9" + - name: Prepare coverage artifact + if: ${{ contains(env.USING_COVERAGE, matrix.python-version) }} + uses: aio-libs/prepare-coverage@v21.9.1 - - name: "Upload coverage to Codecov" - if: "contains(env.USING_COVERAGE, matrix.python-version)" - uses: "codecov/codecov-action@v1" + check: + name: Check + if: always() + needs: [test] + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 with: - fail_ci_if_error: true + jobs: ${{ toJSON(needs) }} + - name: Upload coverage + uses: aio-libs/upload-coverage@v21.9.4 package: name: "Build & verify package" diff --git a/Makefile b/Makefile index fa6d6c0d..0817a0e7 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,9 @@ else endif test: - pytest tests + coverage run -m pytest tests + coverage xml + coverage report install: pip install -U pre-commit diff --git a/setup.cfg b/setup.cfg index 7c3d8a9c..d78f17d5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -41,7 +41,7 @@ install_requires = [options.extras_require] testing = - coverage + coverage==6.2 hypothesis >= 5.7.1 flaky >= 3.5.0 @@ -51,6 +51,7 @@ pytest11 = [coverage:run] source = pytest_asyncio +branch = true [coverage:report] show_missing = true @@ -59,6 +60,7 @@ show_missing = true addopts = -rsx --tb=short testpaths = tests asyncio_mode = auto +junit_family=xunit2 filterwarnings = error [flake8] diff --git a/tox.ini b/tox.ini index 7d551eca..dc09b8c5 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ skip_missing_interpreters = true [testenv] extras = testing -commands = coverage run -m pytest {posargs} +commands = make test [testenv:lint] skip_install = true From 2eb12a7b0591dfb8578303235d87bb25ddeedf77 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 12 Jan 2022 18:31:16 +0200 Subject: [PATCH 060/198] Setup GitHub Workflows linter and yaml-reformatter (#253) --- .github/dependabot.yml | 23 +++---- .github/workflows/main.yml | 120 ++++++++++++++++++------------------- .pre-commit-config.yaml | 103 +++++++++++++++++++------------ 3 files changed, 137 insertions(+), 109 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 10c63edc..c99eadff 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,14 @@ +--- version: 2 updates: -- package-ecosystem: pip - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 - target-branch: master -- package-ecosystem: github-actions - directory: / - schedule: - interval: daily - open-pull-requests-limit: 10 + - package-ecosystem: pip + directory: / + schedule: + interval: daily + open-pull-requests-limit: 10 + target-branch: master + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 784ea5e2..12aafa0d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,72 +2,72 @@ name: CI on: - push: - branches: ["master"] - pull_request: - branches: ["master"] - workflow_dispatch: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: jobs: - test: - name: "Python ${{ matrix.python-version }}" - runs-on: "ubuntu-latest" - env: - USING_COVERAGE: "3.7,3.8,3.9,3.10" + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + env: + USING_COVERAGE: 3.7,3.8,3.9,3.10 - strategy: - matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + strategy: + matrix: + python-version: ['3.7', '3.8', '3.9', '3.10'] - steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" - with: - python-version: "${{ matrix.python-version }}" - - name: "Install dependencies" - run: | - set -xe - python -VV - python -m site - python -m pip install --upgrade pip - python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions - - name: "Run tox targets for ${{ matrix.python-version }}" - run: "python -m tox" + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + set -xe + python -VV + python -m site + python -m pip install --upgrade pip + python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions + - name: Run tox targets for ${{ matrix.python-version }} + run: python -m tox - - name: Prepare coverage artifact - if: ${{ contains(env.USING_COVERAGE, matrix.python-version) }} - uses: aio-libs/prepare-coverage@v21.9.1 + - name: Prepare coverage artifact + if: ${{ contains(env.USING_COVERAGE, matrix.python-version) }} + uses: aio-libs/prepare-coverage@v21.9.1 - check: - name: Check - if: always() - needs: [test] - runs-on: ubuntu-latest - steps: - - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 - with: - jobs: ${{ toJSON(needs) }} - - name: Upload coverage - uses: aio-libs/upload-coverage@v21.9.4 + check: + name: Check + if: always() + needs: [test] + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} + - name: Upload coverage + uses: aio-libs/upload-coverage@v21.9.4 - package: - name: "Build & verify package" - runs-on: "ubuntu-latest" + package: + name: Build & verify package + runs-on: ubuntu-latest - steps: - - uses: "actions/checkout@v2" - - uses: "actions/setup-python@v2" - with: - python-version: "3.9" + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.9' - - name: "Install poetry, check-wheel-content, and twine" - run: "python -m pip install build check-wheel-contents twine" - - name: "Build package" - run: "python -m build" - - name: "List result" - run: "ls -l dist" - - name: "Check wheel contents" - run: "check-wheel-contents dist/*.whl" - - name: "Check long_description" - run: "python -m twine check dist/*" + - name: Install poetry, check-wheel-content, and twine + run: python -m pip install build check-wheel-contents twine + - name: Build package + run: python -m build + - name: List result + run: ls -l dist + - name: Check wheel contents + run: check-wheel-contents dist/*.whl + - name: Check long_description + run: python -m twine check dist/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cf368171..a085f108 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,39 +1,66 @@ +--- repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: 'v4.1.0' - hooks: - - id: check-merge-conflict - exclude: "rst$" -- repo: https://github.com/asottile/yesqa - rev: v1.3.0 - hooks: - - id: yesqa -- repo: https://github.com/Zac-HD/shed - rev: 0.6.0 # 0.7 does not support Python 3.7 - hooks: - - id: shed - args: - - --refactor - - --py37-plus - types_or: - - python - - markdown - - rst -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: fix-encoding-pragma - args: [--remove] - - id: check-yaml - - id: debug-statements -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 - hooks: - - id: flake8 - language_version: python3 -- repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 - hooks: - - id: python-use-type-annotations + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: check-merge-conflict + exclude: rst$ + - repo: https://github.com/asottile/yesqa + rev: v1.3.0 + hooks: + - id: yesqa + - repo: https://github.com/Zac-HD/shed + rev: 0.6.0 # 0.7 does not support Python 3.7 + hooks: + - id: shed + args: + - --refactor + - --py37-plus + types_or: + - python + - markdown + - rst + - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt + rev: 0.1.0 + hooks: + - id: yamlfmt + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: fix-encoding-pragma + args: [--remove] + - id: check-case-conflict + - id: check-json + - id: check-xml + - id: check-yaml + - id: debug-statements + - repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + language_version: python3 + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: python-use-type-annotations + - repo: https://github.com/rhysd/actionlint + rev: v1.6.8 + hooks: + - id: actionlint-docker + args: + - -ignore + - 'SC2155:' + - -ignore + - 'SC2086:' + - -ignore + - 'SC1004:' + - repo: https://github.com/sirosen/check-jsonschema + rev: 0.9.1 + hooks: + - id: check-github-actions +ci: + skip: + - actionlint-docker + - check-github-actions From cd8498709d5cf763c7a73cac9b43a0bd2a2d4fb7 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 10:57:59 +0200 Subject: [PATCH 061/198] Release process automation (#252) --- .github/actionlint-matcher.json | 17 +++++++ .github/workflows/main.yml | 88 ++++++++++++++++++++++++++------- tools/get-version.py | 17 +++++++ tox.ini | 18 +++++-- 4 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 .github/actionlint-matcher.json create mode 100644 tools/get-version.py diff --git a/.github/actionlint-matcher.json b/.github/actionlint-matcher.json new file mode 100644 index 00000000..a99709f7 --- /dev/null +++ b/.github/actionlint-matcher.json @@ -0,0 +1,17 @@ +{ + "problemMatcher": [ + { + "owner": "actionlint", + "pattern": [ + { + "code": 5, + "column": 3, + "file": 1, + "line": 2, + "message": 4, + "regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$" + } + ] + } + ] +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12aafa0d..186b31b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,43 @@ on: workflow_dispatch: jobs: + lint: + name: Run linters + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + prerelease: ${{ steps.version.outputs.prerelease }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: '3.9' + - name: Install GitHub matcher for ActionLint checker + run: | + echo "::add-matcher::.github/actionlint-matcher.json" + - name: Install check-wheel-content, and twine + run: python -m pip install build check-wheel-contents tox twine + - name: Build package + run: python -m build + - name: Run tox for linter + run: python -m tox -e lint + - name: List result + run: ls -l dist + - name: Check wheel contents + run: check-wheel-contents dist/*.whl + - name: Check long_description + run: python -m twine check dist/* + - name: Get version info + id: version + run: tox -e version-info + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: dist + path: dist + test: name: Python ${{ matrix.python-version }} runs-on: ubuntu-latest @@ -21,6 +58,8 @@ jobs: steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -41,7 +80,7 @@ jobs: check: name: Check if: always() - needs: [test] + needs: [lint, test] runs-on: ubuntu-latest steps: - name: Decide whether the needed jobs succeeded or failed @@ -51,23 +90,36 @@ jobs: - name: Upload coverage uses: aio-libs/upload-coverage@v21.9.4 - package: - name: Build & verify package + deploy: + name: Deploy + environment: release + # Run only on pushing a tag + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + needs: [lint, check] runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - name: Checkout + uses: actions/checkout@v2.4.0 with: - python-version: '3.9' - - - name: Install poetry, check-wheel-content, and twine - run: python -m pip install build check-wheel-contents twine - - name: Build package - run: python -m build - - name: List result - run: ls -l dist - - name: Check wheel contents - run: check-wheel-contents dist/*.whl - - name: Check long_description - run: python -m twine check dist/* + fetch-depth: 0 + - name: Download distributions + uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - name: Collected dists + run: | + tree dist + - name: PyPI upload + uses: pypa/gh-action-pypi-publish@v1.4.2 + with: + packages_dir: dist + password: ${{ secrets.PYPI_API_TOKEN }} + - name: GitHub Release + uses: ncipollo/release-action@v1 + with: + name: pytest-asyncio ${{ needs.lint.outputs.version }} + artifacts: dist + bodyFile: README.rst + prerelease: ${{ needs.lint.outputs.prerelease }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/tools/get-version.py b/tools/get-version.py new file mode 100644 index 00000000..e988a32c --- /dev/null +++ b/tools/get-version.py @@ -0,0 +1,17 @@ +import json +import sys +from importlib import metadata + +from packaging.version import parse as parse_version + + +def main(): + version_string = metadata.version("pytest-asyncio") + version = parse_version(version_string) + print(f"::set-output name=version::{version}") + prerelease = json.dumps(version.is_prerelease) + print(f"::set-output name=prerelease::{prerelease}") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tox.ini b/tox.ini index dc09b8c5..0092b03e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,20 +1,25 @@ [tox] minversion = 3.14.0 -envlist = py37, py38, py39, py310, lint +envlist = py37, py38, py39, py310, lint, version-info skip_missing_interpreters = true +passenv = + CI [testenv] extras = testing commands = make test +allowlist_externals = + make [testenv:lint] skip_install = true basepython = python3.9 -extras = tests deps = - pre-commit + pre-commit == 2.16.0 commands = make lint +allowlist_externals = + make [testenv:coverage-report] deps = coverage @@ -23,6 +28,13 @@ commands = coverage combine coverage report +[testenv:version-info] +basepython = python3.9 +deps = + packaging == 21.3 +commands = + python ./tools/get-version.py + [gh-actions] python = 3.7: py37 From 8ccb30650068f58d6f3e7314d2c1f2d59cdba1e9 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 10:59:27 +0200 Subject: [PATCH 062/198] Build on tag --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 186b31b5..c07b3b40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,7 @@ name: CI on: push: branches: [master] + tags: [v*] pull_request: branches: [master] workflow_dispatch: From 696cf7d5e0a458825c27ae8c7d621fb538c70827 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 11:19:59 +0200 Subject: [PATCH 063/198] Fix trove classifier for asyncio --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index d78f17d5..7be86f36 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,7 +25,7 @@ classifiers = Topic :: Software Development :: Testing - Framework :: Asyncio + Framework :: AsyncIO Framework :: Pytest [options] From 141937b89aa6ced9856ed3f997818ef8e3fbea57 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 11:41:15 +0200 Subject: [PATCH 064/198] Fix release artifacts --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c07b3b40..c2c986ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -120,7 +120,7 @@ jobs: uses: ncipollo/release-action@v1 with: name: pytest-asyncio ${{ needs.lint.outputs.version }} - artifacts: dist + artifacts: dist/* bodyFile: README.rst prerelease: ${{ needs.lint.outputs.prerelease }} token: ${{ secrets.GITHUB_TOKEN }} From d291c666870d2d903fc99543dccd77dca8496d5b Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 12:06:56 +0200 Subject: [PATCH 065/198] Convert README.rst to Markdown for making githun release --- .github/workflows/main.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c2c986ec..7ead9bbb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -99,6 +99,9 @@ jobs: needs: [lint, check] runs-on: ubuntu-latest steps: + - name: Install pandoc + run: | + apt install pandoc - name: Checkout uses: actions/checkout@v2.4.0 with: @@ -111,6 +114,9 @@ jobs: - name: Collected dists run: | tree dist + - name: Convert README.rst to Markdown + run: | + pandoc -s -o README.md README.rst - name: PyPI upload uses: pypa/gh-action-pypi-publish@v1.4.2 with: @@ -121,6 +127,6 @@ jobs: with: name: pytest-asyncio ${{ needs.lint.outputs.version }} artifacts: dist/* - bodyFile: README.rst + bodyFile: README.md prerelease: ${{ needs.lint.outputs.prerelease }} token: ${{ secrets.GITHUB_TOKEN }} From 90436c98dd27e670f0c721b48bb28001ccdcbbda Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 12:28:49 +0200 Subject: [PATCH 066/198] Fix pandoc installation procedure --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7ead9bbb..1a0c9031 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -101,7 +101,7 @@ jobs: steps: - name: Install pandoc run: | - apt install pandoc + sudo apt-get install -y pandoc - name: Checkout uses: actions/checkout@v2.4.0 with: From 2e2d5d202ecfea6fd403d92a9dd6ab6734aa0f85 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 12:50:41 +0200 Subject: [PATCH 067/198] Bump to 0.17 release --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 42f867db..c63f72d2 100644 --- a/README.rst +++ b/README.rst @@ -256,7 +256,7 @@ or an async framework such as `asynctest `_, `#188 `_ - Drop support for Python 3.6 From 4ee5722e0be3c3ca9b71d7d597b2bcd328b4f8d7 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 13 Jan 2022 14:30:21 +0200 Subject: [PATCH 068/198] Alternative yamlfmt settings (#254) --- .github/dependabot.yml | 22 ++-- .github/workflows/main.yml | 238 ++++++++++++++++++------------------- .pre-commit-config.yaml | 127 ++++++++++---------- 3 files changed, 194 insertions(+), 193 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c99eadff..9179b31d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,14 +1,14 @@ --- version: 2 updates: - - package-ecosystem: pip - directory: / - schedule: - interval: daily - open-pull-requests-limit: 10 - target-branch: master - - package-ecosystem: github-actions - directory: / - schedule: - interval: daily - open-pull-requests-limit: 10 +- package-ecosystem: pip + directory: / + schedule: + interval: daily + open-pull-requests-limit: 10 + target-branch: master +- package-ecosystem: github-actions + directory: / + schedule: + interval: daily + open-pull-requests-limit: 10 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a0c9031..901ec10e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,131 +2,131 @@ name: CI on: - push: - branches: [master] - tags: [v*] - pull_request: - branches: [master] - workflow_dispatch: + push: + branches: [master] + tags: [v*] + pull_request: + branches: [master] + workflow_dispatch: jobs: - lint: - name: Run linters - runs-on: ubuntu-latest - outputs: - version: ${{ steps.version.outputs.version }} - prerelease: ${{ steps.version.outputs.prerelease }} - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - uses: actions/setup-python@v2 - with: - python-version: '3.9' - - name: Install GitHub matcher for ActionLint checker - run: | - echo "::add-matcher::.github/actionlint-matcher.json" - - name: Install check-wheel-content, and twine - run: python -m pip install build check-wheel-contents tox twine - - name: Build package - run: python -m build - - name: Run tox for linter - run: python -m tox -e lint - - name: List result - run: ls -l dist - - name: Check wheel contents - run: check-wheel-contents dist/*.whl - - name: Check long_description - run: python -m twine check dist/* - - name: Get version info - id: version - run: tox -e version-info - - name: Upload artifacts - uses: actions/upload-artifact@v2 - with: - name: dist - path: dist + lint: + name: Run linters + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + prerelease: ${{ steps.version.outputs.prerelease }} + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: '3.9' + - name: Install GitHub matcher for ActionLint checker + run: | + echo "::add-matcher::.github/actionlint-matcher.json" + - name: Install check-wheel-content, and twine + run: python -m pip install build check-wheel-contents tox twine + - name: Build package + run: python -m build + - name: Run tox for linter + run: python -m tox -e lint + - name: List result + run: ls -l dist + - name: Check wheel contents + run: check-wheel-contents dist/*.whl + - name: Check long_description + run: python -m twine check dist/* + - name: Get version info + id: version + run: tox -e version-info + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: dist + path: dist - test: - name: Python ${{ matrix.python-version }} - runs-on: ubuntu-latest - env: - USING_COVERAGE: 3.7,3.8,3.9,3.10 + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + env: + USING_COVERAGE: 3.7,3.8,3.9,3.10 - strategy: - matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + strategy: + matrix: + python-version: ['3.7', '3.8', '3.9', '3.10'] - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - set -xe - python -VV - python -m site - python -m pip install --upgrade pip - python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions - - name: Run tox targets for ${{ matrix.python-version }} - run: python -m tox + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + set -xe + python -VV + python -m site + python -m pip install --upgrade pip + python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions + - name: Run tox targets for ${{ matrix.python-version }} + run: python -m tox - - name: Prepare coverage artifact - if: ${{ contains(env.USING_COVERAGE, matrix.python-version) }} - uses: aio-libs/prepare-coverage@v21.9.1 + - name: Prepare coverage artifact + if: ${{ contains(env.USING_COVERAGE, matrix.python-version) }} + uses: aio-libs/prepare-coverage@v21.9.1 - check: - name: Check - if: always() - needs: [lint, test] - runs-on: ubuntu-latest - steps: - - name: Decide whether the needed jobs succeeded or failed - uses: re-actors/alls-green@release/v1 - with: - jobs: ${{ toJSON(needs) }} - - name: Upload coverage - uses: aio-libs/upload-coverage@v21.9.4 + check: + name: Check + if: always() + needs: [lint, test] + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} + - name: Upload coverage + uses: aio-libs/upload-coverage@v21.9.4 - deploy: - name: Deploy - environment: release + deploy: + name: Deploy + environment: release # Run only on pushing a tag - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') - needs: [lint, check] - runs-on: ubuntu-latest - steps: - - name: Install pandoc - run: | - sudo apt-get install -y pandoc - - name: Checkout - uses: actions/checkout@v2.4.0 - with: - fetch-depth: 0 - - name: Download distributions - uses: actions/download-artifact@v2 - with: - name: dist - path: dist - - name: Collected dists - run: | - tree dist - - name: Convert README.rst to Markdown - run: | - pandoc -s -o README.md README.rst - - name: PyPI upload - uses: pypa/gh-action-pypi-publish@v1.4.2 - with: - packages_dir: dist - password: ${{ secrets.PYPI_API_TOKEN }} - - name: GitHub Release - uses: ncipollo/release-action@v1 - with: - name: pytest-asyncio ${{ needs.lint.outputs.version }} - artifacts: dist/* - bodyFile: README.md - prerelease: ${{ needs.lint.outputs.prerelease }} - token: ${{ secrets.GITHUB_TOKEN }} + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + needs: [lint, check] + runs-on: ubuntu-latest + steps: + - name: Install pandoc + run: | + sudo apt-get install -y pandoc + - name: Checkout + uses: actions/checkout@v2.4.0 + with: + fetch-depth: 0 + - name: Download distributions + uses: actions/download-artifact@v2 + with: + name: dist + path: dist + - name: Collected dists + run: | + tree dist + - name: Convert README.rst to Markdown + run: | + pandoc -s -o README.md README.rst + - name: PyPI upload + uses: pypa/gh-action-pypi-publish@v1.4.2 + with: + packages_dir: dist + password: ${{ secrets.PYPI_API_TOKEN }} + - name: GitHub Release + uses: ncipollo/release-action@v1 + with: + name: pytest-asyncio ${{ needs.lint.outputs.version }} + artifacts: dist/* + bodyFile: README.md + prerelease: ${{ needs.lint.outputs.prerelease }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a085f108..bf5f9e2c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,66 +1,67 @@ --- repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 - hooks: - - id: check-merge-conflict - exclude: rst$ - - repo: https://github.com/asottile/yesqa - rev: v1.3.0 - hooks: - - id: yesqa - - repo: https://github.com/Zac-HD/shed - rev: 0.6.0 # 0.7 does not support Python 3.7 - hooks: - - id: shed - args: - - --refactor - - --py37-plus - types_or: - - python - - markdown - - rst - - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt - rev: 0.1.0 - hooks: - - id: yamlfmt - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: fix-encoding-pragma - args: [--remove] - - id: check-case-conflict - - id: check-json - - id: check-xml - - id: check-yaml - - id: debug-statements - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 - hooks: - - id: flake8 - language_version: python3 - - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 - hooks: - - id: python-use-type-annotations - - repo: https://github.com/rhysd/actionlint - rev: v1.6.8 - hooks: - - id: actionlint-docker - args: - - -ignore - - 'SC2155:' - - -ignore - - 'SC2086:' - - -ignore - - 'SC1004:' - - repo: https://github.com/sirosen/check-jsonschema - rev: 0.9.1 - hooks: - - id: check-github-actions +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: check-merge-conflict + exclude: rst$ +- repo: https://github.com/asottile/yesqa + rev: v1.3.0 + hooks: + - id: yesqa +- repo: https://github.com/Zac-HD/shed + rev: 0.6.0 # 0.7 does not support Python 3.7 + hooks: + - id: shed + args: + - --refactor + - --py37-plus + types_or: + - python + - markdown + - rst +- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt + rev: 0.1.0 + hooks: + - id: yamlfmt + args: [--mapping, '2', --sequence, '2', --offset, '0'] +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: fix-encoding-pragma + args: [--remove] + - id: check-case-conflict + - id: check-json + - id: check-xml + - id: check-yaml + - id: debug-statements +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + language_version: python3 +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: python-use-type-annotations +- repo: https://github.com/rhysd/actionlint + rev: v1.6.8 + hooks: + - id: actionlint-docker + args: + - -ignore + - 'SC2155:' + - -ignore + - 'SC2086:' + - -ignore + - 'SC1004:' +- repo: https://github.com/sirosen/check-jsonschema + rev: 0.9.1 + hooks: + - id: check-github-actions ci: - skip: - - actionlint-docker - - check-github-actions + skip: + - actionlint-docker + - check-github-actions From eb6f3a8d5c804d3585d5d645589a58b9ad2f3c0a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jan 2022 14:36:11 +0200 Subject: [PATCH 069/198] Bump pypa/gh-action-pypi-publish from 1.4.2 to 1.5.0 (#255) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.4.2 to 1.5.0. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.4.2...v1.5.0) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 901ec10e..1728d40f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -118,7 +118,7 @@ jobs: run: | pandoc -s -o README.md README.rst - name: PyPI upload - uses: pypa/gh-action-pypi-publish@v1.4.2 + uses: pypa/gh-action-pypi-publish@v1.5.0 with: packages_dir: dist password: ${{ secrets.PYPI_API_TOKEN }} From 6cc430ce7ff845b1e07cbe08fc4c6221d68afd5c Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 14 Jan 2022 10:12:38 +0100 Subject: [PATCH 070/198] Fix auto marking of async hypothesis tests in auto mode (#259) * refactor: Extracted function determining whether a test function is a Hypothesis test. Signed-off-by: Michael Seifert * fix: Fixes a bug that prevents async Hypothesis tests from working without explicit "asyncio" marker when "--asyncio-mode=auto" is set. The option --asyncio-mode=auto marks all async functions with the asyncio mark during the collection phase. However, when pytest collects the Hypothesis test, the @given decorator has already been applied and the Hypothesis test function is no longer a coroutine. This commit extends the "pytest_pycollect_makeitem" hook to mark Hypothesis tests whose function body is a coroutine. Closes #258 Signed-off-by: Michael Seifert --- README.rst | 4 +++ pytest_asyncio/plugin.py | 18 ++++++++++++-- tests/hypothesis/test_base.py | 46 +++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index c63f72d2..9d2257a5 100644 --- a/README.rst +++ b/README.rst @@ -256,6 +256,10 @@ or an async framework such as `asynctest `_ + 0.17.0 (22-01-13) ~~~~~~~~~~~~~~~~~~~ - `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 49157de5..04b5e139 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -115,7 +115,13 @@ def pytest_configure(config): @pytest.mark.tryfirst def pytest_pycollect_makeitem(collector, name, obj): """A pytest hook to collect asyncio coroutines.""" - if collector.funcnamefilter(name) and _is_coroutine(obj): + if not collector.funcnamefilter(name): + return + if ( + _is_coroutine(obj) + or _is_hypothesis_test(obj) + and _hypothesis_test_wraps_coroutine(obj) + ): item = pytest.Function.from_parent(collector, name=name) if "asyncio" in item.keywords: return list(collector._genfunctions(name, obj)) @@ -128,6 +134,10 @@ def pytest_pycollect_makeitem(collector, name, obj): return ret +def _hypothesis_test_wraps_coroutine(function): + return _is_coroutine(function.hypothesis.inner_test) + + class FixtureStripper: """Include additional Fixture, and then strip them""" @@ -288,7 +298,7 @@ def pytest_pyfunc_call(pyfuncitem): where the wrapped test coroutine is executed in an event loop. """ if "asyncio" in pyfuncitem.keywords: - if getattr(pyfuncitem.obj, "is_hypothesis_test", False): + if _is_hypothesis_test(pyfuncitem.obj): pyfuncitem.obj.hypothesis.inner_test = wrap_in_sync( pyfuncitem.obj.hypothesis.inner_test, _loop=pyfuncitem.funcargs["event_loop"], @@ -300,6 +310,10 @@ def pytest_pyfunc_call(pyfuncitem): yield +def _is_hypothesis_test(function) -> bool: + return getattr(function, "is_hypothesis_test", False) + + def wrap_in_sync(func, _loop): """Return a sync wrapper around an async function executing it in the current event loop.""" diff --git a/tests/hypothesis/test_base.py b/tests/hypothesis/test_base.py index e9273d0e..fbee75bf 100644 --- a/tests/hypothesis/test_base.py +++ b/tests/hypothesis/test_base.py @@ -2,6 +2,7 @@ sync shim for Hypothesis. """ import asyncio +from textwrap import dedent import pytest from hypothesis import given, strategies as st @@ -40,3 +41,48 @@ async def test_can_use_fixture_provided_event_loop(event_loop, n): semaphore = asyncio.Semaphore(value=0) event_loop.call_soon(semaphore.release) await semaphore.acquire() + + +def test_async_auto_marked(pytester): + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + from hypothesis import given + import hypothesis.strategies as st + + pytest_plugins = 'pytest_asyncio' + + @given(n=st.integers()) + async def test_hypothesis(n: int): + assert isinstance(n, int) + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) + + +def test_sync_not_auto_marked(pytester): + """Assert that synchronous Hypothesis functions are not marked with asyncio""" + pytester.makepyfile( + dedent( + """\ + import asyncio + import pytest + from hypothesis import given + import hypothesis.strategies as st + + pytest_plugins = 'pytest_asyncio' + + @given(n=st.integers()) + def test_hypothesis(request, n: int): + markers = [marker.name for marker in request.node.own_markers] + assert "asyncio" not in markers + assert isinstance(n, int) + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) From 0a3328f5fced1568b60fdd33e66937b7bbca8922 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sat, 15 Jan 2022 13:29:12 +0200 Subject: [PATCH 071/198] Don't close event loop if the loop doesn't exist (#261) --- README.rst | 1 + pytest_asyncio/plugin.py | 9 +++++++-- tests/test_event_loop_scope.py | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 9d2257a5..58e13553 100644 --- a/README.rst +++ b/README.rst @@ -259,6 +259,7 @@ Changelog 0.17.1 (UNRELEASED) ~~~~~~~~~~~~~~~~~~~ - Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ +- Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ 0.17.0 (22-01-13) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 04b5e139..a7989b68 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -169,8 +169,13 @@ def pytest_fixture_post_finalizer(fixturedef, request): """Called after fixture teardown""" if fixturedef.argname == "event_loop": policy = asyncio.get_event_loop_policy() - # Clean up existing loop to avoid ResourceWarnings - policy.get_event_loop().close() + try: + loop = policy.get_event_loop() + except RuntimeError: + loop = None + if loop is not None: + # Clean up existing loop to avoid ResourceWarnings + loop.close() new_loop = policy.new_event_loop() # Replace existing event loop # Ensure subsequent calls to get_event_loop() succeed policy.set_event_loop(new_loop) diff --git a/tests/test_event_loop_scope.py b/tests/test_event_loop_scope.py index 8ae4eb1e..21fd6415 100644 --- a/tests/test_event_loop_scope.py +++ b/tests/test_event_loop_scope.py @@ -29,3 +29,9 @@ def test_3(): 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 + + +def test_4(event_loop): + # If a test sets the loop to None -- pytest_fixture_post_finalizer() + # still should work + asyncio.get_event_loop_policy().set_event_loop(None) From 308f3087e21c5dd4d4eb1dfa5d8f89a5a1e90496 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sat, 15 Jan 2022 14:59:09 +0200 Subject: [PATCH 072/198] Provide typing info (#260) --- Makefile | 5 +- README.rst | 1 + pytest_asyncio/plugin.py | 166 ++++++++++++++++++++++++++++++--------- pytest_asyncio/py.typed | 0 setup.cfg | 3 + tox.ini | 3 +- 6 files changed, 136 insertions(+), 42 deletions(-) create mode 100644 pytest_asyncio/py.typed diff --git a/Makefile b/Makefile index 0817a0e7..2b0216f9 100644 --- a/Makefile +++ b/Makefile @@ -23,10 +23,11 @@ clean-test: ## remove test and coverage artifacts lint: # CI env-var is set by GitHub actions ifdef CI - pre-commit run --all-files --show-diff-on-failure + python -m pre_commit run --all-files --show-diff-on-failure else - pre-commit run --all-files + python -m pre_commit run --all-files endif + python -m mypy pytest_asyncio --show-error-codes test: coverage run -m pytest tests diff --git a/README.rst b/README.rst index 58e13553..f0da202e 100644 --- a/README.rst +++ b/README.rst @@ -260,6 +260,7 @@ Changelog ~~~~~~~~~~~~~~~~~~~ - Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ - Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ +- Added type annotations. `#198 `_ 0.17.0 (22-01-13) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index a7989b68..bd6fa6de 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -6,8 +6,45 @@ import inspect import socket import warnings +from typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Dict, + Iterable, + Iterator, + List, + Optional, + Set, + TypeVar, + Union, + cast, + overload, +) import pytest +from typing_extensions import Literal + +_R = TypeVar("_R") + +_ScopeName = Literal["session", "package", "module", "class", "function"] +_T = TypeVar("_T") + +SimpleFixtureFunction = TypeVar( + "SimpleFixtureFunction", bound=Callable[..., Awaitable[_R]] +) +FactoryFixtureFunction = TypeVar( + "FactoryFixtureFunction", bound=Callable[..., AsyncIterator[_R]] +) +FixtureFunction = Union[SimpleFixtureFunction, FactoryFixtureFunction] +FixtureFunctionMarker = Callable[[FixtureFunction], FixtureFunction] + +Config = Any # pytest < 7.0 +PytestPluginManager = Any # pytest < 7.0 +FixtureDef = Any # pytest < 7.0 +Parser = Any # pytest < 7.0 +SubRequest = Any # pytest < 7.0 class Mode(str, enum.Enum): @@ -41,7 +78,7 @@ class Mode(str, enum.Enum): """ -def pytest_addoption(parser, pluginmanager): +def pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None: group = parser.getgroup("asyncio") group.addoption( "--asyncio-mode", @@ -58,7 +95,45 @@ def pytest_addoption(parser, pluginmanager): ) -def fixture(fixture_function=None, **kwargs): +@overload +def fixture( + fixture_function: FixtureFunction, + *, + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + name: Optional[str] = ..., +) -> FixtureFunction: + ... + + +@overload +def fixture( + fixture_function: None = ..., + *, + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + name: Optional[str] = None, +) -> FixtureFunctionMarker: + ... + + +def fixture( + fixture_function: Optional[FixtureFunction] = None, **kwargs: Any +) -> Union[FixtureFunction, FixtureFunctionMarker]: if fixture_function is not None: _set_explicit_asyncio_mark(fixture_function) return pytest.fixture(fixture_function, **kwargs) @@ -66,41 +141,41 @@ def fixture(fixture_function=None, **kwargs): else: @functools.wraps(fixture) - def inner(fixture_function): + def inner(fixture_function: FixtureFunction) -> FixtureFunction: return fixture(fixture_function, **kwargs) return inner -def _has_explicit_asyncio_mark(obj): +def _has_explicit_asyncio_mark(obj: Any) -> bool: obj = getattr(obj, "__func__", obj) # instance method maybe? return getattr(obj, "_force_asyncio_fixture", False) -def _set_explicit_asyncio_mark(obj): +def _set_explicit_asyncio_mark(obj: Any) -> None: if hasattr(obj, "__func__"): # instance method, check the function object obj = obj.__func__ obj._force_asyncio_fixture = True -def _is_coroutine(obj): +def _is_coroutine(obj: Any) -> bool: """Check to see if an object is really an asyncio coroutine.""" return asyncio.iscoroutinefunction(obj) or inspect.isgeneratorfunction(obj) -def _is_coroutine_or_asyncgen(obj): +def _is_coroutine_or_asyncgen(obj: Any) -> bool: return _is_coroutine(obj) or inspect.isasyncgenfunction(obj) -def _get_asyncio_mode(config): +def _get_asyncio_mode(config: Config) -> Mode: val = config.getoption("asyncio_mode") if val is None: val = config.getini("asyncio_mode") return Mode(val) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: """Inject documentation.""" config.addinivalue_line( "markers", @@ -113,10 +188,14 @@ def pytest_configure(config): @pytest.mark.tryfirst -def pytest_pycollect_makeitem(collector, name, obj): +def pytest_pycollect_makeitem( + collector: Union[pytest.Module, pytest.Class], name: str, obj: object +) -> Union[ + None, pytest.Item, pytest.Collector, List[Union[pytest.Item, pytest.Collector]] +]: """A pytest hook to collect asyncio coroutines.""" if not collector.funcnamefilter(name): - return + return None if ( _is_coroutine(obj) or _is_hypothesis_test(obj) @@ -131,10 +210,11 @@ def pytest_pycollect_makeitem(collector, name, obj): ret = list(collector._genfunctions(name, obj)) for elem in ret: elem.add_marker("asyncio") - return ret + return ret # type: ignore[return-value] + return None -def _hypothesis_test_wraps_coroutine(function): +def _hypothesis_test_wraps_coroutine(function: Any) -> bool: return _is_coroutine(function.hypothesis.inner_test) @@ -144,11 +224,11 @@ class FixtureStripper: REQUEST = "request" EVENT_LOOP = "event_loop" - def __init__(self, fixturedef): + def __init__(self, fixturedef: FixtureDef) -> None: self.fixturedef = fixturedef - self.to_strip = set() + self.to_strip: Set[str] = set() - def add(self, name): + def add(self, name: str) -> None: """Add fixture name to fixturedef and record in to_strip list (If not previously included)""" if name in self.fixturedef.argnames: @@ -156,7 +236,7 @@ def add(self, name): self.fixturedef.argnames += (name,) self.to_strip.add(name) - def get_and_strip_from(self, name, data_dict): + def get_and_strip_from(self, name: str, data_dict: Dict[str, _T]) -> _T: """Strip name from data, and return value""" result = data_dict[name] if name in self.to_strip: @@ -165,7 +245,7 @@ def get_and_strip_from(self, name, data_dict): @pytest.hookimpl(trylast=True) -def pytest_fixture_post_finalizer(fixturedef, request): +def pytest_fixture_post_finalizer(fixturedef: FixtureDef, request: SubRequest) -> None: """Called after fixture teardown""" if fixturedef.argname == "event_loop": policy = asyncio.get_event_loop_policy() @@ -182,7 +262,9 @@ def pytest_fixture_post_finalizer(fixturedef, request): @pytest.hookimpl(hookwrapper=True) -def pytest_fixture_setup(fixturedef, request): +def pytest_fixture_setup( + fixturedef: FixtureDef, request: SubRequest +) -> Optional[object]: """Adjust the event loop policy when an event loop is produced.""" if fixturedef.argname == "event_loop": outcome = yield @@ -295,7 +377,7 @@ async def setup(): @pytest.hookimpl(tryfirst=True, hookwrapper=True) -def pytest_pyfunc_call(pyfuncitem): +def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> Optional[object]: """ Pytest hook called before a test case is run. @@ -303,31 +385,35 @@ def pytest_pyfunc_call(pyfuncitem): where the wrapped test coroutine is executed in an event loop. """ if "asyncio" in pyfuncitem.keywords: + funcargs: Dict[str, object] = pyfuncitem.funcargs # type: ignore[name-defined] + loop = cast(asyncio.AbstractEventLoop, funcargs["event_loop"]) if _is_hypothesis_test(pyfuncitem.obj): pyfuncitem.obj.hypothesis.inner_test = wrap_in_sync( pyfuncitem.obj.hypothesis.inner_test, - _loop=pyfuncitem.funcargs["event_loop"], + _loop=loop, ) else: pyfuncitem.obj = wrap_in_sync( - pyfuncitem.obj, _loop=pyfuncitem.funcargs["event_loop"] + pyfuncitem.obj, + _loop=loop, ) yield -def _is_hypothesis_test(function) -> bool: +def _is_hypothesis_test(function: Any) -> bool: return getattr(function, "is_hypothesis_test", False) -def wrap_in_sync(func, _loop): +def wrap_in_sync(func: Callable[..., Awaitable[Any]], _loop: asyncio.AbstractEventLoop): """Return a sync wrapper around an async function executing it in the current event loop.""" # if the function is already wrapped, we rewrap using the original one # not using __wrapped__ because the original function may already be # a wrapped one - if hasattr(func, "_raw_test_func"): - func = func._raw_test_func + raw_func = getattr(func, "_raw_test_func", None) + if raw_func is not None: + func = raw_func @functools.wraps(func) def inner(**kwargs): @@ -344,20 +430,22 @@ def inner(**kwargs): task.exception() raise - inner._raw_test_func = func + inner._raw_test_func = func # type: ignore[attr-defined] return inner -def pytest_runtest_setup(item): +def pytest_runtest_setup(item: pytest.Item) -> None: if "asyncio" in item.keywords: + fixturenames = item.fixturenames # type: ignore[attr-defined] # inject an event loop fixture for all async tests - if "event_loop" in item.fixturenames: - item.fixturenames.remove("event_loop") - item.fixturenames.insert(0, "event_loop") + if "event_loop" in fixturenames: + fixturenames.remove("event_loop") + fixturenames.insert(0, "event_loop") + obj = item.obj # type: ignore[attr-defined] if ( item.get_closest_marker("asyncio") is not None - and not getattr(item.obj, "hypothesis", False) - and getattr(item.obj, "is_hypothesis_test", False) + and not getattr(obj, "hypothesis", False) + and getattr(obj, "is_hypothesis_test", False) ): pytest.fail( "test function `%r` is using Hypothesis, but pytest-asyncio " @@ -366,14 +454,14 @@ def pytest_runtest_setup(item): @pytest.fixture -def event_loop(request): +def event_loop(request: pytest.FixtureRequest) -> Iterator[asyncio.AbstractEventLoop]: """Create an instance of the default event loop for each test case.""" loop = asyncio.get_event_loop_policy().new_event_loop() yield loop loop.close() -def _unused_port(socket_type): +def _unused_port(socket_type: int) -> int: """Find an unused localhost port from 1024-65535 and return it.""" with contextlib.closing(socket.socket(type=socket_type)) as sock: sock.bind(("127.0.0.1", 0)) @@ -381,17 +469,17 @@ def _unused_port(socket_type): @pytest.fixture -def unused_tcp_port(): +def unused_tcp_port() -> int: return _unused_port(socket.SOCK_STREAM) @pytest.fixture -def unused_udp_port(): +def unused_udp_port() -> int: return _unused_port(socket.SOCK_DGRAM) @pytest.fixture(scope="session") -def unused_tcp_port_factory(): +def unused_tcp_port_factory() -> Callable[[], int]: """A factory function, producing different unused TCP ports.""" produced = set() @@ -410,7 +498,7 @@ def factory(): @pytest.fixture(scope="session") -def unused_udp_port_factory(): +def unused_udp_port_factory() -> Callable[[], int]: """A factory function, producing different unused UDP ports.""" produced = set() diff --git a/pytest_asyncio/py.typed b/pytest_asyncio/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/setup.cfg b/setup.cfg index 7be86f36..1b3f97be 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,6 +27,7 @@ classifiers = Framework :: AsyncIO Framework :: Pytest + Typing :: Typed [options] python_requires = >=3.7 @@ -38,12 +39,14 @@ setup_requires = install_requires = pytest >= 5.4.0 + typing-extensions >= 4.0 [options.extras_require] testing = coverage==6.2 hypothesis >= 5.7.1 flaky >= 3.5.0 + mypy == 0.931 [options.entry_points] pytest11 = diff --git a/tox.ini b/tox.ini index 0092b03e..a5477455 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,8 @@ allowlist_externals = [testenv:lint] skip_install = true -basepython = python3.9 +basepython = python3.10 +extras = testing deps = pre-commit == 2.16.0 commands = From 087e0b6ce22f453ca0093e6e25d143553e55e165 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 16 Jan 2022 14:13:13 +0200 Subject: [PATCH 073/198] Show asyncio mode in pytest report headers (#266) --- README.rst | 1 + pytest_asyncio/plugin.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/README.rst b/README.rst index f0da202e..7c888870 100644 --- a/README.rst +++ b/README.rst @@ -261,6 +261,7 @@ Changelog - Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ - Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ - Added type annotations. `#198 `_ +- Show asyncio mode in pytest report headers. `#266 `_ 0.17.0 (22-01-13) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index bd6fa6de..8635b624 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -187,6 +187,13 @@ def pytest_configure(config: Config) -> None: config.issue_config_time_warning(LEGACY_MODE, stacklevel=2) +@pytest.mark.tryfirst +def pytest_report_header(config: Config) -> List[str]: + """Add asyncio config to pytest header.""" + mode = _get_asyncio_mode(config) + return [f"asyncio: mode={mode}"] + + @pytest.mark.tryfirst def pytest_pycollect_makeitem( collector: Union[pytest.Module, pytest.Class], name: str, obj: object From 36f277dc91d64ecde9d81c90fa33b47c8391d140 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 16 Jan 2022 22:51:20 +0200 Subject: [PATCH 074/198] Relax asyncio_mode type definition; it allows to support pytest 6.1+ (#264) --- README.rst | 1 + pytest_asyncio/plugin.py | 3 +-- setup.cfg | 2 +- tests/conftest.py | 2 ++ tests/hypothesis/test_base.py | 12 ++++++------ tests/modes/test_auto_mode.py | 28 +++++++++++++--------------- tests/modes/test_legacy_mode.py | 29 +++++++++++++---------------- tests/modes/test_strict_mode.py | 22 ++++++++++------------ tests/test_flaky_integration.py | 10 +++------- tox.ini | 14 ++++++++++++-- 10 files changed, 62 insertions(+), 61 deletions(-) diff --git a/README.rst b/README.rst index 7c888870..2e6fd79b 100644 --- a/README.rst +++ b/README.rst @@ -262,6 +262,7 @@ Changelog - Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ - Added type annotations. `#198 `_ - Show asyncio mode in pytest report headers. `#266 `_ +- Relax ``asyncio_mode`` type definition; it allows to support pytest 6.1+. `#262 `_ 0.17.0 (22-01-13) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 8635b624..7a7c8dd5 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -90,7 +90,6 @@ def pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None parser.addini( "asyncio_mode", help="default value for --asyncio-mode", - type="string", default="legacy", ) @@ -461,7 +460,7 @@ def pytest_runtest_setup(item: pytest.Item) -> None: @pytest.fixture -def event_loop(request: pytest.FixtureRequest) -> Iterator[asyncio.AbstractEventLoop]: +def event_loop(request: "pytest.FixtureRequest") -> Iterator[asyncio.AbstractEventLoop]: """Create an instance of the default event loop for each test case.""" loop = asyncio.get_event_loop_policy().new_event_loop() yield loop diff --git a/setup.cfg b/setup.cfg index 1b3f97be..f05526bd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,7 +38,7 @@ setup_requires = setuptools_scm >= 6.2 install_requires = - pytest >= 5.4.0 + pytest >= 6.1.0 typing-extensions >= 4.0 [options.extras_require] diff --git a/tests/conftest.py b/tests/conftest.py index 03fd33f2..4aa8c89a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,8 @@ import pytest +pytest_plugins = "pytester" + @pytest.fixture def dependent_fixture(event_loop): diff --git a/tests/hypothesis/test_base.py b/tests/hypothesis/test_base.py index fbee75bf..e6da3427 100644 --- a/tests/hypothesis/test_base.py +++ b/tests/hypothesis/test_base.py @@ -43,8 +43,8 @@ async def test_can_use_fixture_provided_event_loop(event_loop, n): await semaphore.acquire() -def test_async_auto_marked(pytester): - pytester.makepyfile( +def test_async_auto_marked(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -60,13 +60,13 @@ async def test_hypothesis(n: int): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) -def test_sync_not_auto_marked(pytester): +def test_sync_not_auto_marked(testdir): """Assert that synchronous Hypothesis functions are not marked with asyncio""" - pytester.makepyfile( + testdir.makepyfile( dedent( """\ import asyncio @@ -84,5 +84,5 @@ def test_hypothesis(request, n: int): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) diff --git a/tests/modes/test_auto_mode.py b/tests/modes/test_auto_mode.py index 980b0b04..157ffded 100644 --- a/tests/modes/test_auto_mode.py +++ b/tests/modes/test_auto_mode.py @@ -1,10 +1,8 @@ from textwrap import dedent -pytest_plugins = "pytester" - -def test_auto_mode_cmdline(pytester): - pytester.makepyfile( +def test_auto_mode_cmdline(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -17,12 +15,12 @@ async def test_a(): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) -def test_auto_mode_cfg(pytester): - pytester.makepyfile( +def test_auto_mode_cfg(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -35,13 +33,13 @@ async def test_a(): """ ) ) - pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = auto\n") - result = pytester.runpytest() + testdir.makefile(".ini", pytest="[pytest]\nasyncio_mode = auto\n") + result = testdir.runpytest() result.assert_outcomes(passed=1) -def test_auto_mode_async_fixture(pytester): - pytester.makepyfile( +def test_auto_mode_async_fixture(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -60,12 +58,12 @@ async def test_a(fixture_a): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) -def test_auto_mode_method_fixture(pytester): - pytester.makepyfile( +def test_auto_mode_method_fixture(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -87,5 +85,5 @@ async def test_a(self, fixture_a): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) diff --git a/tests/modes/test_legacy_mode.py b/tests/modes/test_legacy_mode.py index df9c2cb6..12d4afe1 100644 --- a/tests/modes/test_legacy_mode.py +++ b/tests/modes/test_legacy_mode.py @@ -1,8 +1,5 @@ from textwrap import dedent -pytest_plugins = "pytester" - - LEGACY_MODE = ( "The 'asyncio_mode' default value will change to 'strict' in future, " "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " @@ -18,8 +15,8 @@ ).format(name="*") -def test_warning_for_legacy_mode_cmdline(pytester): - pytester.makepyfile( +def test_warning_for_legacy_mode_cmdline(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -33,13 +30,13 @@ async def test_a(): """ ) ) - result = pytester.runpytest("--asyncio-mode=legacy") + result = testdir.runpytest("--asyncio-mode=legacy") assert result.parseoutcomes()["warnings"] == 1 result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) -def test_warning_for_legacy_mode_cfg(pytester): - pytester.makepyfile( +def test_warning_for_legacy_mode_cfg(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -53,15 +50,15 @@ async def test_a(): """ ) ) - pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = legacy\n") - result = pytester.runpytest() + testdir.makefile(".ini", pytest="[pytest]\nasyncio_mode = legacy\n") + result = testdir.runpytest() assert result.parseoutcomes()["warnings"] == 1 result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) result.stdout.no_fnmatch_line("*" + LEGACY_ASYNCIO_FIXTURE + "*") -def test_warning_for_legacy_fixture(pytester): - pytester.makepyfile( +def test_warning_for_legacy_fixture(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -81,13 +78,13 @@ async def test_a(fixture_a): """ ) ) - result = pytester.runpytest("--asyncio-mode=legacy") + result = testdir.runpytest("--asyncio-mode=legacy") assert result.parseoutcomes()["warnings"] == 2 result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) -def test_warning_for_legacy_method_fixture(pytester): - pytester.makepyfile( +def test_warning_for_legacy_method_fixture(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -110,6 +107,6 @@ async def test_a(self, fixture_a): """ ) ) - result = pytester.runpytest("--asyncio-mode=legacy") + result = testdir.runpytest("--asyncio-mode=legacy") assert result.parseoutcomes()["warnings"] == 2 result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) diff --git a/tests/modes/test_strict_mode.py b/tests/modes/test_strict_mode.py index 7b574012..3b6487c7 100644 --- a/tests/modes/test_strict_mode.py +++ b/tests/modes/test_strict_mode.py @@ -1,10 +1,8 @@ from textwrap import dedent -pytest_plugins = "pytester" - -def test_strict_mode_cmdline(pytester): - pytester.makepyfile( +def test_strict_mode_cmdline(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -18,12 +16,12 @@ async def test_a(): """ ) ) - result = pytester.runpytest("--asyncio-mode=strict") + result = testdir.runpytest("--asyncio-mode=strict") result.assert_outcomes(passed=1) -def test_strict_mode_cfg(pytester): - pytester.makepyfile( +def test_strict_mode_cfg(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -37,13 +35,13 @@ async def test_a(): """ ) ) - pytester.makefile(".ini", pytest="[pytest]\nasyncio_mode = strict\n") - result = pytester.runpytest() + testdir.makefile(".ini", pytest="[pytest]\nasyncio_mode = strict\n") + result = testdir.runpytest() result.assert_outcomes(passed=1) -def test_strict_mode_method_fixture(pytester): - pytester.makepyfile( +def test_strict_mode_method_fixture(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -66,5 +64,5 @@ async def test_a(self, fixture_a): """ ) ) - result = pytester.runpytest("--asyncio-mode=auto") + result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) diff --git a/tests/test_flaky_integration.py b/tests/test_flaky_integration.py index 2e551aad..54c9d2ea 100644 --- a/tests/test_flaky_integration.py +++ b/tests/test_flaky_integration.py @@ -1,14 +1,10 @@ """Tests for the Flaky integration, which retries failed tests. """ - - from textwrap import dedent -pytest_plugins = "pytester" - -def test_auto_mode_cmdline(pytester): - pytester.makepyfile( +def test_auto_mode_cmdline(testdir): + testdir.makepyfile( dedent( """\ import asyncio @@ -29,7 +25,7 @@ async def test_asyncio_flaky_thing_that_fails_then_succeeds(): ) # runpytest_subprocess() is required to don't pollute the output # with flaky restart information - result = pytester.runpytest_subprocess() + result = testdir.runpytest_subprocess("--asyncio-mode=strict") result.assert_outcomes(passed=1) result.stdout.fnmatch_lines( [ diff --git a/tox.ini b/tox.ini index a5477455..574ea6d4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,22 @@ [tox] minversion = 3.14.0 -envlist = py37, py38, py39, py310, lint, version-info +envlist = py37, py38, py39, py310, lint, version-info, pytest-min skip_missing_interpreters = true passenv = CI [testenv] extras = testing +deps = + pytest == 6.2.5 # required for Python 3.10, not bad for others +commands = make test +allowlist_externals = + make + +[testenv:pytest-min] +extras = testing +deps = + pytest == 6.1.0 commands = make test allowlist_externals = make @@ -38,7 +48,7 @@ commands = [gh-actions] python = - 3.7: py37 + 3.7: py37, pytest-min 3.8: py38 3.9: py39, lint 3.10: py310 From 8ed5687f8c28ae6f7cf11b3726907912eaee4241 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Sun, 16 Jan 2022 22:52:14 +0200 Subject: [PATCH 075/198] Bump to 0.17.1 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2e6fd79b..faf54785 100644 --- a/README.rst +++ b/README.rst @@ -256,7 +256,7 @@ or an async framework such as `asynctest `_ - Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ From 547933dabaa56b3d9c244c8302252f3b638463d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 17 Jan 2022 16:06:32 +0100 Subject: [PATCH 076/198] Require typing-extensions on py<3.8 only (#269) typing.Literal is available since Python 3.8. Use it instead of requiring typing-extensions for systems that no longer have Python 3.7. --- pytest_asyncio/plugin.py | 7 ++++++- setup.cfg | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 7a7c8dd5..7abbd6bd 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -5,6 +5,7 @@ import functools import inspect import socket +import sys import warnings from typing import ( Any, @@ -24,7 +25,11 @@ ) import pytest -from typing_extensions import Literal + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal _R = TypeVar("_R") diff --git a/setup.cfg b/setup.cfg index f05526bd..952a1dbe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -39,7 +39,7 @@ setup_requires = install_requires = pytest >= 6.1.0 - typing-extensions >= 4.0 + typing-extensions >= 4.0; python_version < "3.8" [options.extras_require] testing = From 39c6d0ce88868d8398606ea10541befa7d7241cd Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Mon, 17 Jan 2022 17:10:02 +0200 Subject: [PATCH 077/198] Update README --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index faf54785..d903e884 100644 --- a/README.rst +++ b/README.rst @@ -256,6 +256,13 @@ or an async framework such as `asynctest `_ + + 0.17.1 (22-01-16) ~~~~~~~~~~~~~~~~~~~ - Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ From c919fd7be35b7f10ba47c953a336baa73cfa8653 Mon Sep 17 00:00:00 2001 From: Robert Craigie Date: Mon, 17 Jan 2022 10:10:39 -0500 Subject: [PATCH 078/198] Remove unconditional test item attribute access (#268) --- pytest_asyncio/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 7abbd6bd..89151971 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -452,7 +452,7 @@ def pytest_runtest_setup(item: pytest.Item) -> None: if "event_loop" in fixturenames: fixturenames.remove("event_loop") fixturenames.insert(0, "event_loop") - obj = item.obj # type: ignore[attr-defined] + obj = getattr(item, 'obj', None) if ( item.get_closest_marker("asyncio") is not None and not getattr(obj, "hypothesis", False) From 435332735305417413c04ecf29056243137d1261 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Mon, 17 Jan 2022 17:12:56 +0200 Subject: [PATCH 079/198] Update changelog --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index d903e884..68df7e09 100644 --- a/README.rst +++ b/README.rst @@ -261,6 +261,7 @@ Changelog ~~~~~~~~~~~~~~~~~~~ - Require ``typing-extensions`` on Python<3.8 only. `#269 `_ +- Fix a regression in tests collection introduced by 0.17.1, the plugin works fine with non-python tests again. `#267 `_ 0.17.1 (22-01-16) From 048a6edc56e7d2c4a5f1283b5d2dd93a1270bfce Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 19 Jan 2022 00:01:09 +0200 Subject: [PATCH 080/198] Code cleanup: drop 'request' argument from async fixtures (#270) --- pytest_asyncio/plugin.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 89151971..d3922ade 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -232,7 +232,6 @@ def _hypothesis_test_wraps_coroutine(function: Any) -> bool: class FixtureStripper: """Include additional Fixture, and then strip them""" - REQUEST = "request" EVENT_LOOP = "event_loop" def __init__(self, fixturedef: FixtureDef) -> None: @@ -330,15 +329,11 @@ def pytest_fixture_setup( fixture_stripper = FixtureStripper(fixturedef) fixture_stripper.add(FixtureStripper.EVENT_LOOP) - fixture_stripper.add(FixtureStripper.REQUEST) def wrapper(*args, **kwargs): loop = fixture_stripper.get_and_strip_from( FixtureStripper.EVENT_LOOP, kwargs ) - request = fixture_stripper.get_and_strip_from( - FixtureStripper.REQUEST, kwargs - ) gen_obj = generator(*args, **kwargs) @@ -452,7 +447,7 @@ def pytest_runtest_setup(item: pytest.Item) -> None: if "event_loop" in fixturenames: fixturenames.remove("event_loop") fixturenames.insert(0, "event_loop") - obj = getattr(item, 'obj', None) + obj = getattr(item, "obj", None) if ( item.get_closest_marker("asyncio") is not None and not getattr(obj, "hypothesis", False) From dab3b5184c0bdd0bd93dddeb6968de7f565fb8db Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Fri, 21 Jan 2022 18:59:39 +0200 Subject: [PATCH 081/198] Raise a warning if @pytest.mark.asyncio is applied to non-async function (#275) --- README.rst | 5 +++ pytest_asyncio/plugin.py | 66 +++++++++++++++++++++++++--------------- tests/test_simple.py | 39 ++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/README.rst b/README.rst index 68df7e09..2d00f5b9 100644 --- a/README.rst +++ b/README.rst @@ -257,6 +257,11 @@ or an async framework such as `asynctest `_ + 0.17.2 (22-01-17) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index d3922ade..8d9aa980 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -213,7 +213,8 @@ def pytest_pycollect_makeitem( and _hypothesis_test_wraps_coroutine(obj) ): item = pytest.Function.from_parent(collector, name=name) - if "asyncio" in item.keywords: + marker = item.get_closest_marker("asyncio") + if marker is not None: return list(collector._genfunctions(name, obj)) else: if _get_asyncio_mode(item.config) == Mode.AUTO: @@ -390,16 +391,19 @@ def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> Optional[object]: Wraps marked tests in a synchronous function where the wrapped test coroutine is executed in an event loop. """ - if "asyncio" in pyfuncitem.keywords: + marker = pyfuncitem.get_closest_marker("asyncio") + if marker is not None: funcargs: Dict[str, object] = pyfuncitem.funcargs # type: ignore[name-defined] loop = cast(asyncio.AbstractEventLoop, funcargs["event_loop"]) if _is_hypothesis_test(pyfuncitem.obj): pyfuncitem.obj.hypothesis.inner_test = wrap_in_sync( + pyfuncitem, pyfuncitem.obj.hypothesis.inner_test, _loop=loop, ) else: pyfuncitem.obj = wrap_in_sync( + pyfuncitem, pyfuncitem.obj, _loop=loop, ) @@ -410,7 +414,11 @@ def _is_hypothesis_test(function: Any) -> bool: return getattr(function, "is_hypothesis_test", False) -def wrap_in_sync(func: Callable[..., Awaitable[Any]], _loop: asyncio.AbstractEventLoop): +def wrap_in_sync( + pyfuncitem: pytest.Function, + func: Callable[..., Awaitable[Any]], + _loop: asyncio.AbstractEventLoop, +): """Return a sync wrapper around an async function executing it in the current event loop.""" @@ -424,34 +432,44 @@ def wrap_in_sync(func: Callable[..., Awaitable[Any]], _loop: asyncio.AbstractEve @functools.wraps(func) def inner(**kwargs): coro = func(**kwargs) - if coro is not None: - task = asyncio.ensure_future(coro, loop=_loop) - try: - _loop.run_until_complete(task) - except BaseException: - # run_until_complete doesn't get the result from exceptions - # that are not subclasses of `Exception`. Consume all - # exceptions to prevent asyncio's warning from logging. - if task.done() and not task.cancelled(): - task.exception() - raise + if not inspect.isawaitable(coro): + pyfuncitem.warn( + pytest.PytestWarning( + f"The test {pyfuncitem} is marked with '@pytest.mark.asyncio' " + "but it is not an async function. " + "Please remove asyncio marker. " + "If the test is not marked explicitly, " + "check for global markers applied via 'pytestmark'." + ) + ) + return + task = asyncio.ensure_future(coro, loop=_loop) + try: + _loop.run_until_complete(task) + except BaseException: + # run_until_complete doesn't get the result from exceptions + # that are not subclasses of `Exception`. Consume all + # exceptions to prevent asyncio's warning from logging. + if task.done() and not task.cancelled(): + task.exception() + raise inner._raw_test_func = func # type: ignore[attr-defined] return inner def pytest_runtest_setup(item: pytest.Item) -> None: - if "asyncio" in item.keywords: - fixturenames = item.fixturenames # type: ignore[attr-defined] - # inject an event loop fixture for all async tests - if "event_loop" in fixturenames: - fixturenames.remove("event_loop") - fixturenames.insert(0, "event_loop") + marker = item.get_closest_marker("asyncio") + if marker is None: + return + fixturenames = item.fixturenames # type: ignore[attr-defined] + # inject an event loop fixture for all async tests + if "event_loop" in fixturenames: + fixturenames.remove("event_loop") + fixturenames.insert(0, "event_loop") obj = getattr(item, "obj", None) - if ( - item.get_closest_marker("asyncio") is not None - and not getattr(obj, "hypothesis", False) - and getattr(obj, "is_hypothesis_test", False) + if not getattr(obj, "hypothesis", False) and getattr( + obj, "is_hypothesis_test", False ): pytest.fail( "test function `%r` is using Hypothesis, but pytest-asyncio " diff --git a/tests/test_simple.py b/tests/test_simple.py index 31204b6c..dc68d61e 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -1,5 +1,6 @@ """Quick'n'dirty unit tests for provided fixtures and markers.""" import asyncio +from textwrap import dedent import pytest @@ -26,14 +27,14 @@ async def test_asyncio_marker(): @pytest.mark.xfail(reason="need a failure", strict=True) @pytest.mark.asyncio -def test_asyncio_marker_fail(): +async def test_asyncio_marker_fail(): raise AssertionError @pytest.mark.asyncio -def test_asyncio_marker_with_default_param(a_param=None): +async def test_asyncio_marker_with_default_param(a_param=None): """Test the asyncio pytest marker.""" - yield # sleep(0) + await asyncio.sleep(0) @pytest.mark.asyncio @@ -240,3 +241,35 @@ async def test_no_warning_on_skip(): def test_async_close_loop(event_loop): event_loop.close() return "ok" + + +def test_warn_asyncio_marker_for_regular_func(testdir): + testdir.makepyfile( + dedent( + """\ + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + def test_a(): + pass + """ + ) + ) + testdir.makefile( + ".ini", + pytest=dedent( + """\ + [pytest] + asyncio_mode = strict + filterwarnings = + default + """ + ), + ) + result = testdir.runpytest() + result.assert_outcomes(passed=1) + result.stdout.fnmatch_lines( + ["*is marked with '@pytest.mark.asyncio' but it is not an async function.*"] + ) From d8efa640f0aa1ba8856b908ba486150588018209 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 26 Jan 2022 00:30:26 +0200 Subject: [PATCH 082/198] Support parametrized event_loop fixture (#278) --- README.rst | 1 + pytest_asyncio/plugin.py | 229 +++++++++--------- .../async_fixtures/test_parametrized_loop.py | 31 +++ 3 files changed, 146 insertions(+), 115 deletions(-) create mode 100644 tests/async_fixtures/test_parametrized_loop.py diff --git a/README.rst b/README.rst index 2d00f5b9..7c788475 100644 --- a/README.rst +++ b/README.rst @@ -261,6 +261,7 @@ Changelog ~~~~~~~~~~~~~~~~~~~ - Raise a warning if @pytest.mark.asyncio is applied to non-async function. `#275 `_ +- Support parametrized ``event_loop`` fixture. `#278 `_ 0.17.2 (22-01-17) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 8d9aa980..f0374893 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -165,7 +165,7 @@ def _set_explicit_asyncio_mark(obj: Any) -> None: def _is_coroutine(obj: Any) -> bool: """Check to see if an object is really an asyncio coroutine.""" - return asyncio.iscoroutinefunction(obj) or inspect.isgeneratorfunction(obj) + return asyncio.iscoroutinefunction(obj) def _is_coroutine_or_asyncgen(obj: Any) -> bool: @@ -198,6 +198,118 @@ def pytest_report_header(config: Config) -> List[str]: return [f"asyncio: mode={mode}"] +def _preprocess_async_fixtures(config: Config, holder: Set[FixtureDef]) -> None: + asyncio_mode = _get_asyncio_mode(config) + fixturemanager = config.pluginmanager.get_plugin("funcmanage") + for fixtures in fixturemanager._arg2fixturedefs.values(): + for fixturedef in fixtures: + if fixturedef is holder: + continue + func = fixturedef.func + if not _is_coroutine_or_asyncgen(func): + # Nothing to do with a regular fixture function + continue + if not _has_explicit_asyncio_mark(func): + if asyncio_mode == Mode.AUTO: + # Enforce asyncio mode if 'auto' + _set_explicit_asyncio_mark(func) + elif asyncio_mode == Mode.LEGACY: + _set_explicit_asyncio_mark(func) + try: + code = func.__code__ + except AttributeError: + code = func.__func__.__code__ + name = ( + f"" + ) + warnings.warn( + LEGACY_ASYNCIO_FIXTURE.format(name=name), + DeprecationWarning, + ) + + to_add = [] + for name in ("request", "event_loop"): + if name not in fixturedef.argnames: + to_add.append(name) + + if to_add: + fixturedef.argnames += tuple(to_add) + + if inspect.isasyncgenfunction(func): + fixturedef.func = _wrap_asyncgen(func) + elif inspect.iscoroutinefunction(func): + fixturedef.func = _wrap_async(func) + + assert _has_explicit_asyncio_mark(fixturedef.func) + holder.add(fixturedef) + + +def _add_kwargs( + func: Callable[..., Any], + kwargs: Dict[str, Any], + event_loop: asyncio.AbstractEventLoop, + request: SubRequest, +) -> Dict[str, Any]: + sig = inspect.signature(func) + ret = kwargs.copy() + if "request" in sig.parameters: + ret["request"] = request + if "event_loop" in sig.parameters: + ret["event_loop"] = event_loop + return ret + + +def _wrap_asyncgen(func: Callable[..., AsyncIterator[_R]]) -> Callable[..., _R]: + @functools.wraps(func) + def _asyncgen_fixture_wrapper( + event_loop: asyncio.AbstractEventLoop, request: SubRequest, **kwargs: Any + ) -> _R: + gen_obj = func(**_add_kwargs(func, kwargs, event_loop, request)) + + async def setup() -> _R: + res = await gen_obj.__anext__() + return res + + def finalizer() -> None: + """Yield again, to finalize.""" + + async def async_finalizer() -> None: + try: + await gen_obj.__anext__() + except StopAsyncIteration: + pass + else: + msg = "Async generator fixture didn't stop." + msg += "Yield only once." + raise ValueError(msg) + + event_loop.run_until_complete(async_finalizer()) + + result = event_loop.run_until_complete(setup()) + request.addfinalizer(finalizer) + return result + + return _asyncgen_fixture_wrapper + + +def _wrap_async(func: Callable[..., Awaitable[_R]]) -> Callable[..., _R]: + @functools.wraps(func) + def _async_fixture_wrapper( + event_loop: asyncio.AbstractEventLoop, request: SubRequest, **kwargs: Any + ) -> _R: + async def setup() -> _R: + res = await func(**_add_kwargs(func, kwargs, event_loop, request)) + return res + + return event_loop.run_until_complete(setup()) + + return _async_fixture_wrapper + + +_HOLDER: Set[FixtureDef] = set() + + @pytest.mark.tryfirst def pytest_pycollect_makeitem( collector: Union[pytest.Module, pytest.Class], name: str, obj: object @@ -212,6 +324,7 @@ def pytest_pycollect_makeitem( or _is_hypothesis_test(obj) and _hypothesis_test_wraps_coroutine(obj) ): + _preprocess_async_fixtures(collector.config, _HOLDER) item = pytest.Function.from_parent(collector, name=name) marker = item.get_closest_marker("asyncio") if marker is not None: @@ -230,31 +343,6 @@ def _hypothesis_test_wraps_coroutine(function: Any) -> bool: return _is_coroutine(function.hypothesis.inner_test) -class FixtureStripper: - """Include additional Fixture, and then strip them""" - - EVENT_LOOP = "event_loop" - - def __init__(self, fixturedef: FixtureDef) -> None: - self.fixturedef = fixturedef - self.to_strip: Set[str] = set() - - def add(self, name: str) -> None: - """Add fixture name to fixturedef - and record in to_strip list (If not previously included)""" - if name in self.fixturedef.argnames: - return - self.fixturedef.argnames += (name,) - self.to_strip.add(name) - - def get_and_strip_from(self, name: str, data_dict: Dict[str, _T]) -> _T: - """Strip name from data, and return value""" - result = data_dict[name] - if name in self.to_strip: - del data_dict[name] - return result - - @pytest.hookimpl(trylast=True) def pytest_fixture_post_finalizer(fixturedef: FixtureDef, request: SubRequest) -> None: """Called after fixture teardown""" @@ -291,95 +379,6 @@ def pytest_fixture_setup( policy.set_event_loop(loop) return - func = fixturedef.func - if not _is_coroutine_or_asyncgen(func): - # Nothing to do with a regular fixture function - yield - return - - config = request.node.config - asyncio_mode = _get_asyncio_mode(config) - - if not _has_explicit_asyncio_mark(func): - if asyncio_mode == Mode.AUTO: - # Enforce asyncio mode if 'auto' - _set_explicit_asyncio_mark(func) - elif asyncio_mode == Mode.LEGACY: - _set_explicit_asyncio_mark(func) - try: - code = func.__code__ - except AttributeError: - code = func.__func__.__code__ - name = ( - f"" - ) - warnings.warn( - LEGACY_ASYNCIO_FIXTURE.format(name=name), - DeprecationWarning, - ) - else: - # asyncio_mode is STRICT, - # don't handle fixtures that are not explicitly marked - yield - return - - if inspect.isasyncgenfunction(func): - # This is an async generator function. Wrap it accordingly. - generator = func - - fixture_stripper = FixtureStripper(fixturedef) - fixture_stripper.add(FixtureStripper.EVENT_LOOP) - - def wrapper(*args, **kwargs): - loop = fixture_stripper.get_and_strip_from( - FixtureStripper.EVENT_LOOP, kwargs - ) - - gen_obj = generator(*args, **kwargs) - - async def setup(): - res = await gen_obj.__anext__() - return res - - def finalizer(): - """Yield again, to finalize.""" - - async def async_finalizer(): - try: - await gen_obj.__anext__() - except StopAsyncIteration: - pass - else: - msg = "Async generator fixture didn't stop." - msg += "Yield only once." - raise ValueError(msg) - - loop.run_until_complete(async_finalizer()) - - result = loop.run_until_complete(setup()) - request.addfinalizer(finalizer) - return result - - fixturedef.func = wrapper - elif inspect.iscoroutinefunction(func): - coro = func - - fixture_stripper = FixtureStripper(fixturedef) - fixture_stripper.add(FixtureStripper.EVENT_LOOP) - - def wrapper(*args, **kwargs): - loop = fixture_stripper.get_and_strip_from( - FixtureStripper.EVENT_LOOP, kwargs - ) - - async def setup(): - res = await coro(*args, **kwargs) - return res - - return loop.run_until_complete(setup()) - - fixturedef.func = wrapper yield diff --git a/tests/async_fixtures/test_parametrized_loop.py b/tests/async_fixtures/test_parametrized_loop.py new file mode 100644 index 00000000..2fb8befa --- /dev/null +++ b/tests/async_fixtures/test_parametrized_loop.py @@ -0,0 +1,31 @@ +import asyncio + +import pytest + +TESTS_COUNT = 0 + + +def teardown_module(): + # parametrized 2 * 2 times: 2 for 'event_loop' and 2 for 'fix' + assert TESTS_COUNT == 4 + + +@pytest.fixture(scope="module", params=[1, 2]) +def event_loop(request): + request.param + loop = asyncio.new_event_loop() + yield loop + loop.close() + + +@pytest.fixture(params=["a", "b"]) +async def fix(request): + await asyncio.sleep(0) + return request.param + + +@pytest.mark.asyncio +async def test_parametrized_loop(fix): + await asyncio.sleep(0) + global TESTS_COUNT + TESTS_COUNT += 1 From e78b59d5d8f8fed7d3aaf39c184a7d4a337676de Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 3 Feb 2022 17:07:52 +0200 Subject: [PATCH 083/198] Fix setuptools_scm configuration (#279) * Fix setuptools_scm configuration * build: Enabled Tox build isolation. This fixes an issue that forced us to add setuptools_scm to setup.cfg, instead of specifying the dependency just once in pyproject.toml. See discussion https://github.com/pytest-dev/pytest-asyncio/pull/279 Signed-off-by: Michael Seifert Co-authored-by: Michael Seifert --- pyproject.toml | 2 +- setup.cfg | 3 --- tox.ini | 1 + 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 189ffa1d..81540a53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ requires = [ "setuptools>=51.0", "wheel>=0.36", - "setuptools_scm>=6.2" + "setuptools_scm[toml]>=6.2" ] build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg index 952a1dbe..18aa9489 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,9 +34,6 @@ python_requires = >=3.7 packages = find: include_package_data = True -setup_requires = - setuptools_scm >= 6.2 - install_requires = pytest >= 6.1.0 typing-extensions >= 4.0; python_version < "3.8" diff --git a/tox.ini b/tox.ini index 574ea6d4..53aca291 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,7 @@ minversion = 3.14.0 envlist = py37, py38, py39, py310, lint, version-info, pytest-min skip_missing_interpreters = true +isolated_build = true passenv = CI From a92d8947ab57c7d88082dff9dcded686622ed47b Mon Sep 17 00:00:00 2001 From: Matthieu MN <10926130+gazorby@users.noreply.github.com> Date: Mon, 7 Feb 2022 12:21:04 +0100 Subject: [PATCH 084/198] Relax dependency on typing-extensions (#284) --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 18aa9489..a28c5fcc 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,7 +36,7 @@ include_package_data = True install_requires = pytest >= 6.1.0 - typing-extensions >= 4.0; python_version < "3.8" + typing-extensions >= 3.7.2; python_version < "3.8" [options.extras_require] testing = From 07e9922f1dc9cb84f0948e6c84ad9921c3662969 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 7 Feb 2022 12:41:20 +0100 Subject: [PATCH 085/198] Prepare release of v0.18.0 (#282) Signed-off-by: Michael Seifert Co-authored-by: Andrew Svetlov --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 7c788475..e1e432f2 100644 --- a/README.rst +++ b/README.rst @@ -257,7 +257,7 @@ or an async framework such as `asynctest `_ From bf3d32cf0d1e2c546406ba53b96d40d10a1e6fbd Mon Sep 17 00:00:00 2001 From: Kian-Meng Ang Date: Wed, 9 Feb 2022 21:47:45 +0800 Subject: [PATCH 086/198] Fix typos in README (#289) --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index e1e432f2..900167df 100644 --- a/README.rst +++ b/README.rst @@ -69,7 +69,7 @@ The mode can be set by ``asyncio_mode`` configuration option in `configuration f [pytest] asyncio_mode = auto -The value can be overriden by command-line option for ``pytest`` invocation: +The value can be overridden by command-line option for ``pytest`` invocation: .. code-block:: bash @@ -91,7 +91,7 @@ plugin. This mode requires the simplest tests and fixtures configuration and is recommended for default usage *unless* the same project and its test suite should execute tests from different async frameworks, e.g. ``asyncio`` and ``trio``. In this -case, auto-handling can break tests designed for other framework; plase use *strict* +case, auto-handling can break tests designed for other framework; please use *strict* mode instead. Strict mode From f7c8226af1d207650c11b203649759d2051d3a8d Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 10 Feb 2022 12:57:43 +0100 Subject: [PATCH 087/198] fix: Fixed a regression that prevented async fixtures from working in sync tests. (#287) The commit simply processes all async fixtures of a test regardless of whether the test is an async function or not. Closes #286 Signed-off-by: Michael Seifert --- README.rst | 4 ++++ pytest_asyncio/plugin.py | 2 +- tests/test_asyncio_fixture.py | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 900167df..87a52eed 100644 --- a/README.rst +++ b/README.rst @@ -257,6 +257,10 @@ or an async framework such as `asynctest `_ + 0.18.0 (22-02-07) ~~~~~~~~~~~~~~~~~~~ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index f0374893..1ecfbe49 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -319,12 +319,12 @@ def pytest_pycollect_makeitem( """A pytest hook to collect asyncio coroutines.""" if not collector.funcnamefilter(name): return None + _preprocess_async_fixtures(collector.config, _HOLDER) if ( _is_coroutine(obj) or _is_hypothesis_test(obj) and _hypothesis_test_wraps_coroutine(obj) ): - _preprocess_async_fixtures(collector.config, _HOLDER) item = pytest.Function.from_parent(collector, name=name) marker = item.get_closest_marker("asyncio") if marker is not None: diff --git a/tests/test_asyncio_fixture.py b/tests/test_asyncio_fixture.py index cfe10479..3a28cebb 100644 --- a/tests/test_asyncio_fixture.py +++ b/tests/test_asyncio_fixture.py @@ -1,4 +1,5 @@ import asyncio +from textwrap import dedent import pytest @@ -39,3 +40,25 @@ async def fixture_with_params(request): async def test_fixture_with_params(fixture_with_params): await asyncio.sleep(0) assert fixture_with_params % 2 == 0 + + +@pytest.mark.parametrize("mode", ("auto", "strict", "legacy")) +def test_sync_function_uses_async_fixture(testdir, mode): + testdir.makepyfile( + dedent( + """\ + import pytest_asyncio + + pytest_plugins = 'pytest_asyncio' + + @pytest_asyncio.fixture + async def always_true(): + return True + + def test_sync_function_uses_async_fixture(always_true): + assert always_true is True + """ + ) + ) + result = testdir.runpytest(f"--asyncio-mode={mode}") + result.assert_outcomes(passed=1) From 34436cd6653b1dd8e1836a99ca1412b850167f52 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Thu, 10 Feb 2022 13:58:38 +0200 Subject: [PATCH 088/198] Release 0.18.1 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 87a52eed..52434b2f 100644 --- a/README.rst +++ b/README.rst @@ -257,7 +257,7 @@ or an async framework such as `asynctest `_ From 9246f5825f589ff01f1c67620ce34bdc416c5af3 Mon Sep 17 00:00:00 2001 From: kriek Date: Wed, 23 Feb 2022 15:24:09 +0100 Subject: [PATCH 089/198] Fix asyncio auto mode not marking static methods (closes pytest-dev/pytest-asyncio#265, closes pytest-dev/pytest-asyncio#292). (#295) Co-authored-by: Andrew Svetlov --- pytest_asyncio/plugin.py | 3 +++ tests/modes/test_auto_mode.py | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 1ecfbe49..c31683ab 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -320,6 +320,9 @@ def pytest_pycollect_makeitem( if not collector.funcnamefilter(name): return None _preprocess_async_fixtures(collector.config, _HOLDER) + if isinstance(obj, staticmethod): + # staticmethods need to be unwrapped. + obj = obj.__func__ if ( _is_coroutine(obj) or _is_hypothesis_test(obj) diff --git a/tests/modes/test_auto_mode.py b/tests/modes/test_auto_mode.py index 157ffded..fc4d2df0 100644 --- a/tests/modes/test_auto_mode.py +++ b/tests/modes/test_auto_mode.py @@ -87,3 +87,53 @@ async def test_a(self, fixture_a): ) result = testdir.runpytest("--asyncio-mode=auto") result.assert_outcomes(passed=1) + + +def test_auto_mode_static_method(testdir): + testdir.makepyfile( + dedent( + """\ + import asyncio + + pytest_plugins = 'pytest_asyncio' + + + class TestA: + + @staticmethod + async def test_a(): + await asyncio.sleep(0) + """ + ) + ) + result = testdir.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) + + +def test_auto_mode_static_method_fixture(testdir): + testdir.makepyfile( + dedent( + """\ + import asyncio + import pytest + + pytest_plugins = 'pytest_asyncio' + + + class TestA: + + @staticmethod + @pytest.fixture + async def fixture_a(): + await asyncio.sleep(0) + return 1 + + @staticmethod + async def test_a(fixture_a): + await asyncio.sleep(0) + assert fixture_a == 1 + """ + ) + ) + result = testdir.runpytest("--asyncio-mode=auto") + result.assert_outcomes(passed=1) From beee1f640d6f0da0f7c25d591f53f1517753fba3 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Wed, 23 Feb 2022 16:25:43 +0200 Subject: [PATCH 090/198] Update changelog --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index 52434b2f..402d84dc 100644 --- a/README.rst +++ b/README.rst @@ -257,6 +257,11 @@ or an async framework such as `asynctest `_ + + 0.18.1 (22-02-10) ~~~~~~~~~~~~~~~~~~~ - Fixes a regression that prevented async fixtures from working in synchronous tests. `#286 `_ From 357cddb506c03406d9769a5aedcc026b4fa80cb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Feb 2022 19:47:58 +0100 Subject: [PATCH 091/198] Bump actions/setup-python from 2 to 3 (#300) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 3. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1728d40f..a9b33649 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: '3.9' - name: Install GitHub matcher for ActionLint checker @@ -61,7 +61,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From cad1b94f1457e2a07eb58ccd32269a95e1dda1c3 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 3 Mar 2022 08:29:28 +0100 Subject: [PATCH 092/198] fix: Add positional arguments to the synchronous test function wrapper. (#303) This fixes a compatibility issue with Hypothesis 6.39.0. Closes #302 Signed-off-by: Michael Seifert --- README.rst | 1 + pytest_asyncio/plugin.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 402d84dc..d7c82615 100644 --- a/README.rst +++ b/README.rst @@ -260,6 +260,7 @@ Changelog 0.18.2 (Unreleased) ~~~~~~~~~~~~~~~~~~~ - Fix asyncio auto mode not marking static methods. `#295 `_ +- Fix a compatibility issue with Hypothesis 6.39.0. `#302 `_ 0.18.1 (22-02-10) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index c31683ab..187f51da 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -432,8 +432,8 @@ def wrap_in_sync( func = raw_func @functools.wraps(func) - def inner(**kwargs): - coro = func(**kwargs) + def inner(*args, **kwargs): + coro = func(*args, **kwargs) if not inspect.isawaitable(coro): pyfuncitem.warn( pytest.PytestWarning( From 2359807ec75a1a39c9f60fae715b3a39885c67cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 08:35:31 +0100 Subject: [PATCH 093/198] Bump actions/checkout from 2 to 3 (#301) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a9b33649..a5ffe577 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,7 @@ jobs: version: ${{ steps.version.outputs.version }} prerelease: ${{ steps.version.outputs.prerelease }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - uses: actions/setup-python@v3 @@ -58,7 +58,7 @@ jobs: python-version: ['3.7', '3.8', '3.9', '3.10'] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - uses: actions/setup-python@v3 @@ -103,7 +103,7 @@ jobs: run: | sudo apt-get install -y pandoc - name: Checkout - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: Download distributions From 929608e60ec2c2643c7d0e7b0604cf186c158cd9 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 3 Mar 2022 12:34:36 +0100 Subject: [PATCH 094/198] docs: Prepare release 0.18.2. (#304) Signed-off-by: Michael Seifert --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d7c82615..5d313344 100644 --- a/README.rst +++ b/README.rst @@ -257,7 +257,7 @@ or an async framework such as `asynctest `_ - Fix a compatibility issue with Hypothesis 6.39.0. `#302 `_ From 82d212b6f510468b3a68752de30f50ab7ac61131 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 8 Mar 2022 17:55:53 +0100 Subject: [PATCH 095/198] Extract changelog to separate file (#306) * docs: Extracted changelog into a separate file. Signed-off-by: Michael Seifert * docs: Adjusted heading adornments in changelog to reflect its status as a standalone file. Signed-off-by: Michael Seifert * build: Removed GitHub and git-related files from the source tarball. Signed-off-by: Michael Seifert --- CHANGELOG.rst | 158 ++++++++++++++++++++++++++++++++++++++++++++++++ MANIFEST.in | 5 ++ README.rst | 163 -------------------------------------------------- 3 files changed, 163 insertions(+), 163 deletions(-) create mode 100644 CHANGELOG.rst create mode 100644 MANIFEST.in diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 00000000..3eac3894 --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,158 @@ +========= +Changelog +========= + +0.18.2 (22-03-03) +================= +- Fix asyncio auto mode not marking static methods. `#295 `_ +- Fix a compatibility issue with Hypothesis 6.39.0. `#302 `_ + +0.18.1 (22-02-10) +================= +- Fixes a regression that prevented async fixtures from working in synchronous tests. `#286 `_ + +0.18.0 (22-02-07) +================= + +- Raise a warning if @pytest.mark.asyncio is applied to non-async function. `#275 `_ +- Support parametrized ``event_loop`` fixture. `#278 `_ + +0.17.2 (22-01-17) +================= + +- Require ``typing-extensions`` on Python<3.8 only. `#269 `_ +- Fix a regression in tests collection introduced by 0.17.1, the plugin works fine with non-python tests again. `#267 `_ + + +0.17.1 (22-01-16) +================= +- Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ +- Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ +- Added type annotations. `#198 `_ +- Show asyncio mode in pytest report headers. `#266 `_ +- Relax ``asyncio_mode`` type definition; it allows to support pytest 6.1+. `#262 `_ + +0.17.0 (22-01-13) +================= +- `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ +- Drop support for Python 3.6 +- Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ +- Added `flaky `_ to test dependencies +- Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ +- Added the plugin modes: *strict*, *auto*, and *legacy*. See `documentation `_ for details. `#125 `_ +- Correctly process ``KeyboardInterrupt`` during async fixture setup phase `#219 `_ + +0.16.0 (2021-10-16) +=================== +- Add support for Python 3.10 + +0.15.1 (2021-04-22) +=================== +- Hotfix for errors while closing event loops while replacing them. + `#209 `_ + `#210 `_ + +0.15.0 (2021-04-19) +=================== +- Add support for Python 3.9 +- Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. +- Set ``unused_tcp_port_factory`` fixture scope to 'session'. + `#163 `_ +- Properly close event loops when replacing them. + `#208 `_ + +0.14.0 (2020-06-24) +=================== +- Fix `#162 `_, and ``event_loop`` fixture behavior now is coherent on all scopes. + `#164 `_ + +0.12.0 (2020-05-04) +=================== +- Run the event loop fixture as soon as possible. This helps with fixtures that have an implicit dependency on the event loop. + `#156 `_ + +0.11.0 (2020-04-20) +=================== +- Test on 3.8, drop 3.3 and 3.4. Stick to 0.10 for these versions. + `#152 `_ +- Use the new Pytest 5.4.0 Function API. We therefore depend on pytest >= 5.4.0. + `#142 `_ +- Better ``pytest.skip`` support. + `#126 `_ + +0.10.0 (2019-01-08) +==================== +- ``pytest-asyncio`` integrates with `Hypothesis `_ + to support ``@given`` on async test functions using ``asyncio``. + `#102 `_ +- Pytest 4.1 support. + `#105 `_ + +0.9.0 (2018-07-28) +================== +- 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) +================== +- Improve integration with other packages (like aiohttp) with more careful event loop handling. + `#64 `_ + +0.7.0 (2017-09-08) +================== +- Python versions pre-3.6 can use the async_generator library for async fixtures. + `#62 ` + +0.6.0 (2017-05-28) +================== +- Support for Python versions pre-3.5 has been dropped. +- ``pytestmark`` now works on both module and class level. +- The ``forbid_global_loop`` parameter has been removed. +- Support for async and async gen fixtures has been added. + `#45 `_ +- The deprecation warning regarding ``asyncio.async()`` has been fixed. + `#51 `_ + +0.5.0 (2016-09-07) +================== +- Introduced a changelog. + `#31 `_ +- The ``event_loop`` fixture is again responsible for closing itself. + This makes the fixture slightly harder to correctly override, but enables + other fixtures to depend on it correctly. + `#30 `_ +- Deal with the event loop policy by wrapping a special pytest hook, + ``pytest_fixture_setup``. This allows setting the policy before fixtures + dependent on the ``event_loop`` fixture run, thus allowing them to take + advantage of the ``forbid_global_loop`` parameter. As a consequence of this, + we now depend on pytest 3.0. + `#29 `_ + +0.4.1 (2016-06-01) +================== +- Fix a bug preventing the propagation of exceptions from the plugin. + `#25 `_ + +0.4.0 (2016-05-30) +================== +- Make ``event_loop`` fixtures simpler to override by closing them in the + plugin, instead of directly in the fixture. + `#21 `_ +- Introduce the ``forbid_global_loop`` parameter. + `#21 `_ + +0.3.0 (2015-12-19) +================== +- Support for Python 3.5 ``async``/``await`` syntax. + `#17 `_ + +0.2.0 (2015-08-01) +================== +- ``unused_tcp_port_factory`` fixture. + `#10 `_ + +0.1.1 (2015-04-23) +================== +Initial release. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..fdf813e9 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include CHANGELOG.rst + +recursive-exclude .github * +exclude .gitignore +exclude .pre-commit-config.yaml diff --git a/README.rst b/README.rst index 5d313344..93b369b7 100644 --- a/README.rst +++ b/README.rst @@ -254,169 +254,6 @@ Test classes subclassing the standard `unittest `__ or an async framework such as `asynctest `__. -Changelog ---------- - -0.18.2 (22-03-03) -~~~~~~~~~~~~~~~~~~~ -- Fix asyncio auto mode not marking static methods. `#295 `_ -- Fix a compatibility issue with Hypothesis 6.39.0. `#302 `_ - - -0.18.1 (22-02-10) -~~~~~~~~~~~~~~~~~~~ -- Fixes a regression that prevented async fixtures from working in synchronous tests. `#286 `_ - -0.18.0 (22-02-07) -~~~~~~~~~~~~~~~~~~~ - -- Raise a warning if @pytest.mark.asyncio is applied to non-async function. `#275 `_ -- Support parametrized ``event_loop`` fixture. `#278 `_ - -0.17.2 (22-01-17) -~~~~~~~~~~~~~~~~~~~ - -- Require ``typing-extensions`` on Python<3.8 only. `#269 `_ -- Fix a regression in tests collection introduced by 0.17.1, the plugin works fine with non-python tests again. `#267 `_ - - -0.17.1 (22-01-16) -~~~~~~~~~~~~~~~~~~~ -- Fixes a bug that prevents async Hypothesis tests from working without explicit ``asyncio`` marker when ``--asyncio-mode=auto`` is set. `#258 `_ -- Fixed a bug that closes the default event loop if the loop doesn't exist `#257 `_ -- Added type annotations. `#198 `_ -- Show asyncio mode in pytest report headers. `#266 `_ -- Relax ``asyncio_mode`` type definition; it allows to support pytest 6.1+. `#262 `_ - -0.17.0 (22-01-13) -~~~~~~~~~~~~~~~~~~~ -- `pytest-asyncio` no longer alters existing event loop policies. `#168 `_, `#188 `_ -- Drop support for Python 3.6 -- Fixed an issue when pytest-asyncio was used in combination with `flaky` or inherited asynchronous Hypothesis tests. `#178 `_ `#231 `_ -- Added `flaky `_ to test dependencies -- Added ``unused_udp_port`` and ``unused_udp_port_factory`` fixtures (similar to ``unused_tcp_port`` and ``unused_tcp_port_factory`` counterparts. `#99 `_ -- Added the plugin modes: *strict*, *auto*, and *legacy*. See `documentation `_ for details. `#125 `_ -- Correctly process ``KeyboardInterrupt`` during async fixture setup phase `#219 `_ - -0.16.0 (2021-10-16) -~~~~~~~~~~~~~~~~~~~ -- Add support for Python 3.10 - -0.15.1 (2021-04-22) -~~~~~~~~~~~~~~~~~~~ -- Hotfix for errors while closing event loops while replacing them. - `#209 `_ - `#210 `_ - -0.15.0 (2021-04-19) -~~~~~~~~~~~~~~~~~~~ -- Add support for Python 3.9 -- Abandon support for Python 3.5. If you still require support for Python 3.5, please use pytest-asyncio v0.14 or earlier. -- Set ``unused_tcp_port_factory`` fixture scope to 'session'. - `#163 `_ -- Properly close event loops when replacing them. - `#208 `_ - -0.14.0 (2020-06-24) -~~~~~~~~~~~~~~~~~~~ -- Fix `#162 `_, and ``event_loop`` fixture behavior now is coherent on all scopes. - `#164 `_ - -0.12.0 (2020-05-04) -~~~~~~~~~~~~~~~~~~~ -- Run the event loop fixture as soon as possible. This helps with fixtures that have an implicit dependency on the event loop. - `#156 `_ - -0.11.0 (2020-04-20) -~~~~~~~~~~~~~~~~~~~ -- Test on 3.8, drop 3.3 and 3.4. Stick to 0.10 for these versions. - `#152 `_ -- Use the new Pytest 5.4.0 Function API. We therefore depend on pytest >= 5.4.0. - `#142 `_ -- Better ``pytest.skip`` support. - `#126 `_ - -0.10.0 (2019-01-08) -~~~~~~~~~~~~~~~~~~~~ -- ``pytest-asyncio`` integrates with `Hypothesis `_ - to support ``@given`` on async test functions using ``asyncio``. - `#102 `_ -- Pytest 4.1 support. - `#105 `_ - -0.9.0 (2018-07-28) -~~~~~~~~~~~~~~~~~~ -- 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) -~~~~~~~~~~~~~~~~~~ -- Improve integration with other packages (like aiohttp) with more careful event loop handling. - `#64 `_ - -0.7.0 (2017-09-08) -~~~~~~~~~~~~~~~~~~ -- Python versions pre-3.6 can use the async_generator library for async fixtures. - `#62 ` - - -0.6.0 (2017-05-28) -~~~~~~~~~~~~~~~~~~ -- Support for Python versions pre-3.5 has been dropped. -- ``pytestmark`` now works on both module and class level. -- The ``forbid_global_loop`` parameter has been removed. -- Support for async and async gen fixtures has been added. - `#45 `_ -- The deprecation warning regarding ``asyncio.async()`` has been fixed. - `#51 `_ - -0.5.0 (2016-09-07) -~~~~~~~~~~~~~~~~~~ -- Introduced a changelog. - `#31 `_ -- The ``event_loop`` fixture is again responsible for closing itself. - This makes the fixture slightly harder to correctly override, but enables - other fixtures to depend on it correctly. - `#30 `_ -- Deal with the event loop policy by wrapping a special pytest hook, - ``pytest_fixture_setup``. This allows setting the policy before fixtures - dependent on the ``event_loop`` fixture run, thus allowing them to take - advantage of the ``forbid_global_loop`` parameter. As a consequence of this, - we now depend on pytest 3.0. - `#29 `_ - - -0.4.1 (2016-06-01) -~~~~~~~~~~~~~~~~~~ -- Fix a bug preventing the propagation of exceptions from the plugin. - `#25 `_ - -0.4.0 (2016-05-30) -~~~~~~~~~~~~~~~~~~ -- Make ``event_loop`` fixtures simpler to override by closing them in the - plugin, instead of directly in the fixture. - `#21 `_ -- Introduce the ``forbid_global_loop`` parameter. - `#21 `_ - -0.3.0 (2015-12-19) -~~~~~~~~~~~~~~~~~~ -- Support for Python 3.5 ``async``/``await`` syntax. - `#17 `_ - -0.2.0 (2015-08-01) -~~~~~~~~~~~~~~~~~~ -- ``unused_tcp_port_factory`` fixture. - `#10 `_ - - -0.1.1 (2015-04-23) -~~~~~~~~~~~~~~~~~~ -Initial release. - - Contributing ------------ Contributions are very welcome. Tests can be run with ``tox``, please ensure From 133d8a81ecb283821d63a622ee2ae24b946d062a Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 11 Mar 2022 12:53:49 +0100 Subject: [PATCH 096/198] Fix CI linting workflow (#308) * ci: No longer fail silently when the expected Python interpreter is missing. The tox "lint" target expects Python 3.10 to be installed, but CI only installs Python 3.9. skip_missing_interpreters caused the "lint" workflow in CI to exit successfully, even though no linting was performed. Signed-off-by: Michael Seifert * ci: Install Python 3.10 for the "lint" workflow, as expected by the tox configuration. Signed-off-by: Michael Seifert * ci: Do not inlcude tox's "lint" environment in the set of "3.9" environments of a GitHub actions run. Linting is performed explicitly in a separate workflow and does not need to be run as part of the Python 3.9 tests. Additionally, linting currently expects Python 3.10 and will fail during the Python 3.9 test run. Signed-off-by: Michael Seifert * build: Dependencies for tox's "lint" environent are installed correctly. The lint environment requires mypy from the test dependencies to be installed. Although the environment defines `extras = testing`, it also specifies `skip_install = true`, which also skips installation of test dependencies. This change removes skip_install = true, so that mypy is installed correctly. Signed-off-by: Michael Seifert * build: Removed the explicit interpreter version dependency from tox's "version-info" environment. Signed-off-by: Michael Seifert --- .github/workflows/main.yml | 2 +- tox.ini | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a5ffe577..9036f312 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v3 with: - python-version: '3.9' + python-version: '3.10' - name: Install GitHub matcher for ActionLint checker run: | echo "::add-matcher::.github/actionlint-matcher.json" diff --git a/tox.ini b/tox.ini index 53aca291..00d45222 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,6 @@ [tox] minversion = 3.14.0 envlist = py37, py38, py39, py310, lint, version-info, pytest-min -skip_missing_interpreters = true isolated_build = true passenv = CI @@ -23,7 +22,6 @@ allowlist_externals = make [testenv:lint] -skip_install = true basepython = python3.10 extras = testing deps = @@ -41,7 +39,6 @@ commands = coverage report [testenv:version-info] -basepython = python3.9 deps = packaging == 21.3 commands = @@ -51,6 +48,6 @@ commands = python = 3.7: py37, pytest-min 3.8: py38 - 3.9: py39, lint + 3.9: py39 3.10: py310 pypy3: pypy3 From f979af9c874fbd2fa76cb48e86ab44ebf8823e14 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 15 Mar 2022 07:05:49 +0100 Subject: [PATCH 097/198] Do not try to initialize async fixtures without explicit asyncio mark in strict mode (#307) * test: Package-scoped event_loop fixture no longer leaks into other tests. The expected behaviour is that the `event_loop` fixture defined in `tests/sessionloop/conftest.py` is torn down when all tests in `tests/sessionloop` are complete. Running the tests with the pytest option --setup-show pointed out that the fixture is torn down at the end of the test session, instead. This is an unintended side effect of the sessionloop test which may affect other tests in the test suite. Reducing the fixture scope from "package" to "module" results in the expected behaviour. The module was renamed to reflect the fact that the tests do not use a session scope. Signed-off-by: Michael Seifert * test: Removed test with obsolete "forbid_global_loop". forbid_global_loop was an option to pytest.mark.asyncio which was removed in v0.6.0. The two subprocess tests are otherwise identical. Therefore, one of the tests was removed along with the obsolete option. Signed-off-by: Michael Seifert * test: Ignore subprocess tests when running on CPython 3.7. When run with Python 3.7 asyncio.subprocess.create_subprocess_exec seems to be affected by an issue that prevents correct cleanup. Tests using pytest-trio will report that signal handling is already performed by another library and fail. [1] This is possibly a bug in CPython 3.7, so we ignore this test for that Python version. CPython 3.7 uses asyncio.streams.StreamReader and asyncio.streams.StreamWriter to implement asyncio.streams.StreamReaderProtocol and asyncio.subprocess.SubprocessStreamProtocol. StreamReaderProtocol contained cyclic references between the reader and the protocol, which prevented garbage collection. While StreamReaderProtocol received a patch [2], SubprocessStreamProtocol, which is used by create_subprocess_exec, possibly has the same problem, but was not patched as part of CPython 3.7. That's why we ignore this test for CPython 3.7. [1] https://github.com/python-trio/pytest-trio/issues/126 [2] https://github.com/python/cpython/pull/9201 Signed-off-by: Michael Seifert * build: Added pytest-trio to the test dependencies. This allows testing compatibility between pytest-trio and pytest-asyncio. Signed-off-by: Michael Seifert * fix: Do not try to initialize async fixtures without explicit asyncio mark in strict mode. This fixes a bug that breaks compatibility with pytest_trio. Closes #298 Signed-off-by: Michael Seifert --- CHANGELOG.rst | 5 ++++ pytest_asyncio/plugin.py | 6 ++++- setup.cfg | 1 + .../conftest.py | 6 ++--- .../test_loop_fixture_scope.py} | 4 +-- tests/test_subprocess.py | 23 +++++++++-------- tests/trio/test_fixtures.py | 25 +++++++++++++++++++ 7 files changed, 54 insertions(+), 16 deletions(-) rename tests/{sessionloop => loop_fixture_scope}/conftest.py (64%) rename tests/{sessionloop/test_session_loops.py => loop_fixture_scope/test_loop_fixture_scope.py} (79%) create mode 100644 tests/trio/test_fixtures.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3eac3894..cf19dfb9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog ========= +UNRELEASED +================= +- Adds `pytest-trio `_ to the test dependencies +- Fixes a bug that caused pytest-asyncio to try to set up async pytest_trio fixtures in strict mode. `#298 `_ + 0.18.2 (22-03-03) ================= - Fix asyncio auto mode not marking static methods. `#295 `_ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 187f51da..08001faf 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -210,7 +210,11 @@ def _preprocess_async_fixtures(config: Config, holder: Set[FixtureDef]) -> None: # Nothing to do with a regular fixture function continue if not _has_explicit_asyncio_mark(func): - if asyncio_mode == Mode.AUTO: + if asyncio_mode == Mode.STRICT: + # Ignore async fixtures without explicit asyncio mark in strict mode + # This applies to pytest_trio fixtures, for example + continue + elif asyncio_mode == Mode.AUTO: # Enforce asyncio mode if 'auto' _set_explicit_asyncio_mark(func) elif asyncio_mode == Mode.LEGACY: diff --git a/setup.cfg b/setup.cfg index a28c5fcc..7b684e0f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,7 @@ testing = hypothesis >= 5.7.1 flaky >= 3.5.0 mypy == 0.931 + pytest-trio >= 0.7.0 [options.entry_points] pytest11 = diff --git a/tests/sessionloop/conftest.py b/tests/loop_fixture_scope/conftest.py similarity index 64% rename from tests/sessionloop/conftest.py rename to tests/loop_fixture_scope/conftest.py index bb6c1d6c..223160c2 100644 --- a/tests/sessionloop/conftest.py +++ b/tests/loop_fixture_scope/conftest.py @@ -3,14 +3,14 @@ import pytest -class CustomSelectorLoopSession(asyncio.SelectorEventLoop): +class CustomSelectorLoop(asyncio.SelectorEventLoop): """A subclass with no overrides, just to test for presence.""" -loop = CustomSelectorLoopSession() +loop = CustomSelectorLoop() -@pytest.fixture(scope="package") +@pytest.fixture(scope="module") def event_loop(): """Create an instance of the default event loop for each test case.""" yield loop diff --git a/tests/sessionloop/test_session_loops.py b/tests/loop_fixture_scope/test_loop_fixture_scope.py similarity index 79% rename from tests/sessionloop/test_session_loops.py rename to tests/loop_fixture_scope/test_loop_fixture_scope.py index acb67165..679ab48f 100644 --- a/tests/sessionloop/test_session_loops.py +++ b/tests/loop_fixture_scope/test_loop_fixture_scope.py @@ -1,4 +1,4 @@ -"""Unit tests for overriding the event loop with a session scoped one.""" +"""Unit tests for overriding the event loop with a larger scoped one.""" import asyncio import pytest @@ -8,7 +8,7 @@ async def test_for_custom_loop(): """This test should be executed using the custom loop.""" await asyncio.sleep(0.01) - assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoopSession" + assert type(asyncio.get_event_loop()).__name__ == "CustomSelectorLoop" @pytest.mark.asyncio diff --git a/tests/test_subprocess.py b/tests/test_subprocess.py index 311d67d5..79c5109d 100644 --- a/tests/test_subprocess.py +++ b/tests/test_subprocess.py @@ -15,17 +15,20 @@ def event_loop(): loop.close() -@pytest.mark.asyncio(forbid_global_loop=False) -async def test_subprocess(event_loop): - """Starting a subprocess should be possible.""" - proc = await asyncio.subprocess.create_subprocess_exec( - sys.executable, "--version", stdout=asyncio.subprocess.PIPE - ) - await proc.communicate() +@pytest.mark.skipif( + sys.version_info < (3, 8), + reason=""" + When run with Python 3.7 asyncio.subprocess.create_subprocess_exec seems to be + affected by an issue that prevents correct cleanup. Tests using pytest-trio + will report that signal handling is already performed by another library and + fail. [1] This is possibly a bug in CPython 3.7, so we ignore this test for + that Python version. - -@pytest.mark.asyncio(forbid_global_loop=True) -async def test_subprocess_forbid(event_loop): + [1] https://github.com/python-trio/pytest-trio/issues/126 + """, +) +@pytest.mark.asyncio +async def test_subprocess(event_loop): """Starting a subprocess should be possible.""" proc = await asyncio.subprocess.create_subprocess_exec( sys.executable, "--version", stdout=asyncio.subprocess.PIPE diff --git a/tests/trio/test_fixtures.py b/tests/trio/test_fixtures.py new file mode 100644 index 00000000..42b28437 --- /dev/null +++ b/tests/trio/test_fixtures.py @@ -0,0 +1,25 @@ +from textwrap import dedent + + +def test_strict_mode_ignores_trio_fixtures(testdir): + testdir.makepyfile( + dedent( + """\ + import pytest + import pytest_asyncio + import pytest_trio + + pytest_plugins = ["pytest_asyncio", "pytest_trio"] + + @pytest_trio.trio_fixture + async def any_fixture(): + return True + + @pytest.mark.trio + async def test_anything(any_fixture): + pass + """ + ) + ) + result = testdir.runpytest("--asyncio-mode=strict") + result.assert_outcomes(passed=1) From bcdc04920eb08586145bf0f18e2fe96d242d9a7d Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 25 Mar 2022 10:22:08 +0100 Subject: [PATCH 098/198] docs: Prepare release of v0.18.3. (#313) Signed-off-by: Michael Seifert --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cf19dfb9..bb10c006 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,7 @@ Changelog ========= -UNRELEASED +0.18.3 (22-03-25) ================= - Adds `pytest-trio `_ to the test dependencies - Fixes a bug that caused pytest-asyncio to try to set up async pytest_trio fixtures in strict mode. `#298 `_ From 5a3ca7b7c9eeb9f077446b9bf37f237cc1fbcec1 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 5 Apr 2022 16:13:21 +0200 Subject: [PATCH 099/198] build: Bumped pre-commit-hook-yamlfmt to v0.1.1. (#318) v0.1.1 fixes an incompatibility with setuptools-61.1.0 see https://github.com/jumanjihouse/pre-commit-hook-yamlfmt/issues/29 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf5f9e2c..8c15003b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - markdown - rst - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt - rev: 0.1.0 + rev: 0.1.1 hooks: - id: yamlfmt args: [--mapping, '2', --sequence, '2', --offset, '0'] From a23fb973e8a8fbc428a92c41ae74189c6a70e370 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 5 Apr 2022 16:19:10 +0200 Subject: [PATCH 100/198] Remove setup.py (#315) * build: Remove deprecated setup.py. setup.py is no longer necessary when the project is installed with a PEP 517 compatible build. Pip has support for PEP 517 since v19.0. The setuptools documentation warns about removing setup.py when editable installations need to be possible. This shouldn't be an issue since editable installations are still possible with pip v21.1 or newer. [1] I don't think a bump of the minimal setuptools version is necessary for this change. Closes #283 [1] https://pip.pypa.io/en/stable/news/#v21-1 Signed-off-by: Michael Seifert * docs: Added changelog entry about removal of setup.py. Signed-off-by: Michael Seifert --- CHANGELOG.rst | 4 ++++ setup.py | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 setup.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bb10c006..3e7994bb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +UNRELEASED +================= +- Removes `setup.py` since all relevant configuration is present `setup.cfg`. Users requiring an editable installation of pytest-asyncio need to use pip v21.1 or newer. `#283 `_ + 0.18.3 (22-03-25) ================= - Adds `pytest-trio `_ to the test dependencies diff --git a/setup.py b/setup.py deleted file mode 100644 index 7f1a1763..00000000 --- a/setup.py +++ /dev/null @@ -1,4 +0,0 @@ -from setuptools import setup - -if __name__ == "__main__": - setup() From 31275681268dae2e529d4014fb87ade3773803ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Apr 2022 12:56:15 +0200 Subject: [PATCH 101/198] Bump actions/download-artifact from 2 to 3 (#320) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 2 to 3. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9036f312..6adc3a23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -107,7 +107,7 @@ jobs: with: fetch-depth: 0 - name: Download distributions - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: dist path: dist From 957ff441e09050e5b10211e5ac4d8e883e47641e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Apr 2022 12:56:33 +0200 Subject: [PATCH 102/198] Bump actions/upload-artifact from 2 to 3 (#319) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6adc3a23..a3c01858 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,7 +42,7 @@ jobs: id: version run: tox -e version-info - name: Upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: dist path: dist From 562925390fc28c29ac6c69e8deb9477bae014de5 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Sat, 9 Apr 2022 14:20:46 +0200 Subject: [PATCH 103/198] Pin runtime and test dependencies (#316) * build: Extracted runtime dependencies finto requirements.txt. Signed-off-by: Michael Seifert * build: Removed upper version bound on pytest dependency. Constrained pytest to v7.1.1. Signed-off-by: Michael Seifert * build: Added version constraints for transitive dependencies of the "testing" extra. Signed-off-by: Michael Seifert * build: Added version constraints for dependencies to the "pytest-min" tox environment. Signed-off-by: Michael Seifert * build: Extracted runtime dependencies from pytest-min tox environment into the file pytest-min-requirements.txt. Signed-off-by: Michael Seifert * build: Added missing explicit dependency on typing-extensions to pytest-min-requirements. Signed-off-by: Michael Seifert * ci: Move different sets of constraint and requirement files to different directories. This allows Dependabot to update both dependency sets independently. Signed-off-by: Michael Seifert * build: Removed upper bound on the mypy version installed by the "testing" extra. Adjusted constraints accordingly. Signed-off-by: Michael Seifert * build: Removed upper bound on the coverage version installed by the "testing" extra. Adjusted constraints accordingly. Signed-off-by: Michael Seifert --- .github/dependabot.yml | 10 ++++++++-- dependencies/default/constraints.txt | 24 ++++++++++++++++++++++++ dependencies/default/requirements.txt | 4 ++++ dependencies/pytest-min/constraints.txt | 22 ++++++++++++++++++++++ dependencies/pytest-min/requirements.txt | 4 ++++ setup.cfg | 5 +++-- tox.ini | 6 ++++-- 7 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 dependencies/default/constraints.txt create mode 100644 dependencies/default/requirements.txt create mode 100644 dependencies/pytest-min/constraints.txt create mode 100644 dependencies/pytest-min/requirements.txt diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9179b31d..caab31bf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,9 +2,15 @@ version: 2 updates: - package-ecosystem: pip - directory: / + directory: /dependencies/default schedule: - interval: daily + interval: weekly + open-pull-requests-limit: 10 + target-branch: master +- package-ecosystem: pip + directory: /dependencies/pytest-min + schedule: + interval: weekly open-pull-requests-limit: 10 target-branch: master - package-ecosystem: github-actions diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt new file mode 100644 index 00000000..a9a0844c --- /dev/null +++ b/dependencies/default/constraints.txt @@ -0,0 +1,24 @@ +async-generator==1.10 +attrs==21.4.0 +coverage==6.3.2 +flaky==3.7.0 +hypothesis==6.39.6 +idna==3.3 +importlib-metadata==4.11.3 +iniconfig==1.1.1 +mypy==0.942 +mypy-extensions==0.4.3 +outcome==1.1.0 +packaging==21.3 +pluggy==1.0.0 +py==1.11.0 +pyparsing==3.0.7 +pytest==7.1.1 +pytest-trio==0.7.0 +sniffio==1.2.0 +sortedcontainers==2.4.0 +tomli==2.0.1 +trio==0.20.0 +typed-ast==1.5.2 +typing_extensions==4.1.1 +zipp==3.7.0 diff --git a/dependencies/default/requirements.txt b/dependencies/default/requirements.txt new file mode 100644 index 00000000..01b2484e --- /dev/null +++ b/dependencies/default/requirements.txt @@ -0,0 +1,4 @@ +# Always adjust install_requires in setup.cfg and pytest-min-requirements.txt +# when changing runtime dependencies +pytest >= 6.1.0 +typing-extensions >= 3.7.2; python_version < "3.8" diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt new file mode 100644 index 00000000..e08c0f1b --- /dev/null +++ b/dependencies/pytest-min/constraints.txt @@ -0,0 +1,22 @@ +async-generator==1.10 +attrs==21.4.0 +coverage==6.3.2 +flaky==3.7.0 +hypothesis==6.39.6 +idna==3.3 +iniconfig==1.1.1 +mypy==0.942 +mypy-extensions==0.4.3 +outcome==1.1.0 +packaging==21.3 +pluggy==0.13.1 +py==1.11.0 +pyparsing==3.0.7 +pytest==6.1.0 +pytest-trio==0.7.0 +sniffio==1.2.0 +sortedcontainers==2.4.0 +toml==0.10.2 +tomli==2.0.1 +trio==0.20.0 +typing_extensions==4.1.1 diff --git a/dependencies/pytest-min/requirements.txt b/dependencies/pytest-min/requirements.txt new file mode 100644 index 00000000..4fc6ef2f --- /dev/null +++ b/dependencies/pytest-min/requirements.txt @@ -0,0 +1,4 @@ +# Always adjust install_requires in setup.cfg and requirements.txt +# when changing minimum version dependencies +pytest == 6.1.0 +typing-extensions >= 3.7.2; python_version < "3.8" diff --git a/setup.cfg b/setup.cfg index 7b684e0f..a0e08d97 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,16 +34,17 @@ python_requires = >=3.7 packages = find: include_package_data = True +# Always adjust requirements.txt and pytest-min-requirements.txt when changing runtime dependencies install_requires = pytest >= 6.1.0 typing-extensions >= 3.7.2; python_version < "3.8" [options.extras_require] testing = - coverage==6.2 + coverage >= 6.2 hypothesis >= 5.7.1 flaky >= 3.5.0 - mypy == 0.931 + mypy >= 0.931 pytest-trio >= 0.7.0 [options.entry_points] diff --git a/tox.ini b/tox.ini index 00d45222..83cae521 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,8 @@ passenv = [testenv] extras = testing deps = - pytest == 6.2.5 # required for Python 3.10, not bad for others + --requirement dependencies/default/requirements.txt + --constraint dependencies/default/constraints.txt commands = make test allowlist_externals = make @@ -16,7 +17,8 @@ allowlist_externals = [testenv:pytest-min] extras = testing deps = - pytest == 6.1.0 + --requirement dependencies/pytest-min/requirements.txt + --constraint dependencies/pytest-min/constraints.txt commands = make test allowlist_externals = make From 1a7030c6fa57c4b1c92268ec54f90c65c12ce825 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 21:57:35 +0200 Subject: [PATCH 104/198] Bump zipp from 3.7.0 to 3.8.0 in /dependencies/default (#321) Bumps [zipp](https://github.com/jaraco/zipp) from 3.7.0 to 3.8.0. - [Release notes](https://github.com/jaraco/zipp/releases) - [Changelog](https://github.com/jaraco/zipp/blob/main/CHANGES.rst) - [Commits](https://github.com/jaraco/zipp/compare/v3.7.0...v3.8.0) --- updated-dependencies: - dependency-name: zipp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a9a0844c..11b8e725 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -21,4 +21,4 @@ tomli==2.0.1 trio==0.20.0 typed-ast==1.5.2 typing_extensions==4.1.1 -zipp==3.7.0 +zipp==3.8.0 From 3e4029d5900ee616956739539b14a26203660ed4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 21:58:00 +0200 Subject: [PATCH 105/198] Bump hypothesis from 6.39.6 to 6.42.0 in /dependencies/default (#324) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.39.6 to 6.42.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.39.6...hypothesis-python-6.42.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 11b8e725..5181d741 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.39.6 +hypothesis==6.42.0 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From a1877ec29406c5681812f4c907c23fca75a17bc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 21:58:28 +0200 Subject: [PATCH 106/198] Bump hypothesis from 6.39.6 to 6.42.0 in /dependencies/pytest-min (#322) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.39.6 to 6.42.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.39.6...hypothesis-python-6.42.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index e08c0f1b..7dc590a1 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.39.6 +hypothesis==6.42.0 idna==3.3 iniconfig==1.1.1 mypy==0.942 From 18304bb066380330f10b235cdaded6920e35b161 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 22:04:32 +0200 Subject: [PATCH 107/198] Bump hypothesis from 6.42.0 to 6.42.2 in /dependencies/pytest-min (#326) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.42.0 to 6.42.2. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.42.0...hypothesis-python-6.42.2) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index 7dc590a1..f3c8abf7 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.42.0 +hypothesis==6.42.2 idna==3.3 iniconfig==1.1.1 mypy==0.942 From 42099399e04f323caa8902055fca76b21f1cb6bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 21:58:39 +0200 Subject: [PATCH 108/198] Bump pyparsing from 3.0.7 to 3.0.8 in /dependencies/default (#331) Bumps [pyparsing](https://github.com/pyparsing/pyparsing) from 3.0.7 to 3.0.8. - [Release notes](https://github.com/pyparsing/pyparsing/releases) - [Changelog](https://github.com/pyparsing/pyparsing/blob/master/CHANGES) - [Commits](https://github.com/pyparsing/pyparsing/compare/pyparsing_3.0.7...pyparsing_3.0.8) --- updated-dependencies: - dependency-name: pyparsing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 5181d741..8e531b90 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -12,7 +12,7 @@ outcome==1.1.0 packaging==21.3 pluggy==1.0.0 py==1.11.0 -pyparsing==3.0.7 +pyparsing==3.0.8 pytest==7.1.1 pytest-trio==0.7.0 sniffio==1.2.0 From be6e20fe2d9fc76a970f8bd2fff37af08557f0f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 21:58:53 +0200 Subject: [PATCH 109/198] Bump pyparsing from 3.0.7 to 3.0.8 in /dependencies/pytest-min (#329) Bumps [pyparsing](https://github.com/pyparsing/pyparsing) from 3.0.7 to 3.0.8. - [Release notes](https://github.com/pyparsing/pyparsing/releases) - [Changelog](https://github.com/pyparsing/pyparsing/blob/master/CHANGES) - [Commits](https://github.com/pyparsing/pyparsing/compare/pyparsing_3.0.7...pyparsing_3.0.8) --- updated-dependencies: - dependency-name: pyparsing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index f3c8abf7..18e01b07 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -11,7 +11,7 @@ outcome==1.1.0 packaging==21.3 pluggy==0.13.1 py==1.11.0 -pyparsing==3.0.7 +pyparsing==3.0.8 pytest==6.1.0 pytest-trio==0.7.0 sniffio==1.2.0 From d9b63fafcb1343284309f42c831f4372ca190bfc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 21:59:08 +0200 Subject: [PATCH 110/198] Bump hypothesis from 6.42.0 to 6.42.3 in /dependencies/default (#330) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.42.0 to 6.42.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.42.0...hypothesis-python-6.42.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 8e531b90..a93dc200 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.42.0 +hypothesis==6.42.3 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From 06fa4097dc1445a166ce7169d81239740ef96dea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 21:59:17 +0200 Subject: [PATCH 111/198] Bump hypothesis from 6.42.2 to 6.42.3 in /dependencies/pytest-min (#328) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.42.2 to 6.42.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.42.2...hypothesis-python-6.42.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index 18e01b07..c2041cc4 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.42.2 +hypothesis==6.42.3 idna==3.3 iniconfig==1.1.1 mypy==0.942 From 523ff720a80a8b7042b769279bcfdeeb9085fbcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 15:56:59 +0200 Subject: [PATCH 112/198] Bump typed-ast from 1.5.2 to 1.5.3 in /dependencies/default (#332) Bumps [typed-ast](https://github.com/python/typed_ast) from 1.5.2 to 1.5.3. - [Release notes](https://github.com/python/typed_ast/releases) - [Changelog](https://github.com/python/typed_ast/blob/master/release_process.md) - [Commits](https://github.com/python/typed_ast/compare/1.5.2...1.5.3) --- updated-dependencies: - dependency-name: typed-ast dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a93dc200..1d1eeb57 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -19,6 +19,6 @@ sniffio==1.2.0 sortedcontainers==2.4.0 tomli==2.0.1 trio==0.20.0 -typed-ast==1.5.2 +typed-ast==1.5.3 typing_extensions==4.1.1 zipp==3.8.0 From 12c12229c4dc13d4de76c9ca4c4e379d1835511b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 16:00:13 +0200 Subject: [PATCH 113/198] Bump typing-extensions from 4.1.1 to 4.2.0 in /dependencies/pytest-min (#335) Bumps [typing-extensions](https://github.com/python/typing) from 4.1.1 to 4.2.0. - [Release notes](https://github.com/python/typing/releases) - [Changelog](https://github.com/python/typing/blob/master/typing_extensions/CHANGELOG.md) - [Commits](https://github.com/python/typing/compare/4.1.1...4.2.0) --- updated-dependencies: - dependency-name: typing-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index c2041cc4..fb4be3d2 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -19,4 +19,4 @@ sortedcontainers==2.4.0 toml==0.10.2 tomli==2.0.1 trio==0.20.0 -typing_extensions==4.1.1 +typing_extensions==4.2.0 From 0d7f43601bba1284e7ca94694622ef56cdd1227e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 16:00:35 +0200 Subject: [PATCH 114/198] Bump typing-extensions from 4.1.1 to 4.2.0 in /dependencies/default (#336) Bumps [typing-extensions](https://github.com/python/typing) from 4.1.1 to 4.2.0. - [Release notes](https://github.com/python/typing/releases) - [Changelog](https://github.com/python/typing/blob/master/typing_extensions/CHANGELOG.md) - [Commits](https://github.com/python/typing/compare/4.1.1...4.2.0) --- updated-dependencies: - dependency-name: typing-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 1d1eeb57..fff6d807 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -20,5 +20,5 @@ sortedcontainers==2.4.0 tomli==2.0.1 trio==0.20.0 typed-ast==1.5.3 -typing_extensions==4.1.1 +typing_extensions==4.2.0 zipp==3.8.0 From 81b45c2c768a1967e1fe06517e1c8945924032f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 16:00:55 +0200 Subject: [PATCH 115/198] Bump hypothesis from 6.42.3 to 6.43.3 in /dependencies/default (#334) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.42.3 to 6.43.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.42.3...hypothesis-python-6.43.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index fff6d807..16aaf0b6 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.42.3 +hypothesis==6.43.3 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From a31916df92e32d57bf0fbc85d2bd2812f97dc520 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Apr 2022 16:01:04 +0200 Subject: [PATCH 116/198] Bump hypothesis from 6.42.3 to 6.43.3 in /dependencies/pytest-min (#333) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.42.3 to 6.43.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.42.3...hypothesis-python-6.43.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/pytest-min/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/pytest-min/constraints.txt b/dependencies/pytest-min/constraints.txt index fb4be3d2..33f7948f 100644 --- a/dependencies/pytest-min/constraints.txt +++ b/dependencies/pytest-min/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.42.3 +hypothesis==6.43.3 idna==3.3 iniconfig==1.1.1 mypy==0.942 From e6f2f96700f63543ea9316035db6bc8a04b59397 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 2 May 2022 20:36:18 +0200 Subject: [PATCH 117/198] build: Stop bumping version requirements of pytest-min. There's no need to bump them, since the dependency set is only used for testing against the minimum supported pytest version. Disabling dependabot for the pytest-min dependencies will reduce the pull request noise. Signed-off-by: Michael Seifert --- .github/dependabot.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index caab31bf..28b158af 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,12 +7,6 @@ updates: interval: weekly open-pull-requests-limit: 10 target-branch: master -- package-ecosystem: pip - directory: /dependencies/pytest-min - schedule: - interval: weekly - open-pull-requests-limit: 10 - target-branch: master - package-ecosystem: github-actions directory: / schedule: From 240ab5481082459a3179ea01bb8cb48dde614ed2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 20:38:21 +0200 Subject: [PATCH 118/198] Bump mypy from 0.942 to 0.950 in /dependencies/default (#347) Bumps [mypy](https://github.com/python/mypy) from 0.942 to 0.950. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.942...v0.950) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 16aaf0b6..860d0f23 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -6,7 +6,7 @@ hypothesis==6.43.3 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 -mypy==0.942 +mypy==0.950 mypy-extensions==0.4.3 outcome==1.1.0 packaging==21.3 From 981dda9eb475fad84b1afd0a93f73324393a89e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 20:38:41 +0200 Subject: [PATCH 119/198] Bump hypothesis from 6.43.3 to 6.46.1 in /dependencies/default (#346) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.43.3 to 6.46.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.43.3...hypothesis-python-6.46.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 860d0f23..2cba29c9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.43.3 +hypothesis==6.46.1 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From 8ad296e33622a3171eb0ce60c19ada73740fc7ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 May 2022 20:46:44 +0200 Subject: [PATCH 120/198] Bump pytest from 7.1.1 to 7.1.2 in /dependencies/default (#342) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.1 to 7.1.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.1...7.1.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 2cba29c9..98c222b0 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -13,7 +13,7 @@ packaging==21.3 pluggy==1.0.0 py==1.11.0 pyparsing==3.0.8 -pytest==7.1.1 +pytest==7.1.2 pytest-trio==0.7.0 sniffio==1.2.0 sortedcontainers==2.4.0 From cf4a40c01b6aeb2d361f28adfb29e41d4ec657ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 May 2022 06:25:57 +0200 Subject: [PATCH 121/198] Bump hypothesis from 6.46.1 to 6.46.2 in /dependencies/default (#348) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.1 to 6.46.2. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.1...hypothesis-python-6.46.2) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 98c222b0..19b3a0c5 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.46.1 +hypothesis==6.46.2 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From 7e0c09af1ea850a2e5821abef88deb4dac285a67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 08:53:56 +0300 Subject: [PATCH 122/198] Bump hypothesis from 6.46.2 to 6.46.5 in /dependencies/default (#350) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.2 to 6.46.5. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.2...hypothesis-python-6.46.5) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 19b3a0c5..7a15d15c 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.2 flaky==3.7.0 -hypothesis==6.46.2 +hypothesis==6.46.5 idna==3.3 importlib-metadata==4.11.3 iniconfig==1.1.1 From ffde33bb305e9092937121a7cf4b150e7cf3294e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 08:54:20 +0300 Subject: [PATCH 123/198] Bump coverage from 6.3.2 to 6.3.3 in /dependencies/default (#351) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.3.2 to 6.3.3. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.3.2...6.3.3) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 7a15d15c..296cf248 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==21.4.0 -coverage==6.3.2 +coverage==6.3.3 flaky==3.7.0 hypothesis==6.46.5 idna==3.3 From 728b87e32852b7e58377483e7b988bff20977ac4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 May 2022 08:54:42 +0300 Subject: [PATCH 124/198] Bump pyparsing from 3.0.8 to 3.0.9 in /dependencies/default (#352) Bumps [pyparsing](https://github.com/pyparsing/pyparsing) from 3.0.8 to 3.0.9. - [Release notes](https://github.com/pyparsing/pyparsing/releases) - [Changelog](https://github.com/pyparsing/pyparsing/blob/master/CHANGES) - [Commits](https://github.com/pyparsing/pyparsing/compare/pyparsing_3.0.8...pyparsing_3.0.9) --- updated-dependencies: - dependency-name: pyparsing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 296cf248..c3dfc418 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -12,7 +12,7 @@ outcome==1.1.0 packaging==21.3 pluggy==1.0.0 py==1.11.0 -pyparsing==3.0.8 +pyparsing==3.0.9 pytest==7.1.2 pytest-trio==0.7.0 sniffio==1.2.0 From a45a845076d7644a4166e4c7887fc23c91c8c247 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 11:38:40 +0200 Subject: [PATCH 125/198] Bump typed-ast from 1.5.3 to 1.5.4 in /dependencies/default (#357) Bumps [typed-ast](https://github.com/python/typed_ast) from 1.5.3 to 1.5.4. - [Release notes](https://github.com/python/typed_ast/releases) - [Changelog](https://github.com/python/typed_ast/blob/master/release_process.md) - [Commits](https://github.com/python/typed_ast/compare/1.5.3...1.5.4) --- updated-dependencies: - dependency-name: typed-ast dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index c3dfc418..1f399d36 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -19,6 +19,6 @@ sniffio==1.2.0 sortedcontainers==2.4.0 tomli==2.0.1 trio==0.20.0 -typed-ast==1.5.3 +typed-ast==1.5.4 typing_extensions==4.2.0 zipp==3.8.0 From 8b5ce53cd1d8ed2b7d600dad6ec9c190bd6d9c55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 11:41:47 +0200 Subject: [PATCH 126/198] Bump importlib-metadata from 4.11.3 to 4.11.4 in /dependencies/default (#356) Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 4.11.3 to 4.11.4. - [Release notes](https://github.com/python/importlib_metadata/releases) - [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst) - [Commits](https://github.com/python/importlib_metadata/compare/v4.11.3...v4.11.4) --- updated-dependencies: - dependency-name: importlib-metadata dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 1f399d36..420c0387 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -4,7 +4,7 @@ coverage==6.3.3 flaky==3.7.0 hypothesis==6.46.5 idna==3.3 -importlib-metadata==4.11.3 +importlib-metadata==4.11.4 iniconfig==1.1.1 mypy==0.950 mypy-extensions==0.4.3 From 83c56c998793a18524af6e9a17b30ae1e8bdaee5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 11:41:58 +0200 Subject: [PATCH 127/198] Bump hypothesis from 6.46.5 to 6.46.7 in /dependencies/default (#355) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.5 to 6.46.7. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.5...hypothesis-python-6.46.7) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 420c0387..564bf9d9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.3.3 flaky==3.7.0 -hypothesis==6.46.5 +hypothesis==6.46.7 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From eb5d705315820346784128001b1ef5e6f9915b6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 May 2022 11:42:22 +0200 Subject: [PATCH 128/198] Bump coverage from 6.3.3 to 6.4 in /dependencies/default (#354) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.3.3 to 6.4. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.3.3...6.4) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 564bf9d9..cc910768 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==21.4.0 -coverage==6.3.3 +coverage==6.4 flaky==3.7.0 hypothesis==6.46.7 idna==3.3 From 4922298ed5a61d77b526b35fd9d5838bf1752aa4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jun 2022 08:45:33 +0200 Subject: [PATCH 129/198] Bump hypothesis from 6.46.7 to 6.46.9 in /dependencies/default (#360) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.7 to 6.46.9. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.7...hypothesis-python-6.46.9) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index cc910768..a86d49bf 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4 flaky==3.7.0 -hypothesis==6.46.7 +hypothesis==6.46.9 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From 7e2f0cffb5382772b7b26eca840fb161df9c47bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jun 2022 08:45:41 +0200 Subject: [PATCH 130/198] Bump mypy from 0.950 to 0.960 in /dependencies/default (#361) Bumps [mypy](https://github.com/python/mypy) from 0.950 to 0.960. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.950...v0.960) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a86d49bf..c115c9fd 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -6,7 +6,7 @@ hypothesis==6.46.9 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 -mypy==0.950 +mypy==0.960 mypy-extensions==0.4.3 outcome==1.1.0 packaging==21.3 From 394fd54a4abaeb292fd0ac52a3348bbd69fc6df0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 20:08:21 +0100 Subject: [PATCH 131/198] Bump mypy from 0.960 to 0.961 in /dependencies/default (#362) Bumps [mypy](https://github.com/python/mypy) from 0.960 to 0.961. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.960...v0.961) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index c115c9fd..5801d5d9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -6,7 +6,7 @@ hypothesis==6.46.9 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 -mypy==0.960 +mypy==0.961 mypy-extensions==0.4.3 outcome==1.1.0 packaging==21.3 From c060bbd10214afc34eae7394cf00866400d3a58b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 20:08:45 +0100 Subject: [PATCH 132/198] Bump hypothesis from 6.46.9 to 6.46.11 in /dependencies/default (#363) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.9 to 6.46.11. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.9...hypothesis-python-6.46.11) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 5801d5d9..ee08f281 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4 flaky==3.7.0 -hypothesis==6.46.9 +hypothesis==6.46.11 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From 090e80b05272cb50af31b49b4d52e9f2d69a6e59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jun 2022 20:09:07 +0100 Subject: [PATCH 133/198] Bump coverage from 6.4 to 6.4.1 in /dependencies/default (#364) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.4 to 6.4.1. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.4...6.4.1) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index ee08f281..849731f5 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==21.4.0 -coverage==6.4 +coverage==6.4.1 flaky==3.7.0 hypothesis==6.46.11 idna==3.3 From c02193236e7da328dfbe06b4e9da14e48de6837b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Jun 2022 09:06:49 +0100 Subject: [PATCH 134/198] Bump hypothesis from 6.46.11 to 6.47.0 in /dependencies/default (#366) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.46.11 to 6.47.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.46.11...hypothesis-python-6.47.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 849731f5..9d5d84bc 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.46.11 +hypothesis==6.47.0 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From b098d4e51aa5cb19c4105ba3b88c4054802c299e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 21:11:48 +0100 Subject: [PATCH 135/198] Bump hypothesis from 6.47.0 to 6.47.2 in /dependencies/default (#367) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.47.0 to 6.47.2. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.47.0...hypothesis-python-6.47.2) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 9d5d84bc..a0616f02 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.47.0 +hypothesis==6.47.2 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From 6c3d433eede395588fe90c594d73bbeaaabf9224 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Jun 2022 21:14:04 +0100 Subject: [PATCH 136/198] Bump trio from 0.20.0 to 0.21.0 in /dependencies/default (#368) Bumps [trio](https://github.com/python-trio/trio) from 0.20.0 to 0.21.0. - [Release notes](https://github.com/python-trio/trio/releases) - [Commits](https://github.com/python-trio/trio/compare/v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: trio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a0616f02..b4f4a2fd 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -18,7 +18,7 @@ pytest-trio==0.7.0 sniffio==1.2.0 sortedcontainers==2.4.0 tomli==2.0.1 -trio==0.20.0 +trio==0.21.0 typed-ast==1.5.4 typing_extensions==4.2.0 zipp==3.8.0 From 15e09be47af477c87d1e769740b6e193a3a51090 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jun 2022 15:28:09 +0200 Subject: [PATCH 137/198] Bump actions/setup-python from 3 to 4 (#365) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a3c01858..7bc25b08 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: '3.10' - name: Install GitHub matcher for ActionLint checker @@ -61,7 +61,7 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies From fcc0b8b8d7589038d5decc6904dbd4e894bf7548 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 13:22:02 +0200 Subject: [PATCH 138/198] Bump outcome from 1.1.0 to 1.2.0 in /dependencies/default (#372) Bumps [outcome](https://github.com/python-trio/outcome) from 1.1.0 to 1.2.0. - [Release notes](https://github.com/python-trio/outcome/releases) - [Commits](https://github.com/python-trio/outcome/compare/v1.1.0...v1.2.0) --- updated-dependencies: - dependency-name: outcome dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index b4f4a2fd..dbd208ee 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -8,7 +8,7 @@ importlib-metadata==4.11.4 iniconfig==1.1.1 mypy==0.961 mypy-extensions==0.4.3 -outcome==1.1.0 +outcome==1.2.0 packaging==21.3 pluggy==1.0.0 py==1.11.0 From 860ff5113c3e73ade396c632c822a171a81e5b78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 13:22:14 +0200 Subject: [PATCH 139/198] Bump hypothesis from 6.47.2 to 6.47.3 in /dependencies/default (#373) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.47.2 to 6.47.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.47.2...hypothesis-python-6.47.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index dbd208ee..35bc12b3 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.47.2 +hypothesis==6.47.3 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From b463f72675cb680f5982013459b910ce3797a015 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Sun, 26 Jun 2022 10:21:44 +0200 Subject: [PATCH 140/198] Python 3.11 support (#370) * build: Run tests on Python 3.11. Signed-off-by: Michael Seifert * feat: Add official support for Python 3.11. Signed-off-by: Michael Seifert --- .github/workflows/main.yml | 4 ++-- CHANGELOG.rst | 1 + setup.cfg | 1 + tox.ini | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7bc25b08..70363f39 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,11 +51,11 @@ jobs: name: Python ${{ matrix.python-version }} runs-on: ubuntu-latest env: - USING_COVERAGE: 3.7,3.8,3.9,3.10 + USING_COVERAGE: 3.7,3.8,3.9,3.10,3.11 strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.7', '3.8', '3.9', '3.10', 3.11-dev] steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3e7994bb..ff7e29b4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,7 @@ Changelog UNRELEASED ================= - Removes `setup.py` since all relevant configuration is present `setup.cfg`. Users requiring an editable installation of pytest-asyncio need to use pip v21.1 or newer. `#283 `_ +- Add support for Python 3.11. 0.18.3 (22-03-25) ================= diff --git a/setup.cfg b/setup.cfg index a0e08d97..b1f1e82d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,6 +22,7 @@ classifiers = Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Topic :: Software Development :: Testing diff --git a/tox.ini b/tox.ini index 83cae521..1d8994ae 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.14.0 -envlist = py37, py38, py39, py310, lint, version-info, pytest-min +envlist = py37, py38, py39, py310, py311, lint, version-info, pytest-min isolated_build = true passenv = CI @@ -52,4 +52,5 @@ python = 3.8: py38 3.9: py39 3.10: py310 + 3.11-dev: py311 pypy3: pypy3 From f13c85f0f70e2e26b583bc5278876ff3229ad10c Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Sun, 26 Jun 2022 11:34:47 +0200 Subject: [PATCH 141/198] docs: Fix typo in README. Signed-off-by: Michael Seifert --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 93b369b7..17a10f67 100644 --- a/README.rst +++ b/README.rst @@ -251,7 +251,7 @@ Note about unittest ------------------- Test classes subclassing the standard `unittest `__ library are not supported, users -are recommended to use `unitest.IsolatedAsyncioTestCase `__ +are recommended to use `unittest.IsolatedAsyncioTestCase `__ or an async framework such as `asynctest `__. Contributing From 4cf16cf984ee8cb4a290a8d4852db12f615368f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 05:45:10 +0200 Subject: [PATCH 142/198] Bump hypothesis from 6.47.3 to 6.48.0 in /dependencies/default (#377) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.47.3 to 6.48.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.47.3...hypothesis-python-6.48.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 35bc12b3..b763832a 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.47.3 +hypothesis==6.48.0 idna==3.3 importlib-metadata==4.11.4 iniconfig==1.1.1 From db72f254b47b2b123cd0ba8892d6c89a481fee96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jun 2022 05:45:27 +0200 Subject: [PATCH 143/198] Bump importlib-metadata from 4.11.4 to 4.12.0 in /dependencies/default (#378) Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 4.11.4 to 4.12.0. - [Release notes](https://github.com/python/importlib_metadata/releases) - [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst) - [Commits](https://github.com/python/importlib_metadata/compare/v4.11.4...v4.12.0) --- updated-dependencies: - dependency-name: importlib-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index b763832a..930336af 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -4,7 +4,7 @@ coverage==6.4.1 flaky==3.7.0 hypothesis==6.48.0 idna==3.3 -importlib-metadata==4.11.4 +importlib-metadata==4.12.0 iniconfig==1.1.1 mypy==0.961 mypy-extensions==0.4.3 From 739198bd62dd89c4d3bab4821d275883272ad2d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 06:26:24 +0200 Subject: [PATCH 144/198] Bump hypothesis from 6.48.0 to 6.48.3 in /dependencies/default (#381) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.48.0 to 6.48.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.48.0...hypothesis-python-6.48.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 930336af..af4b23a6 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.48.0 +hypothesis==6.48.3 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From 49f07a46fcc876decbb6c0fd431ef52172c5654c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 06:26:58 +0200 Subject: [PATCH 145/198] Bump typing-extensions from 4.2.0 to 4.3.0 in /dependencies/default (#382) Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.2.0 to 4.3.0. - [Release notes](https://github.com/python/typing_extensions/releases) - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.2.0...4.3.0) --- updated-dependencies: - dependency-name: typing-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index af4b23a6..cd99339f 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -20,5 +20,5 @@ sortedcontainers==2.4.0 tomli==2.0.1 trio==0.21.0 typed-ast==1.5.4 -typing_extensions==4.2.0 +typing_extensions==4.3.0 zipp==3.8.0 From 25c54a541707d7e4f3f4098c5d28a9534380180e Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 5 Jul 2022 06:27:25 +0200 Subject: [PATCH 146/198] Clarify documentation of event_loop fixture (#375) * docs: Removed contradicting information about the event_loop fixture not setting the global event loop. Signed-off-by: Michael Seifert * docs: Clarified the effect of pytest.mark.asyncio with regards to the event_loop fixture. Signed-off-by: Michael Seifert * docs: Provide an example for redefining the event_loop fixture rather than for setting a custom event loop. Signed-off-by: Michael Seifert --- README.rst | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 17a10f67..12c76eb0 100644 --- a/README.rst +++ b/README.rst @@ -123,19 +123,16 @@ Fixtures ``event_loop`` ~~~~~~~~~~~~~~ -Creates and injects a new instance of the default asyncio event loop. By -default, the loop will be closed at the end of the test (i.e. the default -fixture scope is ``function``). +Creates a new asyncio event loop based on the current event loop policy. The new loop +is available as the return value of this fixture or via `asyncio.get_running_loop `__. +The event loop is closed when the fixture scope ends. The fixture scope defaults +to ``function`` scope. 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. -Simply using this fixture will not set the generated event loop as the -default asyncio event loop, or change the asyncio event loop policy in any way. -Use ``pytest.mark.asyncio`` for this purpose. - .. code-block:: python def test_http_client(event_loop): @@ -143,22 +140,23 @@ Use ``pytest.mark.asyncio`` for this purpose. 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. +The ``event_loop`` fixture can be overridden in any of the standard pytest locations, +e.g. directly in the test file, or in ``conftest.py``. This allows redefining the +fixture scope, for example: .. code-block:: python - @pytest.fixture + @pytest.fixture(scope="session") def event_loop(): - loop = MyCustomLoop() + policy = asyncio.get_event_loop_policy() + loop = policy.new_event_loop() yield loop loop.close() -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. +If you need to change the type of the event loop, prefer setting a custom event loop policy over redefining the ``event_loop`` fixture. + +If the ``pytest.mark.asyncio`` marker is applied to a test function, the ``event_loop`` +fixture will be requested automatically by the test function. ``unused_tcp_port`` ~~~~~~~~~~~~~~~~~~~ From 07beb804a9c934862e0770bf51beb30b7e5a4230 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 12 Jul 2022 21:50:02 +0100 Subject: [PATCH 147/198] opt into strict mode by default (#380) * opt into strict mode by default * docs: Update CHANGELOG.rst Clarify that no code changes were necessary for Python 3.11 support. Co-authored-by: Thomas Grainger Co-authored-by: Michael Seifert --- CHANGELOG.rst | 3 ++- README.rst | 11 ++++++----- pytest_asyncio/plugin.py | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ff7e29b4..92c5752a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,8 +4,9 @@ Changelog UNRELEASED ================= +- BREAKING: The default ``asyncio_mode`` is now *strict*. `#293 `_ - Removes `setup.py` since all relevant configuration is present `setup.cfg`. Users requiring an editable installation of pytest-asyncio need to use pip v21.1 or newer. `#283 `_ -- Add support for Python 3.11. +- Declare support for Python 3.11. 0.18.3 (22-03-25) ================= diff --git a/README.rst b/README.rst index 12c76eb0..1fc5ef47 100644 --- a/README.rst +++ b/README.rst @@ -58,7 +58,7 @@ Modes ----- Starting from ``pytest-asyncio>=0.17``, three modes are provided: *auto*, *strict* and -*legacy* (default). +*legacy*. Starting from ``pytest-asyncio>=0.19`` the *strict* mode is the default. The mode can be set by ``asyncio_mode`` configuration option in `configuration file `_: @@ -104,6 +104,8 @@ pytest plugin can handle them. Please use this mode if multiple async frameworks should be combined in the same test suite. +This mode is used by default for the sake of project inter-compatibility. + Legacy mode ~~~~~~~~~~~ @@ -111,11 +113,10 @@ Legacy mode This mode follows rules used by ``pytest-asyncio<0.17``: tests are not auto-marked but fixtures are. -This mode is used by default for the sake of backward compatibility, deprecation -warnings are emitted with suggestion to either switching to ``auto`` mode or using -``strict`` mode with ``@pytest_asyncio.fixture`` decorators. +Deprecation warnings are emitted with suggestion to either switching to ``auto`` mode +or using ``strict`` mode with ``@pytest_asyncio.fixture`` decorators. -In future, the default will be changed. +The default was changed to ``strict`` in ``pytest-asyncio>=0.19``. Fixtures diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 08001faf..dd6a782b 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -95,7 +95,7 @@ def pytest_addoption(parser: Parser, pluginmanager: PytestPluginManager) -> None parser.addini( "asyncio_mode", help="default value for --asyncio-mode", - default="legacy", + default="strict", ) From 2da33c4feb4a7523f19dd791a6b0ee6200bf14d8 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 15 Jul 2022 09:00:30 +0100 Subject: [PATCH 148/198] docs: Prepare v0.19.0 release. (#385) Signed-off-by: Michael Seifert --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 92c5752a..8de226c4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,7 @@ Changelog ========= -UNRELEASED +0.19.0 (22-07-13) ================= - BREAKING: The default ``asyncio_mode`` is now *strict*. `#293 `_ - Removes `setup.py` since all relevant configuration is present `setup.cfg`. Users requiring an editable installation of pytest-asyncio need to use pip v21.1 or newer. `#283 `_ From 8683fdac717618355dcd60f25184d7ba77c575a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Jul 2022 12:19:18 +0200 Subject: [PATCH 149/198] Build(deps): Bump hypothesis in /dependencies/default (#384) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.48.3 to 6.50.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.48.3...hypothesis-python-6.50.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index cd99339f..11e52939 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.1 flaky==3.7.0 -hypothesis==6.48.3 +hypothesis==6.50.1 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From a89f7fafe11ee77a755c7957d548b8b34668394f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:00:01 +0200 Subject: [PATCH 150/198] Build(deps): Bump coverage from 6.4.1 to 6.4.2 in /dependencies/default (#387) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.4.1 to 6.4.2. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.4.1...6.4.2) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 11e52939..4e717bda 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==21.4.0 -coverage==6.4.1 +coverage==6.4.2 flaky==3.7.0 hypothesis==6.50.1 idna==3.3 From 373ecba6807f1e5da57e1c6882a44eccfa52ed00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:00:44 +0200 Subject: [PATCH 151/198] Build(deps): Bump zipp from 3.8.0 to 3.8.1 in /dependencies/default (#389) Bumps [zipp](https://github.com/jaraco/zipp) from 3.8.0 to 3.8.1. - [Release notes](https://github.com/jaraco/zipp/releases) - [Changelog](https://github.com/jaraco/zipp/blob/main/CHANGES.rst) - [Commits](https://github.com/jaraco/zipp/compare/v3.8.0...v3.8.1) --- updated-dependencies: - dependency-name: zipp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 4e717bda..d4fe7b58 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -21,4 +21,4 @@ tomli==2.0.1 trio==0.21.0 typed-ast==1.5.4 typing_extensions==4.3.0 -zipp==3.8.0 +zipp==3.8.1 From a7489b46551632aee9179fe3fcbfd51e1c64f14e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Jul 2022 19:03:50 +0000 Subject: [PATCH 152/198] Build(deps): Bump hypothesis in /dependencies/default (#388) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.50.1 to 6.52.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.50.1...hypothesis-python-6.52.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index d4fe7b58..e83c0fc6 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.2 flaky==3.7.0 -hypothesis==6.50.1 +hypothesis==6.52.1 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From 378f479f20f2072caa895707c985f91e723398aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jul 2022 07:20:52 +0300 Subject: [PATCH 153/198] Build(deps): Bump pypa/gh-action-pypi-publish from 1.5.0 to 1.5.1 (#393) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.5.0...v1.5.1) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 70363f39..5c5876b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -118,7 +118,7 @@ jobs: run: | pandoc -s -o README.md README.rst - name: PyPI upload - uses: pypa/gh-action-pypi-publish@v1.5.0 + uses: pypa/gh-action-pypi-publish@v1.5.1 with: packages_dir: dist password: ${{ secrets.PYPI_API_TOKEN }} From 574eb0e3eeba4a22697e1de3325b5644c0cfd08a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jul 2022 07:21:56 +0300 Subject: [PATCH 154/198] Build(deps): Bump hypothesis in /dependencies/default (#392) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.52.1 to 6.53.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.52.1...hypothesis-python-6.53.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index e83c0fc6..ccc55c8c 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.2 flaky==3.7.0 -hypothesis==6.52.1 +hypothesis==6.53.0 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From 5ac3c746625f11efe32365317f0a8f24e8788a5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Jul 2022 07:22:18 +0300 Subject: [PATCH 155/198] Build(deps): Bump mypy from 0.961 to 0.971 in /dependencies/default (#391) Bumps [mypy](https://github.com/python/mypy) from 0.961 to 0.971. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.961...v0.971) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index ccc55c8c..2cbfa011 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -6,7 +6,7 @@ hypothesis==6.53.0 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 -mypy==0.961 +mypy==0.971 mypy-extensions==0.4.3 outcome==1.2.0 packaging==21.3 From b03100cf28037ce09ca19183f52dce976254d4ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 21:42:33 +0200 Subject: [PATCH 156/198] Build(deps): Bump coverage from 6.4.2 to 6.4.3 in /dependencies/default (#397) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.4.2 to 6.4.3. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.4.2...6.4.3) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 2cbfa011..33d06bf9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==21.4.0 -coverage==6.4.2 +coverage==6.4.3 flaky==3.7.0 hypothesis==6.53.0 idna==3.3 From 5131a1c198c880f118f2278c257d1668b1f3e857 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 21:43:17 +0200 Subject: [PATCH 157/198] Build(deps): Bump hypothesis in /dependencies/default (#396) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.53.0 to 6.54.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.53.0...hypothesis-python-6.54.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 33d06bf9..143cab9e 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==21.4.0 coverage==6.4.3 flaky==3.7.0 -hypothesis==6.53.0 +hypothesis==6.54.1 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From a1972bb6db30866fb97e63300fd9023d5125c423 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 21:54:25 +0200 Subject: [PATCH 158/198] Build(deps): Bump attrs from 21.4.0 to 22.1.0 in /dependencies/default (#395) Bumps [attrs](https://github.com/python-attrs/attrs) from 21.4.0 to 22.1.0. - [Release notes](https://github.com/python-attrs/attrs/releases) - [Changelog](https://github.com/python-attrs/attrs/blob/main/CHANGELOG.rst) - [Commits](https://github.com/python-attrs/attrs/compare/21.4.0...22.1.0) --- updated-dependencies: - dependency-name: attrs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 143cab9e..60b326e8 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,5 +1,5 @@ async-generator==1.10 -attrs==21.4.0 +attrs==22.1.0 coverage==6.4.3 flaky==3.7.0 hypothesis==6.54.1 From 02aab01134dec379432113aa0239b1b91d3fe3c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 19:04:13 +0200 Subject: [PATCH 159/198] Build(deps): Bump coverage from 6.4.3 to 6.4.4 in /dependencies/default (#401) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.4.3 to 6.4.4. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.4.3...6.4.4) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 60b326e8..36839c5c 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==22.1.0 -coverage==6.4.3 +coverage==6.4.4 flaky==3.7.0 hypothesis==6.54.1 idna==3.3 From 9675b597c508ebeb8945bf29d9f5e6a07fc710dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 19:09:31 +0200 Subject: [PATCH 160/198] Build(deps): Bump hypothesis in /dependencies/default (#400) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.54.1 to 6.54.4. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.54.1...hypothesis-python-6.54.4) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 36839c5c..80615b25 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.4.4 flaky==3.7.0 -hypothesis==6.54.1 +hypothesis==6.54.4 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From 993c5103d118202fb6fe8b635dbda0accd4738eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 18:29:07 +0200 Subject: [PATCH 161/198] Build(deps): Bump sniffio from 1.2.0 to 1.3.0 in /dependencies/default (#405) Bumps [sniffio](https://github.com/python-trio/sniffio) from 1.2.0 to 1.3.0. - [Release notes](https://github.com/python-trio/sniffio/releases) - [Commits](https://github.com/python-trio/sniffio/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: sniffio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 80615b25..bdbe98c7 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -15,7 +15,7 @@ py==1.11.0 pyparsing==3.0.9 pytest==7.1.2 pytest-trio==0.7.0 -sniffio==1.2.0 +sniffio==1.3.0 sortedcontainers==2.4.0 tomli==2.0.1 trio==0.21.0 From 7b052675b05e8f1f375f4c8aa94b753a2c6ddf7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 18:30:37 +0200 Subject: [PATCH 162/198] Build(deps): Bump hypothesis in /dependencies/default (#407) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.54.4 to 6.54.5. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.54.4...hypothesis-python-6.54.5) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index bdbe98c7..a6ffef5f 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.4.4 flaky==3.7.0 -hypothesis==6.54.4 +hypothesis==6.54.5 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From e953cd8bada7981ede7cf56e42be7b9faf30cbea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:32:41 +0000 Subject: [PATCH 163/198] Build(deps): Bump pytest from 7.1.2 to 7.1.3 in /dependencies/default (#406) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.2 to 7.1.3. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.2...7.1.3) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a6ffef5f..5e2720f9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -13,7 +13,7 @@ packaging==21.3 pluggy==1.0.0 py==1.11.0 pyparsing==3.0.9 -pytest==7.1.2 +pytest==7.1.3 pytest-trio==0.7.0 sniffio==1.3.0 sortedcontainers==2.4.0 From 5697df211f702e3b283effecb7a8d5863f528ebc Mon Sep 17 00:00:00 2001 From: DanCardin Date: Mon, 12 Sep 2022 15:55:19 -0400 Subject: [PATCH 164/198] Perform `in` check against cached fixturedefs (#404) _preprocess_async_fixtures previously checked whether a fixturedef was identical to the fixture cache. This can never be the case. The intent of the if-clause was likely to prevent duplicate evaluation of fixtures. This patch changes the if-statement to check whether the fixturedef is contained in the cache. --- CHANGELOG.rst | 4 ++++ pytest_asyncio/plugin.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8de226c4..0b0f2205 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +UNRELEASED +================= +- Fixed an issue which prevented fixture setup from being cached. `#404 `_ + 0.19.0 (22-07-13) ================= - BREAKING: The default ``asyncio_mode`` is now *strict*. `#293 `_ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index dd6a782b..ce172f5f 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -203,7 +203,7 @@ def _preprocess_async_fixtures(config: Config, holder: Set[FixtureDef]) -> None: fixturemanager = config.pluginmanager.get_plugin("funcmanage") for fixtures in fixturemanager._arg2fixturedefs.values(): for fixturedef in fixtures: - if fixturedef is holder: + if fixturedef in holder: continue func = fixturedef.func if not _is_coroutine_or_asyncgen(func): From a86ed2cd461da2d6acadfdd5bb18e7ddcc33535d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:12:37 +0200 Subject: [PATCH 165/198] Build(deps): Bump hypothesis in /dependencies/default (#410) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.54.5 to 6.54.6. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.54.5...hypothesis-python-6.54.6) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 5e2720f9..bf6a822e 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.4.4 flaky==3.7.0 -hypothesis==6.54.5 +hypothesis==6.54.6 idna==3.3 importlib-metadata==4.12.0 iniconfig==1.1.1 From 2d8f69dd9d2c2cf5de50584d238aa6e7a1933524 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:15:55 +0200 Subject: [PATCH 166/198] Build(deps): Bump idna from 3.3 to 3.4 in /dependencies/default (#411) Bumps [idna](https://github.com/kjd/idna) from 3.3 to 3.4. - [Release notes](https://github.com/kjd/idna/releases) - [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst) - [Commits](https://github.com/kjd/idna/compare/v3.3...v3.4) --- updated-dependencies: - dependency-name: idna dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index bf6a822e..8f2dbe79 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -3,7 +3,7 @@ attrs==22.1.0 coverage==6.4.4 flaky==3.7.0 hypothesis==6.54.6 -idna==3.3 +idna==3.4 importlib-metadata==4.12.0 iniconfig==1.1.1 mypy==0.971 From 3d05e999021f879ef40de986775b91ae106c5d4c Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 4 Oct 2022 07:33:02 +0200 Subject: [PATCH 167/198] feat!: Remove legacy mode. (#414) Asyncio modes have been introduced in v0.17.0 which was released on 2022-01-13. In addition to the auto and strict modes, the release defaulted to "legacy" mode for backwards compatibility. The release also issued a deprecation warning when using legacy mode. The default asyncio mode was changed to _strict_ in the v0.19.0 release on 2022-07-13. This change removes legacy mode entirely. Signed-off-by: Michael Seifert --- CHANGELOG.rst | 1 + README.rst | 17 +---- pytest_asyncio/plugin.py | 35 ---------- tests/modes/test_legacy_mode.py | 112 -------------------------------- tests/test_asyncio_fixture.py | 2 +- 5 files changed, 4 insertions(+), 163 deletions(-) delete mode 100644 tests/modes/test_legacy_mode.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0b0f2205..5ceab47f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ Changelog UNRELEASED ================= +- BREAKING: Removed *legacy* mode. If you're upgrading from v0.19 and you haven't configured ``asyncio_mode = legacy``, you can upgrade without taking any additional action. If you're upgrading from an earlier version or you have explicitly enabled *legacy* mode, you need to switch to *auto* or *strict* mode before upgrading to this version. - Fixed an issue which prevented fixture setup from being cached. `#404 `_ 0.19.0 (22-07-13) diff --git a/README.rst b/README.rst index 1fc5ef47..d62087bb 100644 --- a/README.rst +++ b/README.rst @@ -57,8 +57,7 @@ This is enough for pytest to pick up pytest-asyncio. Modes ----- -Starting from ``pytest-asyncio>=0.17``, three modes are provided: *auto*, *strict* and -*legacy*. Starting from ``pytest-asyncio>=0.19`` the *strict* mode is the default. +Pytest-asyncio provides two modes: *auto* and *strict* with *strict* mode being the default. The mode can be set by ``asyncio_mode`` configuration option in `configuration file `_: @@ -107,18 +106,6 @@ suite. This mode is used by default for the sake of project inter-compatibility. -Legacy mode -~~~~~~~~~~~ - -This mode follows rules used by ``pytest-asyncio<0.17``: tests are not auto-marked but -fixtures are. - -Deprecation warnings are emitted with suggestion to either switching to ``auto`` mode -or using ``strict`` mode with ``@pytest_asyncio.fixture`` decorators. - -The default was changed to ``strict`` in ``pytest-asyncio>=0.19``. - - Fixtures -------- @@ -204,7 +191,7 @@ to redefine the ``event_loop`` fixture to have the same or broader scope. Async fixtures need the event loop, and so must have the same or narrower scope than the ``event_loop`` fixture. -*auto* and *legacy* mode automatically converts async fixtures declared with the +*auto* mode automatically converts async fixtures declared with the standard ``@pytest.fixture`` decorator to *asyncio-driven* versions. diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index ce172f5f..6fd300d5 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -6,7 +6,6 @@ import inspect import socket import sys -import warnings from typing import ( Any, AsyncIterator, @@ -55,22 +54,6 @@ class Mode(str, enum.Enum): AUTO = "auto" STRICT = "strict" - LEGACY = "legacy" - - -LEGACY_MODE = DeprecationWarning( - "The 'asyncio_mode' default value will change to 'strict' in future, " - "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " - "in pytest configuration file." -) - -LEGACY_ASYNCIO_FIXTURE = ( - "'@pytest.fixture' is applied to {name} " - "in 'legacy' mode, " - "please replace it with '@pytest_asyncio.fixture' as a preparation " - "for switching to 'strict' mode (or use 'auto' mode to seamlessly handle " - "all these fixtures as asyncio-driven)." -) ASYNCIO_MODE_HELP = """\ @@ -78,8 +61,6 @@ class Mode(str, enum.Enum): 'strict' - for autoprocessing disabling (useful if different async frameworks \ should be tested together, e.g. \ both pytest-asyncio and pytest-trio are used in the same project) -'legacy' - for keeping compatibility with pytest-asyncio<0.17: \ -auto-handling is disabled but pytest_asyncio.fixture usage is not enforced """ @@ -187,8 +168,6 @@ def pytest_configure(config: Config) -> None: "mark the test as a coroutine, it will be " "run using an asyncio event loop", ) - if _get_asyncio_mode(config) == Mode.LEGACY: - config.issue_config_time_warning(LEGACY_MODE, stacklevel=2) @pytest.mark.tryfirst @@ -217,20 +196,6 @@ def _preprocess_async_fixtures(config: Config, holder: Set[FixtureDef]) -> None: elif asyncio_mode == Mode.AUTO: # Enforce asyncio mode if 'auto' _set_explicit_asyncio_mark(func) - elif asyncio_mode == Mode.LEGACY: - _set_explicit_asyncio_mark(func) - try: - code = func.__code__ - except AttributeError: - code = func.__func__.__code__ - name = ( - f"" - ) - warnings.warn( - LEGACY_ASYNCIO_FIXTURE.format(name=name), - DeprecationWarning, - ) to_add = [] for name in ("request", "event_loop"): diff --git a/tests/modes/test_legacy_mode.py b/tests/modes/test_legacy_mode.py deleted file mode 100644 index 12d4afe1..00000000 --- a/tests/modes/test_legacy_mode.py +++ /dev/null @@ -1,112 +0,0 @@ -from textwrap import dedent - -LEGACY_MODE = ( - "The 'asyncio_mode' default value will change to 'strict' in future, " - "please explicitly use 'asyncio_mode=strict' or 'asyncio_mode=auto' " - "in pytest configuration file." -) - -LEGACY_ASYNCIO_FIXTURE = ( - "'@pytest.fixture' is applied to {name} " - "in 'legacy' mode, " - "please replace it with '@pytest_asyncio.fixture' as a preparation " - "for switching to 'strict' mode (or use 'auto' mode to seamlessly handle " - "all these fixtures as asyncio-driven)." -).format(name="*") - - -def test_warning_for_legacy_mode_cmdline(testdir): - testdir.makepyfile( - dedent( - """\ - import asyncio - import pytest - - pytest_plugins = 'pytest_asyncio' - - @pytest.mark.asyncio - async def test_a(): - await asyncio.sleep(0) - """ - ) - ) - result = testdir.runpytest("--asyncio-mode=legacy") - assert result.parseoutcomes()["warnings"] == 1 - result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) - - -def test_warning_for_legacy_mode_cfg(testdir): - testdir.makepyfile( - dedent( - """\ - import asyncio - import pytest - - pytest_plugins = 'pytest_asyncio' - - @pytest.mark.asyncio - async def test_a(): - await asyncio.sleep(0) - """ - ) - ) - testdir.makefile(".ini", pytest="[pytest]\nasyncio_mode = legacy\n") - result = testdir.runpytest() - assert result.parseoutcomes()["warnings"] == 1 - result.stdout.fnmatch_lines(["*" + LEGACY_MODE + "*"]) - result.stdout.no_fnmatch_line("*" + LEGACY_ASYNCIO_FIXTURE + "*") - - -def test_warning_for_legacy_fixture(testdir): - testdir.makepyfile( - dedent( - """\ - import asyncio - import pytest - - pytest_plugins = 'pytest_asyncio' - - @pytest.fixture - async def fixture_a(): - await asyncio.sleep(0) - return 1 - - @pytest.mark.asyncio - async def test_a(fixture_a): - await asyncio.sleep(0) - assert fixture_a == 1 - """ - ) - ) - result = testdir.runpytest("--asyncio-mode=legacy") - assert result.parseoutcomes()["warnings"] == 2 - result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) - - -def test_warning_for_legacy_method_fixture(testdir): - testdir.makepyfile( - dedent( - """\ - import asyncio - import pytest - - pytest_plugins = 'pytest_asyncio' - - - class TestA: - - @pytest.fixture - async def fixture_a(self): - await asyncio.sleep(0) - return 1 - - @pytest.mark.asyncio - async def test_a(self, fixture_a): - await asyncio.sleep(0) - assert fixture_a == 1 - """ - ) - ) - result = testdir.runpytest("--asyncio-mode=legacy") - assert result.parseoutcomes()["warnings"] == 2 - result.stdout.fnmatch_lines(["*" + LEGACY_ASYNCIO_FIXTURE + "*"]) diff --git a/tests/test_asyncio_fixture.py b/tests/test_asyncio_fixture.py index 3a28cebb..2577cba0 100644 --- a/tests/test_asyncio_fixture.py +++ b/tests/test_asyncio_fixture.py @@ -42,7 +42,7 @@ async def test_fixture_with_params(fixture_with_params): assert fixture_with_params % 2 == 0 -@pytest.mark.parametrize("mode", ("auto", "strict", "legacy")) +@pytest.mark.parametrize("mode", ("auto", "strict")) def test_sync_function_uses_async_fixture(testdir, mode): testdir.makepyfile( dedent( From 42a56fff72032269b32e2a6c20bf97e86376def9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 07:33:25 +0200 Subject: [PATCH 168/198] Build(deps): Bump trio from 0.21.0 to 0.22.0 in /dependencies/default (#419) Bumps [trio](https://github.com/python-trio/trio) from 0.21.0 to 0.22.0. - [Release notes](https://github.com/python-trio/trio/releases) - [Commits](https://github.com/python-trio/trio/compare/v0.21.0...v0.22.0) --- updated-dependencies: - dependency-name: trio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 8f2dbe79..14a98758 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -18,7 +18,7 @@ pytest-trio==0.7.0 sniffio==1.3.0 sortedcontainers==2.4.0 tomli==2.0.1 -trio==0.21.0 +trio==0.22.0 typed-ast==1.5.4 typing_extensions==4.3.0 zipp==3.8.1 From 3309e8af31ee659c4d13002d4c64ff055699076d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 07:33:53 +0200 Subject: [PATCH 169/198] Build(deps): Bump coverage from 6.4.4 to 6.5.0 in /dependencies/default (#418) Bumps [coverage](https://github.com/nedbat/coveragepy) from 6.4.4 to 6.5.0. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/6.4.4...6.5.0) --- updated-dependencies: - dependency-name: coverage dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 14a98758..a90c2d90 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,6 @@ async-generator==1.10 attrs==22.1.0 -coverage==6.4.4 +coverage==6.5.0 flaky==3.7.0 hypothesis==6.54.6 idna==3.4 From 1c2300220d94b4ee722154ca923a1115221bc054 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 07:34:18 +0200 Subject: [PATCH 170/198] Build(deps): Bump mypy from 0.971 to 0.982 in /dependencies/default (#417) Bumps [mypy](https://github.com/python/mypy) from 0.971 to 0.982. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.971...v0.982) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a90c2d90..f18b446d 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -6,7 +6,7 @@ hypothesis==6.54.6 idna==3.4 importlib-metadata==4.12.0 iniconfig==1.1.1 -mypy==0.971 +mypy==0.982 mypy-extensions==0.4.3 outcome==1.2.0 packaging==21.3 From d9f77567189c96536b39b43520f4b40895b34fb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 07:37:28 +0200 Subject: [PATCH 171/198] Build(deps): Bump hypothesis in /dependencies/default (#416) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.54.6 to 6.56.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.54.6...hypothesis-python-6.56.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index f18b446d..1f8d6185 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 flaky==3.7.0 -hypothesis==6.54.6 +hypothesis==6.56.0 idna==3.4 importlib-metadata==4.12.0 iniconfig==1.1.1 From cab20f4d346e9e52e5ffc93854de3ec881e7d342 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 07:37:52 +0200 Subject: [PATCH 172/198] Build(deps): Bump importlib-metadata in /dependencies/default (#415) Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 4.12.0 to 5.0.0. - [Release notes](https://github.com/python/importlib_metadata/releases) - [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst) - [Commits](https://github.com/python/importlib_metadata/compare/v4.12.0...v5.0.0) --- updated-dependencies: - dependency-name: importlib-metadata dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 1f8d6185..5621a116 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -4,7 +4,7 @@ coverage==6.5.0 flaky==3.7.0 hypothesis==6.56.0 idna==3.4 -importlib-metadata==4.12.0 +importlib-metadata==5.0.0 iniconfig==1.1.1 mypy==0.982 mypy-extensions==0.4.3 From d45ab217c80117854b510edc6c9fdd457b6b07fc Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 11 Oct 2022 12:37:01 +0200 Subject: [PATCH 173/198] feat: Add deprecation warning for pytest < 7. (#420) The last v6 release of pytest was v6.2.5 on 2021-08-29. People have had more than a year to upgrade to pytest 7. It is time to sunset support for pytest 6. Signed-off-by: Michael Seifert --- CHANGELOG.rst | 1 + pytest_asyncio/plugin.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5ceab47f..0bb2c052 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,7 @@ Changelog UNRELEASED ================= - BREAKING: Removed *legacy* mode. If you're upgrading from v0.19 and you haven't configured ``asyncio_mode = legacy``, you can upgrade without taking any additional action. If you're upgrading from an earlier version or you have explicitly enabled *legacy* mode, you need to switch to *auto* or *strict* mode before upgrading to this version. +- Deprecate use of pytest v6. - Fixed an issue which prevented fixture setup from being cached. `#404 `_ 0.19.0 (22-07-13) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 6fd300d5..220d5a11 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -6,6 +6,7 @@ import inspect import socket import sys +import warnings from typing import ( Any, AsyncIterator, @@ -169,6 +170,14 @@ def pytest_configure(config: Config) -> None: "run using an asyncio event loop", ) + if getattr(pytest, "__version_tuple__", (0, 0, 0) < (7,)): + warnings.warn( + "You're using an outdated version of pytest. Newer releases of " + "pytest-asyncio will not be compatible with this pytest version. " + "Please update pytest to version 7 or later.", + DeprecationWarning, + ) + @pytest.mark.tryfirst def pytest_report_header(config: Config) -> List[str]: From 907c461f172e52159a595e2592176c7feac04a43 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Tue, 11 Oct 2022 12:38:13 +0200 Subject: [PATCH 174/198] Refactor pytest_pycollect_makeitems (#421) * refactor: Extracted logic for marking tests in auto mode into pytest_collection_modifyitems. pytest_pycollect_makeitem currently calls `Collector._genfunctions`, in order to delegate further collection of test items to the current pytest collector. It does so only to add the asyncio mark to async tests after the items have been collected. Rather than relying on a call to the protected `Collector._genfunctions` method the marking logic was moved to the pytest_collection_modifyitems hook, which is called at the end of the collection phase. This change removes the call to protected functions and makes the code easier to understand. Signed-off-by: Michael Seifert * refactor: Hoist up check for asyncio mode before trying to modify function items. pytest_collection_modifyitems has no effect when asyncio mode is not set to AUTO. Moving the mode check out of the loop prevents unnecessary work. Signed-off-by: Michael Seifert * refactor: Renamed _set_explicit_asyncio_mark and _has_explicit_asyncio_mark to _make_asyncio_fixture_function and _is_asyncio_fixture_function, respectively. The new names reflect the purpose of the functions, instead of what they do. The new names also avoid confusion with pytest markers by not using "mark" in their names. Signed-off-by: Michael Seifert * refactor: Removed obsolete elif clause. Legacy mode has been removed, so we don't need an elif to check if we're in AUTO mode. Signed-off-by: Michael Seifert * refactor: Renamed the "holder" argument to _preprocess_async_fixtures to "processed_fixturedefs" to better reflect the purpose of the variable. Signed-off-by: Michael Seifert * refactor: Simplified branching structure of _preprocess_async_fixtures. It is safe to call _make_asyncio_fixture_function without checking whether the fixture function has been converted to an asyncio fixture function, because each fixture is only processed once in the loop. Signed-off-by: Michael Seifert * refactor: Simplified logic in _preprocess_async_fixtures. Merged two if-clauses both of which cause the current fixturedef to be skipped. Signed-off-by: Michael Seifert * refactor: Extracted _inject_fixture_argnames from _preprocess_async_fixtures in order to improve readability. Signed-off-by: Michael Seifert * refactor: Extracted _synchronize_async_fixture from _preprocess_async_fixtures in order to improve readability. Signed-off-by: Michael Seifert --- pytest_asyncio/plugin.py | 117 +++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 220d5a11..9366054b 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -25,6 +25,7 @@ ) import pytest +from pytest import Function, Session, Item if sys.version_info >= (3, 8): from typing import Literal @@ -121,7 +122,7 @@ def fixture( fixture_function: Optional[FixtureFunction] = None, **kwargs: Any ) -> Union[FixtureFunction, FixtureFunctionMarker]: if fixture_function is not None: - _set_explicit_asyncio_mark(fixture_function) + _make_asyncio_fixture_function(fixture_function) return pytest.fixture(fixture_function, **kwargs) else: @@ -133,12 +134,12 @@ def inner(fixture_function: FixtureFunction) -> FixtureFunction: return inner -def _has_explicit_asyncio_mark(obj: Any) -> bool: +def _is_asyncio_fixture_function(obj: Any) -> bool: obj = getattr(obj, "__func__", obj) # instance method maybe? return getattr(obj, "_force_asyncio_fixture", False) -def _set_explicit_asyncio_mark(obj: Any) -> None: +def _make_asyncio_fixture_function(obj: Any) -> None: if hasattr(obj, "__func__"): # instance method, check the function object obj = obj.__func__ @@ -186,41 +187,51 @@ def pytest_report_header(config: Config) -> List[str]: return [f"asyncio: mode={mode}"] -def _preprocess_async_fixtures(config: Config, holder: Set[FixtureDef]) -> None: +def _preprocess_async_fixtures( + config: Config, + processed_fixturedefs: Set[FixtureDef], +) -> None: asyncio_mode = _get_asyncio_mode(config) fixturemanager = config.pluginmanager.get_plugin("funcmanage") for fixtures in fixturemanager._arg2fixturedefs.values(): for fixturedef in fixtures: - if fixturedef in holder: - continue func = fixturedef.func - if not _is_coroutine_or_asyncgen(func): - # Nothing to do with a regular fixture function + if fixturedef in processed_fixturedefs or not _is_coroutine_or_asyncgen( + func + ): + continue + if not _is_asyncio_fixture_function(func) and asyncio_mode == Mode.STRICT: + # Ignore async fixtures without explicit asyncio mark in strict mode + # This applies to pytest_trio fixtures, for example continue - if not _has_explicit_asyncio_mark(func): - if asyncio_mode == Mode.STRICT: - # Ignore async fixtures without explicit asyncio mark in strict mode - # This applies to pytest_trio fixtures, for example - continue - elif asyncio_mode == Mode.AUTO: - # Enforce asyncio mode if 'auto' - _set_explicit_asyncio_mark(func) + _make_asyncio_fixture_function(func) + _inject_fixture_argnames(fixturedef) + _synchronize_async_fixture(fixturedef) + assert _is_asyncio_fixture_function(fixturedef.func) + processed_fixturedefs.add(fixturedef) - to_add = [] - for name in ("request", "event_loop"): - if name not in fixturedef.argnames: - to_add.append(name) - if to_add: - fixturedef.argnames += tuple(to_add) +def _inject_fixture_argnames(fixturedef: FixtureDef) -> None: + """ + Ensures that `request` and `event_loop` are arguments of the specified fixture. + """ + to_add = [] + for name in ("request", "event_loop"): + if name not in fixturedef.argnames: + to_add.append(name) + if to_add: + fixturedef.argnames += tuple(to_add) - if inspect.isasyncgenfunction(func): - fixturedef.func = _wrap_asyncgen(func) - elif inspect.iscoroutinefunction(func): - fixturedef.func = _wrap_async(func) - assert _has_explicit_asyncio_mark(fixturedef.func) - holder.add(fixturedef) +def _synchronize_async_fixture(fixturedef: FixtureDef) -> None: + """ + Wraps the fixture function of an async fixture in a synchronous function. + """ + func = fixturedef.func + if inspect.isasyncgenfunction(func): + fixturedef.func = _wrap_asyncgen(func) + elif inspect.iscoroutinefunction(func): + fixturedef.func = _wrap_async(func) def _add_kwargs( @@ -290,7 +301,7 @@ async def setup() -> _R: @pytest.mark.tryfirst def pytest_pycollect_makeitem( - collector: Union[pytest.Module, pytest.Class], name: str, obj: object + collector: Union[pytest.Module, pytest.Class], name: str, obj: object ) -> Union[ None, pytest.Item, pytest.Collector, List[Union[pytest.Item, pytest.Collector]] ]: @@ -298,28 +309,38 @@ def pytest_pycollect_makeitem( if not collector.funcnamefilter(name): return None _preprocess_async_fixtures(collector.config, _HOLDER) - if isinstance(obj, staticmethod): - # staticmethods need to be unwrapped. - obj = obj.__func__ - if ( - _is_coroutine(obj) - or _is_hypothesis_test(obj) - and _hypothesis_test_wraps_coroutine(obj) - ): - item = pytest.Function.from_parent(collector, name=name) - marker = item.get_closest_marker("asyncio") - if marker is not None: - return list(collector._genfunctions(name, obj)) - else: - if _get_asyncio_mode(item.config) == Mode.AUTO: - # implicitly add asyncio marker if asyncio mode is on - ret = list(collector._genfunctions(name, obj)) - for elem in ret: - elem.add_marker("asyncio") - return ret # type: ignore[return-value] return None +def pytest_collection_modifyitems( + session: Session, config: Config, items: List[Item] +) -> None: + """ + Marks collected async test items as `asyncio` tests. + + The mark is only applied in `AUTO` mode. It is applied to: + + - coroutines + - staticmethods wrapping coroutines + - Hypothesis tests wrapping coroutines + + """ + if _get_asyncio_mode(config) != Mode.AUTO: + return + function_items = (item for item in items if isinstance(item, Function)) + for function_item in function_items: + function = function_item.obj + if isinstance(function, staticmethod): + # staticmethods need to be unwrapped. + function = function.__func__ + if ( + _is_coroutine(function) + or _is_hypothesis_test(function) + and _hypothesis_test_wraps_coroutine(function) + ): + function_item.add_marker("asyncio") + + def _hypothesis_test_wraps_coroutine(function: Any) -> bool: return _is_coroutine(function.hypothesis.inner_test) From eb487bcb076f44dedcdb33e74972bf06c37027ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:38:37 +0200 Subject: [PATCH 175/198] Build(deps): Bump hypothesis in /dependencies/default (#423) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.56.0 to 6.56.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.56.0...hypothesis-python-6.56.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 5621a116..292576e9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 flaky==3.7.0 -hypothesis==6.56.0 +hypothesis==6.56.1 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 From 4abf9d1df228ed8b083721d7affa73e4a08d13c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:39:08 +0200 Subject: [PATCH 176/198] Build(deps): Bump zipp from 3.8.1 to 3.9.0 in /dependencies/default (#424) Bumps [zipp](https://github.com/jaraco/zipp) from 3.8.1 to 3.9.0. - [Release notes](https://github.com/jaraco/zipp/releases) - [Changelog](https://github.com/jaraco/zipp/blob/main/CHANGES.rst) - [Commits](https://github.com/jaraco/zipp/compare/v3.8.1...v3.9.0) --- updated-dependencies: - dependency-name: zipp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 292576e9..49011e94 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -21,4 +21,4 @@ tomli==2.0.1 trio==0.22.0 typed-ast==1.5.4 typing_extensions==4.3.0 -zipp==3.8.1 +zipp==3.9.0 From adc88090f341d9872e9e9b4d22a94cdadf60b3bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:43:22 +0200 Subject: [PATCH 177/198] Build(deps): Bump typing-extensions in /dependencies/default (#425) Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.3.0 to 4.4.0. - [Release notes](https://github.com/python/typing_extensions/releases) - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.3.0...4.4.0) --- updated-dependencies: - dependency-name: typing-extensions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 49011e94..4aea73b4 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -20,5 +20,5 @@ sortedcontainers==2.4.0 tomli==2.0.1 trio==0.22.0 typed-ast==1.5.4 -typing_extensions==4.3.0 +typing_extensions==4.4.0 zipp==3.9.0 From 150f29c107fbd76641de47e040d43840769ef92c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Oct 2022 08:42:10 +0200 Subject: [PATCH 178/198] Build(deps): Bump hypothesis in /dependencies/default (#427) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.56.1 to 6.56.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.56.1...hypothesis-python-6.56.3) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 4aea73b4..cdaa6a6f 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 flaky==3.7.0 -hypothesis==6.56.1 +hypothesis==6.56.3 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 From 6450ddbe974f5359d56317ba8bdda8b2ab48655a Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 Oct 2022 10:50:36 +0200 Subject: [PATCH 179/198] Prepare release of v0.20.0. (#428) Signed-off-by: Michael Seifert --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0bb2c052..f0645f61 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,7 @@ Changelog ========= -UNRELEASED +0.20.0 (22-10-21) ================= - BREAKING: Removed *legacy* mode. If you're upgrading from v0.19 and you haven't configured ``asyncio_mode = legacy``, you can upgrade without taking any additional action. If you're upgrading from an earlier version or you have explicitly enabled *legacy* mode, you need to switch to *auto* or *strict* mode before upgrading to this version. - Deprecate use of pytest v6. From c8d017407d39dd81d6864fa9a58ba1240d54be9f Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 21 Oct 2022 14:46:42 +0200 Subject: [PATCH 180/198] fix: Do not warn about outdated pytest version when pytest>=7 is installed. (#431) Signed-off-by: Michael Seifert --- CHANGELOG.rst | 4 ++++ pytest_asyncio/plugin.py | 2 +- tests/test_pytest_min_version_warning.py | 26 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/test_pytest_min_version_warning.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f0645f61..5c84b46e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +0.20.1 (22-10-21) +================= +- Fixes an issue that warned about using an old version of pytest, even though the most recent version was installed. `#430 `_ + 0.20.0 (22-10-21) ================= - BREAKING: Removed *legacy* mode. If you're upgrading from v0.19 and you haven't configured ``asyncio_mode = legacy``, you can upgrade without taking any additional action. If you're upgrading from an earlier version or you have explicitly enabled *legacy* mode, you need to switch to *auto* or *strict* mode before upgrading to this version. diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 9366054b..3b7b2304 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -171,7 +171,7 @@ def pytest_configure(config: Config) -> None: "run using an asyncio event loop", ) - if getattr(pytest, "__version_tuple__", (0, 0, 0) < (7,)): + if getattr(pytest, "version_tuple", (0, 0, 0)) < (7,): warnings.warn( "You're using an outdated version of pytest. Newer releases of " "pytest-asyncio will not be compatible with this pytest version. " diff --git a/tests/test_pytest_min_version_warning.py b/tests/test_pytest_min_version_warning.py new file mode 100644 index 00000000..11de6800 --- /dev/null +++ b/tests/test_pytest_min_version_warning.py @@ -0,0 +1,26 @@ +from textwrap import dedent + +import pytest + + +@pytest.mark.skipif( + pytest.__version__ < "7.0.0", + reason="The warning shouldn't be present when run with recent pytest versions" +) +@pytest.mark.parametrize("mode", ("auto", "strict")) +def test_pytest_min_version_warning_is_not_triggered_for_pytest_7(testdir, mode): + testdir.makepyfile( + dedent( + """\ + import pytest + + pytest_plugins = 'pytest_asyncio' + + @pytest.mark.asyncio + async def test_triggers_pytest_warning(): + pass + """ + ) + ) + result = testdir.runpytest(f"--asyncio-mode={mode}") + result.assert_outcomes(passed=1, warnings=0) From 0ca201b09a8ce2ff3ddc912ad434d9db34ef5078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Tue, 1 Nov 2022 09:06:50 +0100 Subject: [PATCH 181/198] Fix setuptools deprecation warning for license_file (#432) Use `license_files` instead of `license_file` in `setup.py` to fix the following warning: > The license_file parameter is deprecated, use license_files instead. --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index b1f1e82d..08739b30 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ long_description_content_type = text/x-rst author = Tin Tvrtković author_email = tinchester@gmail.com license = Apache 2.0 -license_file = LICENSE +license_files = LICENSE classifiers = Development Status :: 4 - Beta From 91e723a373952640e08d69adaff1957a8cbe8c8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 09:08:04 +0100 Subject: [PATCH 182/198] Build(deps): Bump zipp from 3.9.0 to 3.10.0 in /dependencies/default (#434) Bumps [zipp](https://github.com/jaraco/zipp) from 3.9.0 to 3.10.0. - [Release notes](https://github.com/jaraco/zipp/releases) - [Changelog](https://github.com/jaraco/zipp/blob/main/CHANGES.rst) - [Commits](https://github.com/jaraco/zipp/compare/v3.9.0...v3.10.0) --- updated-dependencies: - dependency-name: zipp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index cdaa6a6f..5ee465e2 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -21,4 +21,4 @@ tomli==2.0.1 trio==0.22.0 typed-ast==1.5.4 typing_extensions==4.4.0 -zipp==3.9.0 +zipp==3.10.0 From 28ba705a81d041bd3b5487eb53ded447676dad37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Nov 2022 09:08:30 +0100 Subject: [PATCH 183/198] Build(deps): Bump hypothesis in /dependencies/default (#437) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.56.3 to 6.56.4. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.56.3...hypothesis-python-6.56.4) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 5ee465e2..d8925ba9 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -2,7 +2,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 flaky==3.7.0 -hypothesis==6.56.3 +hypothesis==6.56.4 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 From 38fc0320c39e24a473240303fbc780213354e64d Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 10 Nov 2022 07:06:01 +0100 Subject: [PATCH 184/198] Bump to pytest 7.2.0 (#438) * refactor: Address deprecation of @pytest.mark.tryfirst. Signed-off-by: Michael Seifert * test: Remove return value from test case. Return values in tests are deprecated starting from pytest 7.2 and will result in a warning. Signed-off-by: Michael Seifert * build: Bump pytest to v7.2.0. Signed-off-by: Michael Seifert Signed-off-by: Michael Seifert --- CHANGELOG.rst | 4 ++++ dependencies/default/constraints.txt | 4 ++-- pytest_asyncio/plugin.py | 4 ++-- tests/test_simple.py | 1 - 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c84b46e..34fe9c08 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,10 @@ Changelog ========= +UNRELEASED +================= +- Replaced usage of deprecated ``@pytest.mark.tryfirst`` with ``@pytest.hookimpl(tryfirst=True)`` `#438 `_ + 0.20.1 (22-10-21) ================= - Fixes an issue that warned about using an old version of pytest, even though the most recent version was installed. `#430 `_ diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index d8925ba9..b8cc7fc6 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,6 +1,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 +exceptiongroup==1.0.0 flaky==3.7.0 hypothesis==6.56.4 idna==3.4 @@ -11,9 +12,8 @@ mypy-extensions==0.4.3 outcome==1.2.0 packaging==21.3 pluggy==1.0.0 -py==1.11.0 pyparsing==3.0.9 -pytest==7.1.3 +pytest==7.2.0 pytest-trio==0.7.0 sniffio==1.3.0 sortedcontainers==2.4.0 diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 3b7b2304..17268c9b 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -180,7 +180,7 @@ def pytest_configure(config: Config) -> None: ) -@pytest.mark.tryfirst +@pytest.hookimpl(tryfirst=True) def pytest_report_header(config: Config) -> List[str]: """Add asyncio config to pytest header.""" mode = _get_asyncio_mode(config) @@ -299,7 +299,7 @@ async def setup() -> _R: _HOLDER: Set[FixtureDef] = set() -@pytest.mark.tryfirst +@pytest.hookimpl(tryfirst=True) def pytest_pycollect_makeitem( collector: Union[pytest.Module, pytest.Class], name: str, obj: object ) -> Union[ diff --git a/tests/test_simple.py b/tests/test_simple.py index dc68d61e..7b87a7f4 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -240,7 +240,6 @@ async def test_no_warning_on_skip(): def test_async_close_loop(event_loop): event_loop.close() - return "ok" def test_warn_asyncio_marker_for_regular_func(testdir): From fe63e346154b61bbfe767e585b0b3b55fb37463e Mon Sep 17 00:00:00 2001 From: Martijn Pieters Date: Fri, 11 Nov 2022 15:28:36 +0000 Subject: [PATCH 185/198] Handle bound fixture methods correctly (#439) When the current test request references an instance, bind the fixture function to that instance. When the unittest flag is set, this happens unconditionally, otherwise only if: - the fixture wasn't bound already - the fixture is bound to a compatible instance (the request.instance object has the same type or is a subclass of that type). This follows what pytest does in such cases, exactly. --- CHANGELOG.rst | 1 + pytest_asyncio/plugin.py | 59 ++++++++++++++----- tests/async_fixtures/test_async_fixtures.py | 12 ++++ .../async_fixtures/test_async_gen_fixtures.py | 13 ++++ 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 34fe9c08..34e8620b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ Changelog UNRELEASED ================= +- Fixes an issue with async fixtures that are defined as methods on a test class not being rebound to the actual test instance. `#197 `_ - Replaced usage of deprecated ``@pytest.mark.tryfirst`` with ``@pytest.hookimpl(tryfirst=True)`` `#438 `_ 0.20.1 (22-10-21) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 17268c9b..1f94c637 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -227,11 +227,10 @@ def _synchronize_async_fixture(fixturedef: FixtureDef) -> None: """ Wraps the fixture function of an async fixture in a synchronous function. """ - func = fixturedef.func - if inspect.isasyncgenfunction(func): - fixturedef.func = _wrap_asyncgen(func) - elif inspect.iscoroutinefunction(func): - fixturedef.func = _wrap_async(func) + if inspect.isasyncgenfunction(fixturedef.func): + _wrap_asyncgen_fixture(fixturedef) + elif inspect.iscoroutinefunction(fixturedef.func): + _wrap_async_fixture(fixturedef) def _add_kwargs( @@ -249,14 +248,38 @@ def _add_kwargs( return ret -def _wrap_asyncgen(func: Callable[..., AsyncIterator[_R]]) -> Callable[..., _R]: - @functools.wraps(func) +def _perhaps_rebind_fixture_func( + func: _T, instance: Optional[Any], unittest: bool +) -> _T: + if instance is not None: + # The fixture needs to be bound to the actual request.instance + # so it is bound to the same object as the test method. + unbound, cls = func, None + try: + unbound, cls = func.__func__, type(func.__self__) # type: ignore + except AttributeError: + pass + # If unittest is true, the fixture is bound unconditionally. + # otherwise, only if the fixture was bound before to an instance of + # the same type. + if unittest or (cls is not None and isinstance(instance, cls)): + func = unbound.__get__(instance) # type: ignore + return func + + +def _wrap_asyncgen_fixture(fixturedef: FixtureDef) -> None: + fixture = fixturedef.func + + @functools.wraps(fixture) def _asyncgen_fixture_wrapper( event_loop: asyncio.AbstractEventLoop, request: SubRequest, **kwargs: Any - ) -> _R: + ): + func = _perhaps_rebind_fixture_func( + fixture, request.instance, fixturedef.unittest + ) gen_obj = func(**_add_kwargs(func, kwargs, event_loop, request)) - async def setup() -> _R: + async def setup(): res = await gen_obj.__anext__() return res @@ -279,21 +302,27 @@ async def async_finalizer() -> None: request.addfinalizer(finalizer) return result - return _asyncgen_fixture_wrapper + fixturedef.func = _asyncgen_fixture_wrapper -def _wrap_async(func: Callable[..., Awaitable[_R]]) -> Callable[..., _R]: - @functools.wraps(func) +def _wrap_async_fixture(fixturedef: FixtureDef) -> None: + fixture = fixturedef.func + + @functools.wraps(fixture) def _async_fixture_wrapper( event_loop: asyncio.AbstractEventLoop, request: SubRequest, **kwargs: Any - ) -> _R: - async def setup() -> _R: + ): + func = _perhaps_rebind_fixture_func( + fixture, request.instance, fixturedef.unittest + ) + + async def setup(): res = await func(**_add_kwargs(func, kwargs, event_loop, request)) return res return event_loop.run_until_complete(setup()) - return _async_fixture_wrapper + fixturedef.func = _async_fixture_wrapper _HOLDER: Set[FixtureDef] = set() diff --git a/tests/async_fixtures/test_async_fixtures.py b/tests/async_fixtures/test_async_fixtures.py index 7ddd04ab..40012962 100644 --- a/tests/async_fixtures/test_async_fixtures.py +++ b/tests/async_fixtures/test_async_fixtures.py @@ -23,3 +23,15 @@ async def test_async_fixture(async_fixture, mock): assert mock.call_count == 1 assert mock.call_args_list[-1] == unittest.mock.call(START) assert async_fixture is RETVAL + + +class TestAsyncFixtureMethod: + is_same_instance = False + + @pytest.fixture(autouse=True) + async def async_fixture_method(self): + self.is_same_instance = True + + @pytest.mark.asyncio + async def test_async_fixture_method(self): + assert self.is_same_instance diff --git a/tests/async_fixtures/test_async_gen_fixtures.py b/tests/async_fixtures/test_async_gen_fixtures.py index 0bea7458..2b198f2b 100644 --- a/tests/async_fixtures/test_async_gen_fixtures.py +++ b/tests/async_fixtures/test_async_gen_fixtures.py @@ -36,3 +36,16 @@ async def test_async_gen_fixture_finalized(mock): assert mock.call_args_list[-1] == unittest.mock.call(END) finally: mock.reset_mock() + + +class TestAsyncGenFixtureMethod: + is_same_instance = False + + @pytest.fixture(autouse=True) + async def async_gen_fixture_method(self): + self.is_same_instance = True + yield None + + @pytest.mark.asyncio + async def test_async_gen_fixture_method(self): + assert self.is_same_instance From d9faba85890334f0548732d35f1b1d54a850a69f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:30:17 +0100 Subject: [PATCH 186/198] Build(deps): Bump mypy from 0.982 to 0.990 in /dependencies/default (#440) Bumps [mypy](https://github.com/python/mypy) from 0.982 to 0.990. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.982...v0.990) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index b8cc7fc6..52926289 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -7,7 +7,7 @@ hypothesis==6.56.4 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 -mypy==0.982 +mypy==0.990 mypy-extensions==0.4.3 outcome==1.2.0 packaging==21.3 From dc3ad211d160006b4a30996c0a2a2c29754ef1fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:30:46 +0100 Subject: [PATCH 187/198] Build(deps): Bump pytest-trio in /dependencies/default (#441) Bumps [pytest-trio](https://github.com/python-trio/pytest-trio) from 0.7.0 to 0.8.0. - [Release notes](https://github.com/python-trio/pytest-trio/releases) - [Commits](https://github.com/python-trio/pytest-trio/compare/v0.7.0...v0.8.0) --- updated-dependencies: - dependency-name: pytest-trio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 52926289..ff036c2a 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -14,7 +14,7 @@ packaging==21.3 pluggy==1.0.0 pyparsing==3.0.9 pytest==7.2.0 -pytest-trio==0.7.0 +pytest-trio==0.8.0 sniffio==1.3.0 sortedcontainers==2.4.0 tomli==2.0.1 From 07a1416c2fe15d85fc149b3caa35b057de0b3d6e Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Fri, 11 Nov 2022 16:35:02 +0100 Subject: [PATCH 188/198] Prepare release of v0.20.2. Signed-off-by: Michael Seifert --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 34e8620b..aa48ad69 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,7 +2,7 @@ Changelog ========= -UNRELEASED +0.20.2 (22-11-11) ================= - Fixes an issue with async fixtures that are defined as methods on a test class not being rebound to the actual test instance. `#197 `_ - Replaced usage of deprecated ``@pytest.mark.tryfirst`` with ``@pytest.hookimpl(tryfirst=True)`` `#438 `_ From d39589c0353657ee6d75d38db779cc4ecb2491c4 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Mon, 21 Nov 2022 07:13:55 +0100 Subject: [PATCH 189/198] Update pre-commit hooks (#449) * build: Update flake8 pre-commit hook to account for its move from GitLab to GitHub. see https://github.com/PyCQA/flake8/pull/1305 Signed-off-by: Michael Seifert * build: Update "pre-commit-hooks" pre-commit hook. Signed-off-by: Michael Seifert * build: Update "yesqa" pre-commit hook. Signed-off-by: Michael Seifert * build: Update "shed" pre-commit hook. Signed-off-by: Michael Seifert * build: Update "yamlfmt" pre-commit hook. Signed-off-by: Michael Seifert * build: Update "actionlint" pre-commit hook. Signed-off-by: Michael Seifert * build: Update "check-jsonschema" pre-commit hook. Signed-off-by: Michael Seifert Signed-off-by: Michael Seifert --- .pre-commit-config.yaml | 19 +++++++++---------- pytest_asyncio/plugin.py | 24 +++++++++++------------- tests/test_pytest_min_version_warning.py | 2 +- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c15003b..d8ee693e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,32 +1,31 @@ --- repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: check-merge-conflict exclude: rst$ - repo: https://github.com/asottile/yesqa - rev: v1.3.0 + rev: v1.4.0 hooks: - id: yesqa - repo: https://github.com/Zac-HD/shed - rev: 0.6.0 # 0.7 does not support Python 3.7 + rev: 0.10.7 hooks: - id: shed args: - --refactor - - --py37-plus types_or: - python - markdown - rst - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt - rev: 0.1.1 + rev: 0.2.2 hooks: - id: yamlfmt args: [--mapping, '2', --sequence, '2', --offset, '0'] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -37,8 +36,8 @@ repos: - id: check-xml - id: check-yaml - id: debug-statements -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 +- repo: https://github.com/pycqa/flake8 + rev: 5.0.4 hooks: - id: flake8 language_version: python3 @@ -47,7 +46,7 @@ repos: hooks: - id: python-use-type-annotations - repo: https://github.com/rhysd/actionlint - rev: v1.6.8 + rev: v1.6.22 hooks: - id: actionlint-docker args: @@ -58,7 +57,7 @@ repos: - -ignore - 'SC1004:' - repo: https://github.com/sirosen/check-jsonschema - rev: 0.9.1 + rev: 0.19.2 hooks: - id: check-github-actions ci: diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 1f94c637..18d03673 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -25,7 +25,7 @@ ) import pytest -from pytest import Function, Session, Item +from pytest import Function, Item, Session if sys.version_info >= (3, 8): from typing import Literal @@ -89,11 +89,10 @@ def fixture( scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., params: Optional[Iterable[object]] = ..., autouse: bool = ..., - ids: Optional[ - Union[ - Iterable[Union[None, str, float, int, bool]], - Callable[[Any], Optional[object]], - ] + ids: Union[ + Iterable[Union[str, float, int, bool, None]], + Callable[[Any], Optional[object]], + None, ] = ..., name: Optional[str] = ..., ) -> FixtureFunction: @@ -107,11 +106,10 @@ def fixture( scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., params: Optional[Iterable[object]] = ..., autouse: bool = ..., - ids: Optional[ - Union[ - Iterable[Union[None, str, float, int, bool]], - Callable[[Any], Optional[object]], - ] + ids: Union[ + Iterable[Union[str, float, int, bool, None]], + Callable[[Any], Optional[object]], + None, ] = ..., name: Optional[str] = None, ) -> FixtureFunctionMarker: @@ -330,9 +328,9 @@ async def setup(): @pytest.hookimpl(tryfirst=True) def pytest_pycollect_makeitem( - collector: Union[pytest.Module, pytest.Class], name: str, obj: object + collector: Union[pytest.Module, pytest.Class], name: str, obj: object ) -> Union[ - None, pytest.Item, pytest.Collector, List[Union[pytest.Item, pytest.Collector]] + pytest.Item, pytest.Collector, List[Union[pytest.Item, pytest.Collector]], None ]: """A pytest hook to collect asyncio coroutines.""" if not collector.funcnamefilter(name): diff --git a/tests/test_pytest_min_version_warning.py b/tests/test_pytest_min_version_warning.py index 11de6800..5f7bd72f 100644 --- a/tests/test_pytest_min_version_warning.py +++ b/tests/test_pytest_min_version_warning.py @@ -5,7 +5,7 @@ @pytest.mark.skipif( pytest.__version__ < "7.0.0", - reason="The warning shouldn't be present when run with recent pytest versions" + reason="The warning shouldn't be present when run with recent pytest versions", ) @pytest.mark.parametrize("mode", ("auto", "strict")) def test_pytest_min_version_warning_is_not_triggered_for_pytest_7(testdir, mode): From 0b281b1b76b93c29894519e0750a4f8634786741 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 06:16:57 +0000 Subject: [PATCH 190/198] Build(deps): Bump mypy from 0.990 to 0.991 in /dependencies/default (#446) Bumps [mypy](https://github.com/python/mypy) from 0.990 to 0.991. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.990...v0.991) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index ff036c2a..32c9df81 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -7,7 +7,7 @@ hypothesis==6.56.4 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 -mypy==0.990 +mypy==0.991 mypy-extensions==0.4.3 outcome==1.2.0 packaging==21.3 From 42da7a0fea2b2bf0846dbbed5d1abcf56c7fa38b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 06:20:01 +0000 Subject: [PATCH 191/198] Build(deps): Bump hypothesis in /dependencies/default (#450) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.56.4 to 6.58.0. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.56.4...hypothesis-python-6.58.0) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 32c9df81..2d2d844b 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -3,7 +3,7 @@ attrs==22.1.0 coverage==6.5.0 exceptiongroup==1.0.0 flaky==3.7.0 -hypothesis==6.56.4 +hypothesis==6.58.0 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 From d6a9a72ef1749a864e64ac6222a8d0da99e67de5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 06:20:10 +0000 Subject: [PATCH 192/198] Build(deps): Bump exceptiongroup in /dependencies/default (#451) Bumps [exceptiongroup](https://github.com/agronholm/exceptiongroup) from 1.0.0 to 1.0.4. - [Release notes](https://github.com/agronholm/exceptiongroup/releases) - [Changelog](https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst) - [Commits](https://github.com/agronholm/exceptiongroup/compare/1.0.0...1.0.4) --- updated-dependencies: - dependency-name: exceptiongroup dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 2d2d844b..9eacd220 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -1,7 +1,7 @@ async-generator==1.10 attrs==22.1.0 coverage==6.5.0 -exceptiongroup==1.0.0 +exceptiongroup==1.0.4 flaky==3.7.0 hypothesis==6.58.0 idna==3.4 From 3c78732497e02cfb4463fafd7c5b17bf1c88ce95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 18:57:13 +0100 Subject: [PATCH 193/198] Build(deps): Bump hypothesis in /dependencies/default (#453) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.58.0 to 6.58.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.58.0...hypothesis-python-6.58.1) --- updated-dependencies: - dependency-name: hypothesis dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index 9eacd220..a43aa18e 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -3,7 +3,7 @@ attrs==22.1.0 coverage==6.5.0 exceptiongroup==1.0.4 flaky==3.7.0 -hypothesis==6.58.0 +hypothesis==6.58.1 idna==3.4 importlib-metadata==5.0.0 iniconfig==1.1.1 From 56a393abec9b60d4e061b053dfdf8ce6985c8b6b Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 1 Dec 2022 18:57:32 +0100 Subject: [PATCH 194/198] Simplify README, move most content to a separate user documentation. (#448) Signed-off-by: Michael Seifert Signed-off-by: Michael Seifert --- README.rst | 213 ++------------------------------------ docs/Makefile | 20 ++++ docs/make.bat | 35 +++++++ docs/source/concepts.rst | 38 +++++++ docs/source/conf.py | 27 +++++ docs/source/index.rst | 30 ++++++ docs/source/reference.rst | 145 ++++++++++++++++++++++++++ docs/source/support.rst | 21 ++++ setup.cfg | 3 + 9 files changed, 328 insertions(+), 204 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/concepts.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst create mode 100644 docs/source/reference.rst create mode 100644 docs/source/support.rst diff --git a/README.rst b/README.rst index d62087bb..81984e88 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -pytest-asyncio: pytest support for asyncio -========================================== +pytest-asyncio +============== .. image:: https://img.shields.io/pypi/v/pytest-asyncio.svg :target: https://pypi.python.org/pypi/pytest-asyncio @@ -13,12 +13,9 @@ pytest-asyncio: pytest support for asyncio .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black -pytest-asyncio is an Apache2 licensed library, written in Python, for testing -asyncio code with pytest. +pytest-asyncio is a `pytest `_ plugin. It facilitates testing of code that uses the `asyncio `_ library. -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. +Specifically, pytest-asyncio provides support for coroutines as test functions. This allows users to *await* code inside their tests. For example, the following code is executed as a test item by pytest: .. code-block:: python @@ -27,21 +24,14 @@ provides useful fixtures and markers to make testing easier. res = await library.do_something() assert b"expected result" == res -pytest-asyncio has been strongly influenced by pytest-tornado_. -.. _pytest-tornado: https://github.com/eugeniy/pytest-tornado +Note that test classes subclassing the standard `unittest `__ library are not supported. Users +are advised to use `unittest.IsolatedAsyncioTestCase `__ +or an async framework such as `asynctest `__. + -Features --------- +pytest-asyncio is available under the `Apache License 2.0 `_. -- fixtures for creating and injecting versions of the asyncio event loop -- fixtures for injecting unused tcp/udp ports -- pytest markers for treating tests as asyncio coroutines -- easy testing with non-default event loops -- support for `async def` fixtures and async generator fixtures -- support *auto* mode to handle all async fixtures and tests automatically by asyncio; - provide *strict* mode if a test suite should work with different async frameworks - simultaneously, e.g. ``asyncio`` and ``trio``. Installation ------------ @@ -54,191 +44,6 @@ To install pytest-asyncio, simply: This is enough for pytest to pick up pytest-asyncio. -Modes ------ - -Pytest-asyncio provides two modes: *auto* and *strict* with *strict* mode being the default. - -The mode can be set by ``asyncio_mode`` configuration option in `configuration file -`_: - -.. code-block:: ini - - # pytest.ini - [pytest] - asyncio_mode = auto - -The value can be overridden by command-line option for ``pytest`` invocation: - -.. code-block:: bash - - $ pytest tests --asyncio-mode=strict - -Auto mode -~~~~~~~~~ - -When the mode is auto, all discovered *async* tests are considered *asyncio-driven* even -if they have no ``@pytest.mark.asyncio`` marker. - -All async fixtures are considered *asyncio-driven* as well, even if they are decorated -with a regular ``@pytest.fixture`` decorator instead of dedicated -``@pytest_asyncio.fixture`` counterpart. - -*asyncio-driven* means that tests and fixtures are executed by ``pytest-asyncio`` -plugin. - -This mode requires the simplest tests and fixtures configuration and is -recommended for default usage *unless* the same project and its test suite should -execute tests from different async frameworks, e.g. ``asyncio`` and ``trio``. In this -case, auto-handling can break tests designed for other framework; please use *strict* -mode instead. - -Strict mode -~~~~~~~~~~~ - -Strict mode enforces ``@pytest.mark.asyncio`` and ``@pytest_asyncio.fixture`` usage. -Without these markers, tests and fixtures are not considered as *asyncio-driven*, other -pytest plugin can handle them. - -Please use this mode if multiple async frameworks should be combined in the same test -suite. - -This mode is used by default for the sake of project inter-compatibility. - - -Fixtures --------- - -``event_loop`` -~~~~~~~~~~~~~~ -Creates a new asyncio event loop based on the current event loop policy. The new loop -is available as the return value of this fixture or via `asyncio.get_running_loop `__. -The event loop is closed when the fixture scope ends. The fixture scope defaults -to ``function`` scope. - -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 - -The ``event_loop`` fixture can be overridden in any of the standard pytest locations, -e.g. directly in the test file, or in ``conftest.py``. This allows redefining the -fixture scope, for example: - -.. code-block:: python - - @pytest.fixture(scope="session") - def event_loop(): - policy = asyncio.get_event_loop_policy() - loop = policy.new_event_loop() - yield loop - loop.close() - -If you need to change the type of the event loop, prefer setting a custom event loop policy over redefining the ``event_loop`` fixture. - -If the ``pytest.mark.asyncio`` marker is applied to a test function, the ``event_loop`` -fixture will be requested automatically by the test function. - -``unused_tcp_port`` -~~~~~~~~~~~~~~~~~~~ -Finds and yields a single unused TCP port on the localhost interface. Useful for -binding temporary test servers. - -``unused_tcp_port_factory`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A callable which returns a different unused TCP port each invocation. Useful -when several unused TCP ports are required in a test. - -.. code-block:: python - - def a_test(unused_tcp_port_factory): - port1, port2 = unused_tcp_port_factory(), unused_tcp_port_factory() - ... - -``unused_udp_port`` and ``unused_udp_port_factory`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Work just like their TCP counterparts but return unused UDP ports. - - -Async fixtures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Asynchronous fixtures are defined just like ordinary pytest fixtures, except they should be decorated with ``@pytest_asyncio.fixture``. - -.. code-block:: python3 - - import pytest_asyncio - - - @pytest_asyncio.fixture - async def async_gen_fixture(): - await asyncio.sleep(0.1) - yield "a value" - - - @pytest_asyncio.fixture(scope="module") - async def async_fixture(): - return await asyncio.sleep(0.1) - -All scopes are supported, but if you use a non-function scope you will need -to redefine the ``event_loop`` fixture to have the same or broader scope. -Async fixtures need the event loop, and so must have the same or narrower scope -than the ``event_loop`` fixture. - -*auto* mode automatically converts async fixtures declared with the -standard ``@pytest.fixture`` decorator to *asyncio-driven* versions. - - -Markers -------- - -``pytest.mark.asyncio`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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 -the introductory section for an example. - -The event loop used can be overridden by overriding the ``event_loop`` fixture -(see above). - -In order to make your test code a little more concise, the pytest |pytestmark|_ -feature can be used to mark entire modules or classes with this marker. -Only test coroutines will be affected (by default, coroutines prefixed by -``test_``), so, for example, fixtures are safe to define. - -.. code-block:: python - - import asyncio - - import pytest - - # All test coroutines will be treated as marked. - pytestmark = pytest.mark.asyncio - - - async def test_example(event_loop): - """No marker!""" - await asyncio.sleep(0, loop=event_loop) - -In *auto* mode, the ``pytest.mark.asyncio`` marker can be omitted, the marker is added -automatically to *async* test functions. - - -.. |pytestmark| replace:: ``pytestmark`` -.. _pytestmark: http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules - -Note about unittest -------------------- - -Test classes subclassing the standard `unittest `__ library are not supported, users -are recommended to use `unittest.IsolatedAsyncioTestCase `__ -or an async framework such as `asynctest `__. Contributing ------------ diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..dc1312ab --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/concepts.rst b/docs/source/concepts.rst new file mode 100644 index 00000000..eb08bae6 --- /dev/null +++ b/docs/source/concepts.rst @@ -0,0 +1,38 @@ +======== +Concepts +======== + +asyncio event loops +=================== +pytest-asyncio runs each test item in its own asyncio event loop. The loop can be accessed via the ``event_loop`` fixture, which is automatically requested by all async tests. + +.. code-block:: python + + async def test_provided_loop_is_running_loop(event_loop): + assert event_loop is asyncio.get_running_loop() + +You can think of `event_loop` as an autouse fixture for async tests. + +Test discovery modes +==================== + +Pytest-asyncio provides two modes for test discovery, *strict* and *auto*. + + +Strict mode +----------- + +In strict mode pytest-asyncio will only run tests that have the *asyncio* marker and will only evaluate async fixtures decorated with ``@pytest_asyncio.fixture``. Test functions and fixtures without these markers and decorators will not be handled by pytest-asyncio. + +This mode is intended for projects that want so support multiple asynchronous programming libraries as it allows pytest-asyncio to coexist with other async testing plugins in the same codebase. + +Pytest automatically enables installed plugins. As a result pytest plugins need to coexist peacefully in their default configuration. This is why strict mode is the default mode. + +Auto mode +--------- + +In *auto* mode pytest-asyncio automatically adds the *asyncio* marker to all asynchronous test functions. It will also take ownership of all async fixtures, regardless of whether they are decorated with ``@pytest.fixture`` or ``@pytest_asyncio.fixture``. + +This mode is intended for projects that use *asyncio* as their only asynchronous programming library. Auto mode makes for the simplest test and fixture configuration and is the recommended default. + +If you intend to support multiple asynchronous programming libraries, e.g. *asyncio* and *trio*, strict mode will be the preferred option. diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..b61a6679 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,27 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "pytest-asyncio" +copyright = "2022, pytest-asyncio contributors" +author = "Tin Tvrtković" +release = "v0.20.1" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [] + +templates_path = ["_templates"] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_rtd_theme" +html_static_path = ["_static"] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..153fe9e8 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,30 @@ +========================== +Welcome to pytest-asyncio! +========================== + +.. toctree:: + :maxdepth: 1 + :hidden: + + concepts + reference + support + +pytest-asyncio is a `pytest `_ plugin. It facilitates testing of code that uses the `asyncio `_ library. + +Specifically, pytest-asyncio provides support for coroutines as test functions. This allows users to *await* code inside their tests. For example, the following code is executed as a test item by pytest: + +.. code-block:: python + + @pytest.mark.asyncio + async def test_some_asyncio_code(): + res = await library.do_something() + assert b"expected result" == res + + +Note that test classes subclassing the standard `unittest `__ library are not supported. Users +are advised to use `unittest.IsolatedAsyncioTestCase `__ +or an async framework such as `asynctest `__. + + +pytest-asyncio is available under the `Apache License 2.0 `_. diff --git a/docs/source/reference.rst b/docs/source/reference.rst new file mode 100644 index 00000000..2fa77ff4 --- /dev/null +++ b/docs/source/reference.rst @@ -0,0 +1,145 @@ +========= +Reference +========= + +Configuration +============= + +The pytest-asyncio mode can be set by the ``asyncio_mode`` configuration option in the `configuration file +`_: + +.. code-block:: ini + + # pytest.ini + [pytest] + asyncio_mode = auto + +The value can also be set via the ``--asyncio-mode`` command-line option: + +.. code-block:: bash + + $ pytest tests --asyncio-mode=strict + + +If the asyncio mode is set in both the pytest configuration file and the command-line option, the command-line option takes precedence. If no asyncio mode is specified, the mode defaults to `strict`. + +Fixtures +======== + +``event_loop`` +-------------- +Creates a new asyncio event loop based on the current event loop policy. The new loop +is available as the return value of this fixture or via `asyncio.get_running_loop `__. +The event loop is closed when the fixture scope ends. The fixture scope defaults +to ``function`` scope. + +.. 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 + +Note that, when using the ``event_loop`` fixture, you need to interact with the event loop using methods like ``event_loop.run_until_complete``. If you want to *await* code inside your test function, you need to write a coroutine and use it as a test function. The `asyncio <#pytest-mark-asyncio>`__ marker +is used to mark coroutines that should be treated as test functions. + +The ``event_loop`` fixture can be overridden in any of the standard pytest locations, +e.g. directly in the test file, or in ``conftest.py``. This allows redefining the +fixture scope, for example: + +.. code-block:: python + + @pytest.fixture(scope="session") + def event_loop(): + policy = asyncio.get_event_loop_policy() + loop = policy.new_event_loop() + yield loop + loop.close() + +If you need to change the type of the event loop, prefer setting a custom event loop policy over redefining the ``event_loop`` fixture. + +If the ``pytest.mark.asyncio`` decorator is applied to a test function, the ``event_loop`` +fixture will be requested automatically by the test function. + +``unused_tcp_port`` +------------------- +Finds and yields a single unused TCP port on the localhost interface. Useful for +binding temporary test servers. + +``unused_tcp_port_factory`` +--------------------------- +A callable which returns a different unused TCP port each invocation. Useful +when several unused TCP ports are required in a test. + +.. code-block:: python + + def a_test(unused_tcp_port_factory): + port1, port2 = unused_tcp_port_factory(), unused_tcp_port_factory() + ... + +``unused_udp_port`` and ``unused_udp_port_factory`` +--------------------------------------------------- +Works just like their TCP counterparts but returns unused UDP ports. + + +Markers +======= + +``pytest.mark.asyncio`` +----------------------- +A coroutine or async generator with this marker will be treated as a test function by pytest. The marked function will be executed as an +asyncio task in the event loop provided by the ``event_loop`` fixture. + +In order to make your test code a little more concise, the pytest |pytestmark|_ +feature can be used to mark entire modules or classes with this marker. +Only test coroutines will be affected (by default, coroutines prefixed by +``test_``), so, for example, fixtures are safe to define. + +.. code-block:: python + + import asyncio + + import pytest + + # All test coroutines will be treated as marked. + pytestmark = pytest.mark.asyncio + + + async def test_example(event_loop): + """No marker!""" + await asyncio.sleep(0, loop=event_loop) + +In *auto* mode, the ``pytest.mark.asyncio`` marker can be omitted, the marker is added +automatically to *async* test functions. + + +.. |pytestmark| replace:: ``pytestmark`` +.. _pytestmark: http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules + + +Decorators +========== +Asynchronous fixtures are defined just like ordinary pytest fixtures, except they should be decorated with ``@pytest_asyncio.fixture``. + +.. code-block:: python3 + + import pytest_asyncio + + + @pytest_asyncio.fixture + async def async_gen_fixture(): + await asyncio.sleep(0.1) + yield "a value" + + + @pytest_asyncio.fixture(scope="module") + async def async_fixture(): + return await asyncio.sleep(0.1) + +All scopes are supported, but if you use a non-function scope you will need +to redefine the ``event_loop`` fixture to have the same or broader scope. +Async fixtures need the event loop, and so must have the same or narrower scope +than the ``event_loop`` fixture. + +*auto* mode automatically converts async fixtures declared with the +standard ``@pytest.fixture`` decorator to *asyncio-driven* versions. diff --git a/docs/source/support.rst b/docs/source/support.rst new file mode 100644 index 00000000..30981d94 --- /dev/null +++ b/docs/source/support.rst @@ -0,0 +1,21 @@ +=============== +Getting support +=============== + +Enterprise support +================== +`Tidelift `_ works with maintainers of numerous open source projects to ensure enterprise-grade support for your software supply chain. + +The Tidelift subscription includes security updates, verified license compliance, continuous software maintenance, and more. As a result, you get the guarantees provided by commercial software for the open source packages you use. + +Consider `signing up for the Tidelift subscription `__. + + +Direct maintainer support +========================= +If you require commercial support outside of the Tidelift subscription, reach out to `Michael Seifert, `__ one of the project's maintainers. + + +Community support +================= +The GitHub page of pytest-asyncio offers free community support on a best-effort basis. Please use the `issue tracker `__ to report bugs and the `discussions `__ to ask questions. diff --git a/setup.cfg b/setup.cfg index 08739b30..04ea3d90 100644 --- a/setup.cfg +++ b/setup.cfg @@ -47,6 +47,9 @@ testing = flaky >= 3.5.0 mypy >= 0.931 pytest-trio >= 0.7.0 +docs = + sphinx >= 5.3 + sphinx-rtd-theme >= 1.0 [options.entry_points] pytest11 = From a962e2bc89e1181de77e486b1d7cbd7815662350 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 18:57:49 +0100 Subject: [PATCH 195/198] Build(deps): Bump importlib-metadata in /dependencies/default (#454) Bumps [importlib-metadata](https://github.com/python/importlib_metadata) from 5.0.0 to 5.1.0. - [Release notes](https://github.com/python/importlib_metadata/releases) - [Changelog](https://github.com/python/importlib_metadata/blob/main/CHANGES.rst) - [Commits](https://github.com/python/importlib_metadata/compare/v5.0.0...v5.1.0) --- updated-dependencies: - dependency-name: importlib-metadata dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a43aa18e..a07de0ad 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -5,7 +5,7 @@ exceptiongroup==1.0.4 flaky==3.7.0 hypothesis==6.58.1 idna==3.4 -importlib-metadata==5.0.0 +importlib-metadata==5.1.0 iniconfig==1.1.1 mypy==0.991 mypy-extensions==0.4.3 From c3c601cfd9a59e52b555cfd8313d16dbc15fb704 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 18:58:05 +0100 Subject: [PATCH 196/198] Build(deps): Bump pypa/gh-action-pypi-publish from 1.5.1 to 1.5.2 (#456) Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.5.1 to 1.5.2. - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.5.1...v1.5.2) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c5876b8..80d181ef 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -118,7 +118,7 @@ jobs: run: | pandoc -s -o README.md README.rst - name: PyPI upload - uses: pypa/gh-action-pypi-publish@v1.5.1 + uses: pypa/gh-action-pypi-publish@v1.5.2 with: packages_dir: dist password: ${{ secrets.PYPI_API_TOKEN }} From 44ca3da2ad68ea672d07a76ccc065922e13b5d5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 18:58:33 +0100 Subject: [PATCH 197/198] Build(deps): Bump zipp from 3.10.0 to 3.11.0 in /dependencies/default (#455) Bumps [zipp](https://github.com/jaraco/zipp) from 3.10.0 to 3.11.0. - [Release notes](https://github.com/jaraco/zipp/releases) - [Changelog](https://github.com/jaraco/zipp/blob/main/CHANGES.rst) - [Commits](https://github.com/jaraco/zipp/compare/v3.10.0...v3.11.0) --- updated-dependencies: - dependency-name: zipp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies/default/constraints.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/default/constraints.txt b/dependencies/default/constraints.txt index a07de0ad..c89233f0 100644 --- a/dependencies/default/constraints.txt +++ b/dependencies/default/constraints.txt @@ -21,4 +21,4 @@ tomli==2.0.1 trio==0.22.0 typed-ast==1.5.4 typing_extensions==4.4.0 -zipp==3.10.0 +zipp==3.11.0 From 007e8ec12662ffd896c6151239dc7ed1402dc710 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Thu, 8 Dec 2022 13:08:38 +0100 Subject: [PATCH 198/198] [fix] Prevent DeprecationWarning about existing event loops to bubble up into user code. (#461) Pytest-asyncio fixture setup currently uses `get_event_loop` to clean up loops that don't correspond to the loop returned by the `event_loop` fixture. Starting with CPython 3.10.9 and 3.11.1 the call to get_event_loop emits a DeprecationWarning when function is called, but no event loop exists. This warning bubbles up and shows in test runs of library users. If the users have enabled `-W error` their tests will fail due to a warning in pytest-asyncio. This patch ignores the DeprecationWarning in the fixture setup. This is a temporary solution to restore compatibility with the respective CPython patch releases. Addresses #460 Signed-off-by: Michael Seifert Signed-off-by: Michael Seifert --- CHANGELOG.rst | 5 +++++ pytest_asyncio/plugin.py | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aa48ad69..e6f80383 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog ========= +0.20.3 (22-12-08) +================= +- Prevent DeprecationWarning to bubble up on CPython 3.10.9 and 3.11.1. + `#460 `_ + 0.20.2 (22-11-11) ================= - Fixes an issue with async fixtures that are defined as methods on a test class not being rebound to the actual test instance. `#197 `_ diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 18d03673..403d814f 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -399,7 +399,9 @@ def pytest_fixture_setup( loop = outcome.get_result() policy = asyncio.get_event_loop_policy() try: - old_loop = policy.get_event_loop() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + old_loop = policy.get_event_loop() if old_loop is not loop: old_loop.close() except RuntimeError: