diff --git a/docs/how-to-guides/configure_loop_factories_per_test.rst b/docs/how-to-guides/configure_loop_factories_per_test.rst new file mode 100644 index 00000000..f7f6d05c --- /dev/null +++ b/docs/how-to-guides/configure_loop_factories_per_test.rst @@ -0,0 +1,29 @@ +======================================================== +How to configure event loop factories from the test item +======================================================== + +``pytest_asyncio_loop_factories`` is called with the current pytest ``item``. +Use that item to decide which named event loop factories are available for the test being collected. + +For example, a hook can inspect the test's fixtures and return a different factory mapping for tests that request a particular fixture. +In ``conftest.py``, check the current item's fixture names and build the factory mapping for that item: + +.. include:: configure_loop_factories_per_test/conftest.py + :code: python + +Then request the fixture from tests that should use the custom factory: + +.. include:: configure_loop_factories_per_test/test_extra_loop_factories.py + :code: python + +In this example, ``test_runs_with_default_factory_only`` is parametrized only over ``default``, while ``test_runs_with_custom_factory_only`` is parametrized only over ``custom``. + +The same pattern works with any information available from the current pytest item, such as fixture names, markers, node IDs, or file paths. + +Because this is a standard pytest hook, its placement also matters. +An implementation in a nested ``conftest.py`` applies to tests collected under that directory. +Use this when a whole package or directory should share the same factory set. + +For declaring factories without item-specific logic, see :doc:`custom_loop_factory`. + +For selecting a subset of available factories from a test, see :doc:`run_test_with_specific_loop_factories`. diff --git a/docs/how-to-guides/configure_loop_factories_per_test/conftest.py b/docs/how-to-guides/configure_loop_factories_per_test/conftest.py new file mode 100644 index 00000000..ba2af819 --- /dev/null +++ b/docs/how-to-guides/configure_loop_factories_per_test/conftest.py @@ -0,0 +1,18 @@ +import asyncio + +import pytest + + +class CustomEventLoop(asyncio.SelectorEventLoop): + pass + + +@pytest.fixture +def requires_custom_loop(): + pass + + +def pytest_asyncio_loop_factories(config, item): + if "requires_custom_loop" in item.fixturenames: + return {"custom": CustomEventLoop} + return {"default": asyncio.new_event_loop} diff --git a/docs/how-to-guides/configure_loop_factories_per_test/test_extra_loop_factories.py b/docs/how-to-guides/configure_loop_factories_per_test/test_extra_loop_factories.py new file mode 100644 index 00000000..55eafe67 --- /dev/null +++ b/docs/how-to-guides/configure_loop_factories_per_test/test_extra_loop_factories.py @@ -0,0 +1,11 @@ +import pytest + + +@pytest.mark.asyncio +async def test_runs_with_default_factory_only(): + pass + + +@pytest.mark.asyncio +async def test_runs_with_custom_factory_only(requires_custom_loop): + pass diff --git a/docs/how-to-guides/custom_loop_factory.rst b/docs/how-to-guides/custom_loop_factory.rst index 6e176d95..fb4d9f9c 100644 --- a/docs/how-to-guides/custom_loop_factory.rst +++ b/docs/how-to-guides/custom_loop_factory.rst @@ -2,7 +2,7 @@ How to use custom event loop factories for tests ================================================ -pytest-asyncio can run asynchronous tests with custom event loop factories by implementing ``pytest_asyncio_loop_factories`` in ``conftest.py``. The hook returns a mapping from factory names to loop factory callables: +pytest-asyncio can run asynchronous tests with custom event loop factories by implementing ``pytest_asyncio_loop_factories`` in ``conftest.py``. The hook provides the named event loop factories that are available for a test item by returning a mapping from factory names to loop factory callables: .. code-block:: python @@ -21,6 +21,6 @@ pytest-asyncio can run asynchronous tests with custom event loop factories by im "custom": CustomEventLoop, } -See :doc:`run_test_with_specific_loop_factories` for running tests with only a subset of configured factories. +The hook receives the current pytest ``item``, so it can return different factory mappings for different tests. See :doc:`configure_loop_factories_per_test` for item-based factory configuration. -See :doc:`../reference/hooks` and :doc:`../reference/markers/index` for the hook and marker reference. +To run a test with only some configured factories, see :doc:`run_test_with_specific_loop_factories`. diff --git a/docs/how-to-guides/index.rst b/docs/how-to-guides/index.rst index acf0d177..b67a4125 100644 --- a/docs/how-to-guides/index.rst +++ b/docs/how-to-guides/index.rst @@ -11,6 +11,7 @@ How-To Guides change_default_fixture_loop change_default_test_loop custom_loop_factory + configure_loop_factories_per_test run_test_with_specific_loop_factories run_class_tests_in_same_loop run_module_tests_in_same_loop diff --git a/docs/how-to-guides/run_test_with_specific_loop_factories.rst b/docs/how-to-guides/run_test_with_specific_loop_factories.rst index 5be0333a..1a322fed 100644 --- a/docs/how-to-guides/run_test_with_specific_loop_factories.rst +++ b/docs/how-to-guides/run_test_with_specific_loop_factories.rst @@ -2,15 +2,22 @@ How to run a test with specific event loop factories only ========================================================= -To run a test with only a subset of configured factories, use the ``loop_factories`` argument of ``pytest.mark.asyncio``: +``pytest_asyncio_loop_factories`` determines which named event loop factories are available for each test item. +By default, pytest-asyncio parametrizes a test with every factory returned for that item. +Use ``loop_factories`` to select a subset of the factory names returned by the hook. -.. code-block:: python +Assume ``conftest.py`` provides two named factories: - import pytest +.. include:: run_test_with_specific_loop_factories/conftest.py + :code: python +Then use ``loop_factories`` to select which available factory names a test should run with: - @pytest.mark.asyncio(loop_factories=["custom"]) - async def test_only_with_custom_event_loop(): - pass +.. include:: run_test_with_specific_loop_factories/test_loop_factories_subset.py + :code: python If a requested factory name is not available from the hook, the test variant for that factory is skipped. + +For declaring the factories themselves, see :doc:`custom_loop_factory`. + +For choosing the available factories from the pytest item, see :doc:`configure_loop_factories_per_test`. diff --git a/docs/how-to-guides/run_test_with_specific_loop_factories/conftest.py b/docs/how-to-guides/run_test_with_specific_loop_factories/conftest.py new file mode 100644 index 00000000..631ca247 --- /dev/null +++ b/docs/how-to-guides/run_test_with_specific_loop_factories/conftest.py @@ -0,0 +1,12 @@ +import asyncio + + +class CustomEventLoop(asyncio.SelectorEventLoop): + pass + + +def pytest_asyncio_loop_factories(config, item): + return { + "default": asyncio.new_event_loop, + "custom": CustomEventLoop, + } diff --git a/docs/how-to-guides/run_test_with_specific_loop_factories/test_loop_factories_subset.py b/docs/how-to-guides/run_test_with_specific_loop_factories/test_loop_factories_subset.py new file mode 100644 index 00000000..c8eaf4c6 --- /dev/null +++ b/docs/how-to-guides/run_test_with_specific_loop_factories/test_loop_factories_subset.py @@ -0,0 +1,11 @@ +import pytest + + +@pytest.mark.asyncio +async def test_runs_with_every_configured_factory(): + pass + + +@pytest.mark.asyncio(loop_factories=["custom"]) +async def test_runs_with_only_custom_factory(): + pass