From 4279e12063bb4f2114ba25db4bdcb13c6022808d Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 26 Aug 2020 22:11:38 -0400 Subject: [PATCH 01/34] Add trio_run for configurable substitution for trio.run --- pytest_trio/_tests/helpers.py | 6 ++++- pytest_trio/plugin.py | 42 ++++++++++++++++++++++++++++++----- test-requirements.txt | 1 + 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/pytest_trio/_tests/helpers.py b/pytest_trio/_tests/helpers.py index 5ae5f9e..89ef16c 100644 --- a/pytest_trio/_tests/helpers.py +++ b/pytest_trio/_tests/helpers.py @@ -5,11 +5,15 @@ def enable_trio_mode_via_pytest_ini(testdir): testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\n") +def enable_qtrio_mode_via_pytest_ini(testdir): + testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\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] + [enable_trio_mode_via_pytest_ini, enable_qtrio_mode_via_pytest_ini, enable_trio_mode_via_conftest_py] ) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 12e774b..4ec673f 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -39,6 +39,12 @@ def pytest_addoption(parser): type="bool", default=False, ) + parser.addini( + "trio_run", + "what runner should pytest-trio use? [trio, qtrio]", + type="linelist", + default=["trio"], + ) def pytest_configure(config): @@ -308,7 +314,23 @@ async def run(self, test_ctx, contextvars_ctx): def _trio_test_runner_factory(item, testfunc=None): - testfunc = testfunc or item.obj + if testfunc: + run = trio.run + else: + testfunc = item.obj + + runs = {marker.kwargs.get('run', trio.run) for marker in item.iter_markers("trio")} + + if len(runs) == 0: + 1/0 + elif len(runs) == 1: + [run] = runs + else: + runs.discard(trio.run) + if len(runs) == 1: + [run] = runs + else: + 1/0 if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis @@ -320,7 +342,7 @@ def _trio_test_runner_factory(item, testfunc=None): 'test function `%r` is marked trio but is not async' % item ) - @trio_test + @trio_test(run=run) async def _bootstrap_fixtures_and_run_test(**kwargs): __tracebackhide__ = True @@ -438,19 +460,29 @@ def pytest_fixture_setup(fixturedef, request): ################################################################ -def automark(items): +def automark(items, run=trio.run): for item in items: if hasattr(item.obj, "hypothesis"): test_func = item.obj.hypothesis.inner_test else: test_func = item.obj if iscoroutinefunction(test_func): - item.add_marker(pytest.mark.trio) + item.add_marker(pytest.mark.trio(run=run)) def pytest_collection_modifyitems(config, items): if config.getini("trio_mode"): - automark(items) + [run_string] = config.getini("trio_run") + + if run_string == "trio": + run = trio.run + elif run_string == "qtrio": + import qtrio + run = qtrio.run + else: + 1/0 + + automark(items, run=run) ################################################################ diff --git a/test-requirements.txt b/test-requirements.txt index 5c53c25..9139fcf 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,3 +1,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomment-678699693 pytest-cov hypothesis>=3.64 +https://github.com/altendky/trio/archive/configurable_trio_run.zip From 3d213fe004be66247977b64e572f353ad0a89050 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 26 Aug 2020 23:10:57 -0400 Subject: [PATCH 02/34] --upgrade for the Trio PR --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 9139fcf..19ee938 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomment-678699693 pytest-cov hypothesis>=3.64 -https://github.com/altendky/trio/archive/configurable_trio_run.zip +--upgrade https://github.com/altendky/trio/archive/configurable_trio_run.zip From 5b1448dbd22c78f6b08f7993f02c473b6327a622 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 26 Aug 2020 23:18:28 -0400 Subject: [PATCH 03/34] Revert "--upgrade for the Trio PR" This reverts commit 3d213fe004be66247977b64e572f353ad0a89050. --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 19ee938..9139fcf 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomment-678699693 pytest-cov hypothesis>=3.64 ---upgrade https://github.com/altendky/trio/archive/configurable_trio_run.zip +https://github.com/altendky/trio/archive/configurable_trio_run.zip From 05aa01dd887d2dedf7d9b2c97ac44834b9e26c8c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 26 Aug 2020 23:21:21 -0400 Subject: [PATCH 04/34] add qtrio for testing --- test-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test-requirements.txt b/test-requirements.txt index 9139fcf..daa6edd 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,3 +2,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomme pytest-cov hypothesis>=3.64 https://github.com/altendky/trio/archive/configurable_trio_run.zip +https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip From 135476168665e985932c9af53d7e05bcbbfbeecb Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Wed, 26 Aug 2020 23:44:23 -0400 Subject: [PATCH 05/34] Update test-requirements.txt --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index daa6edd..6b83b37 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,4 +2,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomme pytest-cov hypothesis>=3.64 https://github.com/altendky/trio/archive/configurable_trio_run.zip -https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip +https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip[pyside2] From d128020295abf3689e54f5cdf18462b860db637f Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 00:17:49 -0400 Subject: [PATCH 06/34] Update test-requirements.txt --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 6b83b37..329fe63 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,4 +2,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomme pytest-cov hypothesis>=3.64 https://github.com/altendky/trio/archive/configurable_trio_run.zip -https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip[pyside2] +"qtrio[pyside2] @ https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip" From b6b7d0107c27e8e9806fd7cb1cb742d33b6fbec0 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 08:47:09 -0400 Subject: [PATCH 07/34] no "s i guess --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 329fe63..d391c30 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,4 +2,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomme pytest-cov hypothesis>=3.64 https://github.com/altendky/trio/archive/configurable_trio_run.zip -"qtrio[pyside2] @ https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip" +qtrio[pyside2] @ https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip From a021e3f650e10c6db046e78bd08f384fe6b63263 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 11:20:53 -0400 Subject: [PATCH 08/34] use fake qtrio for test to avoid the complicated system setup --- pytest_trio/_tests/helpers.py | 6 +++--- pytest_trio/_tests/test_trio_mode.py | 31 ++++++++++++++++++++++++++++ test-requirements.txt | 1 - 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/pytest_trio/_tests/helpers.py b/pytest_trio/_tests/helpers.py index 89ef16c..dfba5d1 100644 --- a/pytest_trio/_tests/helpers.py +++ b/pytest_trio/_tests/helpers.py @@ -5,8 +5,8 @@ def enable_trio_mode_via_pytest_ini(testdir): testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\n") -def enable_qtrio_mode_via_pytest_ini(testdir): - testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n") +def enable_trio_mode_trio_run_via_pytest_ini(testdir): + testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = trio\n") def enable_trio_mode_via_conftest_py(testdir): @@ -15,5 +15,5 @@ def enable_trio_mode_via_conftest_py(testdir): enable_trio_mode = pytest.mark.parametrize( "enable_trio_mode", - [enable_trio_mode_via_pytest_ini, enable_qtrio_mode_via_pytest_ini, enable_trio_mode_via_conftest_py] + [enable_trio_mode_via_pytest_ini, enable_trio_mode_trio_run_via_pytest_ini, enable_trio_mode_via_conftest_py] ) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index efc66a8..cef4bda 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -36,3 +36,34 @@ def test_trio_mode(testdir, enable_trio_mode): result = testdir.runpytest() result.assert_outcomes(passed=2, failed=2) + + +def test_qtrio_mode_configuration(testdir): + testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n") + + qtrio_text = """ + import trio + + fake_used = False + + def run(*args, **kwargs): + global fake_used + fake_used = True + + return trio.run(*args, **kwargs) + """ + + testdir.makepyfile(qtrio=qtrio_text) + + test_text = """ + import qtrio + import trio + + async def test_fake_qtrio_used(): + await trio.sleep(0) + assert qtrio.fake_used + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes(passed=1) diff --git a/test-requirements.txt b/test-requirements.txt index d391c30..9139fcf 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,4 +2,3 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomme pytest-cov hypothesis>=3.64 https://github.com/altendky/trio/archive/configurable_trio_run.zip -qtrio[pyside2] @ https://github.com/altendky/qtrio/archive/9-altendky-pytest_trio.zip From 9d0572845d2c9410bb2abb7987273b2c5bbe2221 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 11:38:32 -0400 Subject: [PATCH 09/34] yapf --- pytest_trio/_tests/helpers.py | 10 ++++++++-- pytest_trio/_tests/test_trio_mode.py | 4 +++- pytest_trio/plugin.py | 11 +++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/pytest_trio/_tests/helpers.py b/pytest_trio/_tests/helpers.py index dfba5d1..ac85f73 100644 --- a/pytest_trio/_tests/helpers.py +++ b/pytest_trio/_tests/helpers.py @@ -6,7 +6,9 @@ def enable_trio_mode_via_pytest_ini(testdir): def enable_trio_mode_trio_run_via_pytest_ini(testdir): - testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = trio\n") + testdir.makefile( + ".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = trio\n" + ) def enable_trio_mode_via_conftest_py(testdir): @@ -15,5 +17,9 @@ def enable_trio_mode_via_conftest_py(testdir): enable_trio_mode = pytest.mark.parametrize( "enable_trio_mode", - [enable_trio_mode_via_pytest_ini, enable_trio_mode_trio_run_via_pytest_ini, enable_trio_mode_via_conftest_py] + [ + enable_trio_mode_via_pytest_ini, + enable_trio_mode_trio_run_via_pytest_ini, + enable_trio_mode_via_conftest_py, + ] ) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index cef4bda..26bba62 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -39,7 +39,9 @@ def test_trio_mode(testdir, enable_trio_mode): def test_qtrio_mode_configuration(testdir): - testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n") + testdir.makefile( + ".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" + ) qtrio_text = """ import trio diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 4ec673f..124ab67 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -319,10 +319,13 @@ def _trio_test_runner_factory(item, testfunc=None): else: testfunc = item.obj - runs = {marker.kwargs.get('run', trio.run) for marker in item.iter_markers("trio")} + runs = { + marker.kwargs.get('run', trio.run) + for marker in item.iter_markers("trio") + } if len(runs) == 0: - 1/0 + 1 / 0 elif len(runs) == 1: [run] = runs else: @@ -330,7 +333,7 @@ def _trio_test_runner_factory(item, testfunc=None): if len(runs) == 1: [run] = runs else: - 1/0 + 1 / 0 if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis @@ -480,7 +483,7 @@ def pytest_collection_modifyitems(config, items): import qtrio run = qtrio.run else: - 1/0 + 1 / 0 automark(items, run=run) From 1104289dcc223652a68e01944b2c65e79ba78f0c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 13:17:23 -0400 Subject: [PATCH 10/34] yapf (actually) --- pytest_trio/_tests/helpers.py | 3 +-- pytest_trio/_tests/test_async_yield_fixture.py | 8 ++++---- pytest_trio/plugin.py | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pytest_trio/_tests/helpers.py b/pytest_trio/_tests/helpers.py index ac85f73..3715fa5 100644 --- a/pytest_trio/_tests/helpers.py +++ b/pytest_trio/_tests/helpers.py @@ -16,8 +16,7 @@ def enable_trio_mode_via_conftest_py(testdir): enable_trio_mode = pytest.mark.parametrize( - "enable_trio_mode", - [ + "enable_trio_mode", [ enable_trio_mode_via_pytest_ini, enable_trio_mode_trio_run_via_pytest_ini, enable_trio_mode_via_conftest_py, diff --git a/pytest_trio/_tests/test_async_yield_fixture.py b/pytest_trio/_tests/test_async_yield_fixture.py index 71dd362..126cfb9 100644 --- a/pytest_trio/_tests/test_async_yield_fixture.py +++ b/pytest_trio/_tests/test_async_yield_fixture.py @@ -122,7 +122,7 @@ def test_after(): def test_async_yield_fixture_within_sync_fixture( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -174,7 +174,7 @@ def test_after(): def test_async_yield_fixture_within_sync_yield_fixture( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -231,7 +231,7 @@ def test_after(): def test_async_yield_fixture_with_multiple_yields( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -304,7 +304,7 @@ async def test_actual_test(server): def test_async_yield_fixture_crashed_teardown_allow_other_teardowns( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 124ab67..e38ee28 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -156,7 +156,6 @@ class TrioFixture: test itself as well, since the test is basically just a fixture with no dependents and no teardown. """ - def __init__(self, name, func, pytest_kwargs, is_test=False): self.name = name self._func = func From 8cd81b06b5687f7263203eb787462b13d609951c Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 13:24:04 -0400 Subject: [PATCH 11/34] yapf (again (again)) (but with 0.22.0) --- pytest_trio/_tests/test_async_yield_fixture.py | 8 ++++---- pytest_trio/plugin.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pytest_trio/_tests/test_async_yield_fixture.py b/pytest_trio/_tests/test_async_yield_fixture.py index 126cfb9..71dd362 100644 --- a/pytest_trio/_tests/test_async_yield_fixture.py +++ b/pytest_trio/_tests/test_async_yield_fixture.py @@ -122,7 +122,7 @@ def test_after(): def test_async_yield_fixture_within_sync_fixture( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -174,7 +174,7 @@ def test_after(): def test_async_yield_fixture_within_sync_yield_fixture( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -231,7 +231,7 @@ def test_after(): def test_async_yield_fixture_with_multiple_yields( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( @@ -304,7 +304,7 @@ async def test_actual_test(server): def test_async_yield_fixture_crashed_teardown_allow_other_teardowns( - testdir, async_yield_implementation + testdir, async_yield_implementation ): testdir.makepyfile( diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index e38ee28..124ab67 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -156,6 +156,7 @@ class TrioFixture: test itself as well, since the test is basically just a fixture with no dependents and no teardown. """ + def __init__(self, name, func, pytest_kwargs, is_test=False): self.name = name self._func = func From 1ebf01809639e6415ca305439647b515121062e2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 14:13:12 -0400 Subject: [PATCH 12/34] Move trio_test() here --- pytest_trio/plugin.py | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 124ab67..a86840e 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -1,4 +1,5 @@ """pytest-trio implementation.""" +from functools import wraps, partial import sys from traceback import format_exception from collections.abc import Coroutine, Generator @@ -7,7 +8,8 @@ import outcome import pytest import trio -from trio.testing import MockClock, trio_test +from trio.abc import Clock, Instrument +from trio.testing import MockClock from async_generator import ( async_generator, yield_, asynccontextmanager, isasyncgen, isasyncgenfunction @@ -313,6 +315,42 @@ async def run(self, test_ctx, contextvars_ctx): raise RuntimeError("too many yields in fixture") +def _trio_test(fn=None, *, run=trio.run): + """Use: + @trio_test + async def test_whatever(): + await ... + + Also: if a pytest fixture is passed in that subclasses the ``Clock`` abc, then + that clock is passed to ``trio.run()``. + """ + + def decorator(fn): + @wraps(fn) + def wrapper(**kwargs): + __tracebackhide__ = True + clocks = [c for c in kwargs.values() if isinstance(c, Clock)] + if not clocks: + clock = None + elif len(clocks) == 1: + clock = clocks[0] + else: + raise ValueError("too many clocks spoil the broth!") + instruments = [ + i for i in kwargs.values() if isinstance(i, Instrument) + ] + return run( + partial(fn, **kwargs), clock=clock, instruments=instruments + ) + + return wrapper + + if fn is None: + return decorator + + return decorator(fn) + + def _trio_test_runner_factory(item, testfunc=None): if testfunc: run = trio.run @@ -345,7 +383,7 @@ def _trio_test_runner_factory(item, testfunc=None): 'test function `%r` is marked trio but is not async' % item ) - @trio_test(run=run) + @_trio_test(run=run) async def _bootstrap_fixtures_and_run_test(**kwargs): __tracebackhide__ = True From a4bb17446789b0ae7d8572a3d99caa7cc173f014 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 18:27:40 -0400 Subject: [PATCH 13/34] Apply trio_run config for @pytest.mark.trio as well --- pytest_trio/_tests/test_trio_mode.py | 40 ++++++++++++++++++++++------ pytest_trio/plugin.py | 27 ++++++++++++------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 26bba62..56b2092 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -38,29 +38,53 @@ def test_trio_mode(testdir, enable_trio_mode): result.assert_outcomes(passed=2, failed=2) -def test_qtrio_mode_configuration(testdir): +qtrio_text = """ +import trio + +fake_used = False + +def run(*args, **kwargs): + global fake_used + fake_used = True + + return trio.run(*args, **kwargs) +""" + + +def test_qtrio_mode_and_run_configuration(testdir): testdir.makefile( ".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" ) - qtrio_text = """ + testdir.makepyfile(qtrio=qtrio_text) + + test_text = """ + import qtrio import trio - fake_used = False + async def test_fake_qtrio_used(): + await trio.sleep(0) + assert qtrio.fake_used + """ + testdir.makepyfile(test_text) - def run(*args, **kwargs): - global fake_used - fake_used = True + result = testdir.runpytest() + result.assert_outcomes(passed=1) - return trio.run(*args, **kwargs) - """ + +def test_qtrio_just_run_configuration(testdir): + testdir.makefile( + ".ini", pytest="[pytest]\ntrio_run = qtrio\n" + ) testdir.makepyfile(qtrio=qtrio_text) test_text = """ + import pytest import qtrio import trio + @pytest.mark.trio async def test_fake_qtrio_used(): await trio.sleep(0) assert qtrio.fake_used diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index a86840e..1e9e3ab 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -131,6 +131,9 @@ def pytest_exception_interact(node, call, report): canary = contextvars.ContextVar("pytest-trio canary") +config_run = None + + class TrioTestContext: def __init__(self): self.crashed = False @@ -358,7 +361,7 @@ def _trio_test_runner_factory(item, testfunc=None): testfunc = item.obj runs = { - marker.kwargs.get('run', trio.run) + marker.kwargs.get('run', config_run) for marker in item.iter_markers("trio") } @@ -512,17 +515,21 @@ def automark(items, run=trio.run): def pytest_collection_modifyitems(config, items): - if config.getini("trio_mode"): - [run_string] = config.getini("trio_run") + global config_run - if run_string == "trio": - run = trio.run - elif run_string == "qtrio": - import qtrio - run = qtrio.run - else: - 1 / 0 + [run_string] = config.getini("trio_run") + if run_string == "trio": + run = trio.run + elif run_string == "qtrio": + import qtrio + run = qtrio.run + else: + 1 / 0 + + config_run = run + + if config.getini("trio_mode"): automark(items, run=run) From cf9288c6d9d43fff062e148aafd2da775214ee4a Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 20:41:00 -0400 Subject: [PATCH 14/34] Drop that global config_run --- pytest_trio/plugin.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 1e9e3ab..80d8545 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -131,9 +131,6 @@ def pytest_exception_interact(node, call, report): canary = contextvars.ContextVar("pytest-trio canary") -config_run = None - - class TrioTestContext: def __init__(self): self.crashed = False @@ -360,6 +357,7 @@ def _trio_test_runner_factory(item, testfunc=None): else: testfunc = item.obj + config_run = choose_run(config=item.config) runs = { marker.kwargs.get('run', config_run) for marker in item.iter_markers("trio") @@ -514,9 +512,7 @@ def automark(items, run=trio.run): item.add_marker(pytest.mark.trio(run=run)) -def pytest_collection_modifyitems(config, items): - global config_run - +def choose_run(config): [run_string] = config.getini("trio_run") if run_string == "trio": @@ -527,10 +523,12 @@ def pytest_collection_modifyitems(config, items): else: 1 / 0 - config_run = run + return run + +def pytest_collection_modifyitems(config, items): if config.getini("trio_mode"): - automark(items, run=run) + automark(items, run=choose_run(config=config)) ################################################################ From a7be06721991625ee735bb6beab64386b377ae66 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 20:41:22 -0400 Subject: [PATCH 15/34] yapf --- pytest_trio/_tests/test_trio_mode.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 56b2092..bb06cff 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -73,9 +73,7 @@ async def test_fake_qtrio_used(): def test_qtrio_just_run_configuration(testdir): - testdir.makefile( - ".ini", pytest="[pytest]\ntrio_run = qtrio\n" - ) + testdir.makefile(".ini", pytest="[pytest]\ntrio_run = qtrio\n") testdir.makepyfile(qtrio=qtrio_text) From dbcb6dc2d7fc8b5f0bbf758b90ee4c4fd60e8a59 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 21:19:43 -0400 Subject: [PATCH 16/34] Replace 1 / 0 with real exceptions --- pytest_trio/plugin.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 80d8545..6f41228 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -364,7 +364,7 @@ def _trio_test_runner_factory(item, testfunc=None): } if len(runs) == 0: - 1 / 0 + raise RuntimeError("No 'trio' marker found.") elif len(runs) == 1: [run] = runs else: @@ -372,7 +372,10 @@ def _trio_test_runner_factory(item, testfunc=None): if len(runs) == 1: [run] = runs else: - 1 / 0 + raise ValueError( + "Not yet able to select from more than one third-party" + + f" runner. Found: {', '.join(sorted(runs))}" + ) if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis @@ -521,7 +524,10 @@ def choose_run(config): import qtrio run = qtrio.run else: - 1 / 0 + raise ValueError( + f"{run_string!r} not valid for 'trio_run' config." + + " Must be one of: trio, qtrio" + ) return run From 6ace199169b6533bf3fbe74ea18125996317880d Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 21:31:58 -0400 Subject: [PATCH 17/34] yapf --- pytest_trio/plugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 6f41228..9209de5 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -373,8 +373,8 @@ def _trio_test_runner_factory(item, testfunc=None): [run] = runs else: raise ValueError( - "Not yet able to select from more than one third-party" - + f" runner. Found: {', '.join(sorted(runs))}" + "Not yet able to select from more than one third-party" + + f" runner. Found: {', '.join(sorted(runs))}" ) if getattr(testfunc, '_trio_test_runner_wrapped', False): @@ -525,8 +525,8 @@ def choose_run(config): run = qtrio.run else: raise ValueError( - f"{run_string!r} not valid for 'trio_run' config." - + " Must be one of: trio, qtrio" + f"{run_string!r} not valid for 'trio_run' config." + + " Must be one of: trio, qtrio" ) return run From 0c01e6fa5acb7faa6c0ca2a18ba82b38c4e3f732 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 21:42:49 -0400 Subject: [PATCH 18/34] requiring calling as @_trio_test(run=something) --- pytest_trio/plugin.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 9209de5..f51d5b0 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -315,7 +315,7 @@ async def run(self, test_ctx, contextvars_ctx): raise RuntimeError("too many yields in fixture") -def _trio_test(fn=None, *, run=trio.run): +def _trio_test(run): """Use: @trio_test async def test_whatever(): @@ -345,10 +345,7 @@ def wrapper(**kwargs): return wrapper - if fn is None: - return decorator - - return decorator(fn) + return decorator def _trio_test_runner_factory(item, testfunc=None): From 2be7a24b2737dd6af440cd172f4c8e5815f2ead4 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 22:05:23 -0400 Subject: [PATCH 19/34] add test for invalid trio_run name --- pytest_trio/_tests/test_trio_mode.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index bb06cff..58df7a8 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -91,3 +91,23 @@ async def test_fake_qtrio_used(): result = testdir.runpytest() result.assert_outcomes(passed=1) + + +def test_invalid_trio_run_fails(testdir): + run_name = "invalid_trio_run" + + testdir.makefile( + ".ini", pytest=f"[pytest]\ntrio_mode = true\ntrio_run = {run_name}\n" + ) + + test_text = """ + async def test(): + pass + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes() + result.stdout.fnmatch_lines([ + f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" + ]) From e9335c70e350954f0dea8bf71a39bf015674163a Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 22:40:15 -0400 Subject: [PATCH 20/34] add test for multiple third party runners error --- pytest_trio/_tests/test_trio_mode.py | 25 +++++++++++++++++++++++++ pytest_trio/plugin.py | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 58df7a8..2df0724 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -111,3 +111,28 @@ async def test(): result.stdout.fnmatch_lines([ f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" ]) + + +def test_multiple_custom_trio_runs_fail(testdir): + test_text = """ + import pytest + import pytest_trio + + def f(): + pass + + def g(): + pass + + @pytest.mark.trio(run=f) + @pytest.mark.trio(run=g) + async def test(): + pass + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes(failed=1) + result.stdout.fnmatch_lines([ + f"*ValueError: Not yet able to select from more than one third-party runner. Found: *" + ]) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index f51d5b0..27d3d64 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -369,9 +369,10 @@ def _trio_test_runner_factory(item, testfunc=None): if len(runs) == 1: [run] = runs else: + runs_string = ', '.join(sorted(f"{f.__module__}.{f.__name__}" for f in runs)) raise ValueError( "Not yet able to select from more than one third-party" + - f" runner. Found: {', '.join(sorted(runs))}" + f" runner. Found: {runs_string}" ) if getattr(testfunc, '_trio_test_runner_wrapped', False): From 1639e347c88233cce38f00426941348b51537243 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 23:30:15 -0400 Subject: [PATCH 21/34] add test for qtrio.run marker over trio mode --- pytest_trio/_tests/test_trio_mode.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 2df0724..25d692d 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -51,7 +51,7 @@ def run(*args, **kwargs): """ -def test_qtrio_mode_and_run_configuration(testdir): +def test_trio_mode_and_qtrio_run_configuration(testdir): testdir.makefile( ".ini", pytest="[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" ) @@ -72,6 +72,27 @@ async def test_fake_qtrio_used(): result.assert_outcomes(passed=1) +def test_trio_mode_and_qtrio_marker(testdir): + testdir.makefile(".ini", pytest="[pytest]\ntrio_mode = true\n") + + testdir.makepyfile(qtrio=qtrio_text) + + test_text = """ + import pytest + import qtrio + import trio + + @pytest.mark.trio(run=qtrio.run) + async def test_fake_qtrio_used(): + await trio.sleep(0) + assert qtrio.fake_used + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes(passed=1) + + def test_qtrio_just_run_configuration(testdir): testdir.makefile(".ini", pytest="[pytest]\ntrio_run = qtrio\n") From a2cf6e6f7b37d042e24fddcf1b8f22d763febe08 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 27 Aug 2020 23:36:10 -0400 Subject: [PATCH 22/34] yapf --- pytest_trio/_tests/test_trio_mode.py | 16 ++++++++++------ pytest_trio/plugin.py | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 25d692d..bed42d6 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -129,9 +129,11 @@ async def test(): result = testdir.runpytest() result.assert_outcomes() - result.stdout.fnmatch_lines([ - f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" - ]) + result.stdout.fnmatch_lines( + [ + f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" + ] + ) def test_multiple_custom_trio_runs_fail(testdir): @@ -154,6 +156,8 @@ async def test(): result = testdir.runpytest() result.assert_outcomes(failed=1) - result.stdout.fnmatch_lines([ - f"*ValueError: Not yet able to select from more than one third-party runner. Found: *" - ]) + result.stdout.fnmatch_lines( + [ + f"*ValueError: Not yet able to select from more than one third-party runner. Found: *" + ] + ) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 27d3d64..987ae3e 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -369,7 +369,9 @@ def _trio_test_runner_factory(item, testfunc=None): if len(runs) == 1: [run] = runs else: - runs_string = ', '.join(sorted(f"{f.__module__}.{f.__name__}" for f in runs)) + runs_string = ', '.join( + sorted(f"{f.__module__}.{f.__name__}" for f in runs) + ) raise ValueError( "Not yet able to select from more than one third-party" + f" runner. Found: {runs_string}" From 910de1dd39634cbab61ca09091e94e20ca9d5059 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 28 Aug 2020 11:03:16 -0400 Subject: [PATCH 23/34] more tests and coverage --- pytest_trio/_tests/test_fixture_mistakes.py | 25 +++++++++++++++++++++ pytest_trio/_tests/test_trio_mode.py | 12 +++++----- pytest_trio/plugin.py | 6 +++-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/pytest_trio/_tests/test_fixture_mistakes.py b/pytest_trio/_tests/test_fixture_mistakes.py index 5521a80..077861d 100644 --- a/pytest_trio/_tests/test_fixture_mistakes.py +++ b/pytest_trio/_tests/test_fixture_mistakes.py @@ -146,3 +146,28 @@ async def test_whatever(async_fixture): result.assert_outcomes(failed=1) result.stdout.fnmatch_lines(["*async_fixture*cancelled the test*"]) + + +@enable_trio_mode +def test_too_many_clocks(testdir, enable_trio_mode): + enable_trio_mode(testdir) + + testdir.makepyfile( + """ + import pytest + + @pytest.fixture + def extra_clock(mock_clock): + return mock_clock + + async def test_whatever(mock_clock, extra_clock): + pass + """ + ) + + result = testdir.runpytest() + + result.assert_outcomes(failed=1) + result.stdout.fnmatch_lines( + ["*ValueError: too many clocks spoil the broth!*"] + ) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index bed42d6..7aad25a 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -136,7 +136,13 @@ async def test(): ) -def test_multiple_custom_trio_runs_fail(testdir): +def test_third_party_run_plus_marker_fails(testdir): + testdir.makefile( + ".ini", pytest=f"[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" + ) + + testdir.makepyfile(qtrio=qtrio_text) + test_text = """ import pytest import pytest_trio @@ -144,11 +150,7 @@ def test_multiple_custom_trio_runs_fail(testdir): def f(): pass - def g(): - pass - @pytest.mark.trio(run=f) - @pytest.mark.trio(run=g) async def test(): pass """ diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 987ae3e..f47a7d6 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -360,8 +360,10 @@ def _trio_test_runner_factory(item, testfunc=None): for marker in item.iter_markers("trio") } - if len(runs) == 0: - raise RuntimeError("No 'trio' marker found.") + if len(runs) == 0: # pragma: no cover + raise RuntimeError( + "No 'trio' marker found. Please report to pytest-trio." + ) elif len(runs) == 1: [run] = runs else: From 511a6f6354d32ad651051bc00738d1c6269b0050 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 28 Aug 2020 23:56:38 -0400 Subject: [PATCH 24/34] #egg=trio --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 9139fcf..a5a6f77 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,4 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomment-678699693 pytest-cov hypothesis>=3.64 -https://github.com/altendky/trio/archive/configurable_trio_run.zip +https://github.com/altendky/trio/archive/configurable_trio_run.zip#egg=trio From 571128be63984a4fc19b19093aa693b37ea2ef7b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 29 Aug 2020 11:32:50 -0400 Subject: [PATCH 25/34] Add trio_run documentation --- docs/source/reference.rst | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/source/reference.rst b/docs/source/reference.rst index 2018b84..8070bce 100644 --- a/docs/source/reference.rst +++ b/docs/source/reference.rst @@ -381,3 +381,40 @@ write `stateful tests `__ for Trio-based libraries, then check out `hypothesis-trio `__. + + +Using alternative Trio runners +------------------------------ + +If you are working with a library that provides integration with Trio, +such as via :ref:`guest mode `, it can be used with +pytest-trio as well. Setting ``trio_run`` in the pytest configuration +makes your choice the global default for both tests explicitly marked +with ``@pytest.mark.trio`` and those automatically marked by Trio mode. +``trio_run`` presently supports ``trio`` and ``qtrio``. + +.. code-block:: ini + + # pytest.ini + [pytest] + trio_mode = true + trio_run = qtrio + +.. code-block:: python + + import pytest + + @pytest.mark.trio + async def test(): + assert True + +If you want more granular control or need to use a specific function, +it can be passed directly to the marker. + +.. code-block:: python + + import pytest + + @pytest.mark.trio(run=qtrio.run) + async def test(): + assert True From 339b34b9cba4eb7d43efffd500af6e2d69430be5 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 29 Aug 2020 16:45:08 -0400 Subject: [PATCH 26/34] Drop no longer needed Trio PR dependency --- test-requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index a5a6f77..5c53c25 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,4 +1,3 @@ pytest >= 6.0.0 # https://github.com/python-trio/pytest-trio/pull/98#issuecomment-678699693 pytest-cov hypothesis>=3.64 -https://github.com/altendky/trio/archive/configurable_trio_run.zip#egg=trio From ad87be94b82f387695ffcd6d3c2b4e2149be4e09 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 29 Aug 2020 17:49:43 -0400 Subject: [PATCH 27/34] Add trio-run-config anchor in the docs --- docs/source/reference.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/reference.rst b/docs/source/reference.rst index 8070bce..351e8c1 100644 --- a/docs/source/reference.rst +++ b/docs/source/reference.rst @@ -383,6 +383,8 @@ Trio-based libraries, then check out `hypothesis-trio `__. +.. _trio-run-config: + Using alternative Trio runners ------------------------------ From f2ab69293ce54a6b703a554b997576f965c1f9cc Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 18 Sep 2020 22:33:00 -0400 Subject: [PATCH 28/34] Use f.__qualname__ when reporting too many runners --- pytest_trio/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index f47a7d6..17a5b9a 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -372,7 +372,7 @@ def _trio_test_runner_factory(item, testfunc=None): [run] = runs else: runs_string = ', '.join( - sorted(f"{f.__module__}.{f.__name__}" for f in runs) + sorted(f"{f.__module__}.{f.__qualname__}" for f in runs) ) raise ValueError( "Not yet able to select from more than one third-party" + From a45d3149f98ec29d81841c67c355c7790799627b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 2 Oct 2020 10:50:15 -0400 Subject: [PATCH 29/34] Explain reason for fake qtrio module-in-a-string --- pytest_trio/_tests/test_trio_mode.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 7aad25a..2c182e3 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -38,6 +38,10 @@ def test_trio_mode(testdir, enable_trio_mode): result.assert_outcomes(passed=2, failed=2) +# This is faking qtrio due to real qtrio's dependence on either +# PyQt5 or PySide2. They are both large and require special +# handling in CI. The testing here is able to focus on the +# pytest-trio features with just this minimal substitute. qtrio_text = """ import trio From 7f7c4e13a54cfa09d7b84b996e96a9c2bb16cdc2 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 2 Oct 2020 11:19:13 -0400 Subject: [PATCH 30/34] Make trio_run a regular string ini option --- pytest_trio/plugin.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 17a5b9a..e28c18e 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -44,8 +44,7 @@ def pytest_addoption(parser): parser.addini( "trio_run", "what runner should pytest-trio use? [trio, qtrio]", - type="linelist", - default=["trio"], + default="trio", ) @@ -518,7 +517,7 @@ def automark(items, run=trio.run): def choose_run(config): - [run_string] = config.getini("trio_run") + run_string = config.getini("trio_run") if run_string == "trio": run = trio.run From c998963007df7ed49f1f927fe6e68854e4b28c87 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 2 Oct 2020 11:25:56 -0400 Subject: [PATCH 31/34] Tweak string split across lines --- pytest_trio/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index e28c18e..46775d0 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -374,7 +374,7 @@ def _trio_test_runner_factory(item, testfunc=None): sorted(f"{f.__module__}.{f.__qualname__}" for f in runs) ) raise ValueError( - "Not yet able to select from more than one third-party" + + f"Not yet able to select from more than one third-party" f" runner. Found: {runs_string}" ) From 68860e0cc703856e3dfa5600f5a04b39e2422b0b Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 2 Oct 2020 17:27:25 -0400 Subject: [PATCH 32/34] Remove checks for multiple conflicting runner specification --- pytest_trio/_tests/test_trio_mode.py | 29 ---------------------------- pytest_trio/plugin.py | 25 ++---------------------- 2 files changed, 2 insertions(+), 52 deletions(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 2c182e3..6b31a8a 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -138,32 +138,3 @@ async def test(): f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" ] ) - - -def test_third_party_run_plus_marker_fails(testdir): - testdir.makefile( - ".ini", pytest=f"[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" - ) - - testdir.makepyfile(qtrio=qtrio_text) - - test_text = """ - import pytest - import pytest_trio - - def f(): - pass - - @pytest.mark.trio(run=f) - async def test(): - pass - """ - testdir.makepyfile(test_text) - - result = testdir.runpytest() - result.assert_outcomes(failed=1) - result.stdout.fnmatch_lines( - [ - f"*ValueError: Not yet able to select from more than one third-party runner. Found: *" - ] - ) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 46775d0..2b0c712 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -354,29 +354,8 @@ def _trio_test_runner_factory(item, testfunc=None): testfunc = item.obj config_run = choose_run(config=item.config) - runs = { - marker.kwargs.get('run', config_run) - for marker in item.iter_markers("trio") - } - - if len(runs) == 0: # pragma: no cover - raise RuntimeError( - "No 'trio' marker found. Please report to pytest-trio." - ) - elif len(runs) == 1: - [run] = runs - else: - runs.discard(trio.run) - if len(runs) == 1: - [run] = runs - else: - runs_string = ', '.join( - sorted(f"{f.__module__}.{f.__qualname__}" for f in runs) - ) - raise ValueError( - f"Not yet able to select from more than one third-party" - f" runner. Found: {runs_string}" - ) + marker = item.get_closest_marker("trio") + run = marker.kwargs.get('run', config_run) if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis From 2b89fc1cca891c9862c7f99d60e26ceb23184fb9 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 10 Oct 2020 22:58:23 -0400 Subject: [PATCH 33/34] Use closest run-specifying marker, else config --- pytest_trio/_tests/test_trio_mode.py | 43 ++++++++++++++++++++++++++++ pytest_trio/plugin.py | 12 ++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/pytest_trio/_tests/test_trio_mode.py b/pytest_trio/_tests/test_trio_mode.py index 6b31a8a..f7bf61f 100644 --- a/pytest_trio/_tests/test_trio_mode.py +++ b/pytest_trio/_tests/test_trio_mode.py @@ -138,3 +138,46 @@ async def test(): f"*ValueError: {run_name!r} not valid for 'trio_run' config. Must be one of: *" ] ) + + +def test_closest_explicit_run_wins(testdir): + testdir.makefile( + ".ini", pytest=f"[pytest]\ntrio_mode = true\ntrio_run = trio\n" + ) + testdir.makepyfile(qtrio=qtrio_text) + + test_text = """ + import pytest + import pytest_trio + import qtrio + + @pytest.mark.trio(run='should be ignored') + @pytest.mark.trio(run=qtrio.run) + async def test(): + assert qtrio.fake_used + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes(passed=1) + + +def test_ini_run_wins_with_blank_marker(testdir): + testdir.makefile( + ".ini", pytest=f"[pytest]\ntrio_mode = true\ntrio_run = qtrio\n" + ) + testdir.makepyfile(qtrio=qtrio_text) + + test_text = """ + import pytest + import pytest_trio + import qtrio + + @pytest.mark.trio + async def test(): + assert qtrio.fake_used + """ + testdir.makepyfile(test_text) + + result = testdir.runpytest() + result.assert_outcomes(passed=1) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index 2b0c712..e5cd9ab 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -353,9 +353,15 @@ def _trio_test_runner_factory(item, testfunc=None): else: testfunc = item.obj - config_run = choose_run(config=item.config) - marker = item.get_closest_marker("trio") - run = marker.kwargs.get('run', config_run) + for marker in item.iter_markers("trio"): + maybe_run = marker.kwargs.get('run') + if maybe_run is not None: + run = maybe_run + break + else: + # no marker found that explicitly specifiers the runner so use config + run = choose_run(config=item.config) + if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis From 682499fd440f37055de0fc901a79354dc028fd09 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Sat, 10 Oct 2020 23:09:58 -0400 Subject: [PATCH 34/34] remove blank line for yapf --- pytest_trio/plugin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pytest_trio/plugin.py b/pytest_trio/plugin.py index e5cd9ab..61c4181 100644 --- a/pytest_trio/plugin.py +++ b/pytest_trio/plugin.py @@ -362,7 +362,6 @@ def _trio_test_runner_factory(item, testfunc=None): # no marker found that explicitly specifiers the runner so use config run = choose_run(config=item.config) - if getattr(testfunc, '_trio_test_runner_wrapped', False): # We have already wrapped this, perhaps because we combined Hypothesis # with pytest.mark.parametrize