Skip to content

Commit

Permalink
In Trio mode, auto-convert async fixtures to Trio fixtures
Browse files Browse the repository at this point in the history
The main benefit of this is that it lets us catch more cases where
these fixtures are accidentally misused.

Closes gh-18, gh-51
  • Loading branch information
njsmith committed Jul 25, 2018
1 parent 87fd141 commit e798215
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 24 deletions.
15 changes: 15 additions & 0 deletions pytest_trio/_tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pytest


def enable_trio_mode_via_pytest_ini(testdir):
testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\n")


def enable_trio_mode_via_conftest_py(testdir):
testdir.makeconftest("from pytest_trio.enable_trio_mode import *")


enable_trio_mode = pytest.mark.parametrize(
"enable_trio_mode",
[enable_trio_mode_via_pytest_ini, enable_trio_mode_via_conftest_py]
)
59 changes: 55 additions & 4 deletions pytest_trio/_tests/test_fixture_mistakes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest
from pytest_trio import trio_fixture

from .helpers import enable_trio_mode


def test_trio_fixture_with_non_trio_test(testdir):
testdir.makepyfile(
Expand Down Expand Up @@ -34,11 +36,11 @@ def test_sync_indirect(indirect_trio_time):

result.assert_outcomes(passed=1, error=2)
result.stdout.fnmatch_lines(
["*Trio fixtures can only be used by Trio tests*"]
["*: Trio fixtures can only be used by Trio tests*"]
)


def test_trio_fixture_with_wrong_scope(testdir):
def test_trio_fixture_with_wrong_scope_without_trio_mode(testdir):
# There's a trick here: when you have a non-function-scope fixture, it's
# not instantiated for any particular function (obviously). So... when our
# pytest_fixture_setup hook tries to check for marks, it can't normally
Expand All @@ -49,7 +51,6 @@ def test_trio_fixture_with_wrong_scope(testdir):
testdir.makepyfile(
"""
import pytest
import pytest_trio
@pytest.fixture(scope="class")
async def async_class_fixture():
Expand All @@ -65,4 +66,54 @@ async def test_foo(self, async_class_fixture):
result = testdir.runpytest()

result.assert_outcomes(error=1)
result.stdout.fnmatch_lines(["*must be function-scope*"])
result.stdout.fnmatch_lines(["*: Trio fixtures must be function-scope*"])


@enable_trio_mode
def test_trio_fixture_with_wrong_scope_in_trio_mode(testdir, enable_trio_mode):
enable_trio_mode(testdir)

testdir.makepyfile(
"""
import pytest
@pytest.fixture(scope="session")
async def async_session_fixture():
pass
async def test_whatever(async_session_fixture):
pass
"""
)

result = testdir.runpytest()

result.assert_outcomes(error=1)
result.stdout.fnmatch_lines(["*: Trio fixtures must be function-scope*"])


@enable_trio_mode
def test_async_fixture_with_sync_test_in_trio_mode(testdir, enable_trio_mode):
enable_trio_mode(testdir)

testdir.makepyfile(
"""
import pytest
@pytest.fixture
async def async_fixture():
pass
def test_whatever(async_fixture):
pass
"""
)

result = testdir.runpytest()

result.assert_outcomes(error=1)
result.stdout.fnmatch_lines(
["*: Trio fixtures can only be used by Trio tests*"]
)
16 changes: 5 additions & 11 deletions pytest_trio/_tests/test_trio_mode.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pytest

from .helpers import enable_trio_mode

test_text = """
import pytest
import trio
Expand All @@ -26,19 +28,11 @@ async def test_hypothesis_fail(b):
"""


def test_trio_mode_pytest_ini(testdir):
testdir.makepyfile(test_text)

testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\n")

result = testdir.runpytest()
result.assert_outcomes(passed=2, failed=2)
@enable_trio_mode
def test_trio_mode(testdir, enable_trio_mode):
enable_trio_mode(testdir)


def test_trio_mode_conftest(testdir):
testdir.makepyfile(test_text)

testdir.makeconftest("from pytest_trio.enable_trio_mode import *")

result = testdir.runpytest()
result.assert_outcomes(passed=2, failed=2)
8 changes: 6 additions & 2 deletions pytest_trio/enable_trio_mode.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
__all__ = ["pytest_collection_modifyitems"]
__all__ = ["pytest_collection_modifyitems", "pytest_fixture_setup"]

from .plugin import automark
from .plugin import automark, handle_fixture


def pytest_collection_modifyitems(items):
automark(items)


def pytest_fixture_setup(fixturedef, request):
return handle_fixture(fixturedef, request, force_trio_mode=True)
23 changes: 16 additions & 7 deletions pytest_trio/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,22 +214,26 @@ def trio_fixture(func):
return pytest.fixture(func)


def _is_trio_fixture(func, is_trio_test, deps):
def _is_trio_fixture(func, coerce_async, deps):
if getattr(func, "_force_trio_fixture", False):
return True
if is_trio_test:
if iscoroutinefunction(func) or isasyncgenfunction(func):
return True
if (coerce_async and
(iscoroutinefunction(func) or isasyncgenfunction(func))):
return True
if any(isinstance(dep, TrioFixture) for dep in deps.values()):
return True
return False


@pytest.hookimpl
def pytest_fixture_setup(fixturedef, request):
def handle_fixture(fixturedef, request, force_trio_mode):
is_trio_test = (request.node.get_closest_marker("trio") is not None)
if force_trio_mode:
is_trio_mode = True
else:
is_trio_mode = request.node.config.getini("trio_mode")
coerce_async = (is_trio_test or is_trio_mode)
deps = {dep: request.getfixturevalue(dep) for dep in fixturedef.argnames}
if _is_trio_fixture(fixturedef.func, is_trio_test, deps):
if _is_trio_fixture(fixturedef.func, coerce_async, deps):
if request.scope != "function":
raise RuntimeError("Trio fixtures must be function-scope")
if not is_trio_test:
Expand All @@ -239,6 +243,11 @@ def pytest_fixture_setup(fixturedef, request):
return fixture


@pytest.hookimpl
def pytest_fixture_setup(fixturedef, request):
return handle_fixture(fixturedef, request, force_trio_mode=False)


################################################################
# Trio mode
################################################################
Expand Down

0 comments on commit e798215

Please sign in to comment.