Skip to content

Commit

Permalink
fix: Fixes a bug that prevents async Hypothesis tests from working wi…
Browse files Browse the repository at this point in the history
…thout 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 <m.seifert@digitalernachschub.de>
  • Loading branch information
seifertm committed Jan 13, 2022
1 parent 694ebe2 commit bd8f210
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
4 changes: 4 additions & 0 deletions README.rst
Expand Up @@ -256,6 +256,10 @@ or an async framework such as `asynctest <https://asynctest.readthedocs.io/en/la

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 <https://github.com/pytest-dev/pytest-asyncio/issues/258>`_

0.17.0 (22-01-13)
~~~~~~~~~~~~~~~~~~~
- `pytest-asyncio` no longer alters existing event loop policies. `#168 <https://github.com/pytest-dev/pytest-asyncio/issues/168>`_, `#188 <https://github.com/pytest-dev/pytest-asyncio/issues/168>`_
Expand Down
12 changes: 11 additions & 1 deletion pytest_asyncio/plugin.py
Expand Up @@ -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))
Expand All @@ -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"""

Expand Down
17 changes: 17 additions & 0 deletions tests/hypothesis/test_base.py
Expand Up @@ -6,6 +6,8 @@
import pytest
from hypothesis import given, strategies as st

from pytest_asyncio.plugin import Mode


@pytest.fixture(scope="module")
def event_loop():
Expand All @@ -26,6 +28,21 @@ async def test_mark_outer(n):
assert isinstance(n, int)


@given(n=st.integers())
async def test_async_auto_marked(pytestconfig, n: int):
assert pytestconfig.inicfg["asyncio_mode"] == Mode.AUTO
assert isinstance(n, int)


@given(n=st.integers())
def test_sync_not_auto_marked(pytestconfig, request, n: int):
"""Assert that synchronous Hypothesis functions are not marked with asyncio"""
assert pytestconfig.inicfg["asyncio_mode"] == Mode.AUTO
markers = [marker.name for marker in request.node.own_markers]
assert "asyncio" not in markers
assert isinstance(n, int)


@pytest.mark.parametrize("y", [1, 2])
@given(x=st.none())
@pytest.mark.asyncio
Expand Down

0 comments on commit bd8f210

Please sign in to comment.