Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/how-to-guides/configure_loop_factories_per_test.rst
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -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}
Original file line number Diff line number Diff line change
@@ -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
6 changes: 3 additions & 3 deletions docs/how-to-guides/custom_loop_factory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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`.
1 change: 1 addition & 0 deletions docs/how-to-guides/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 13 additions & 6 deletions docs/how-to-guides/run_test_with_specific_loop_factories.rst
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first part up to line 18 explains that all tests are parametrized with whatever entries are returned by the hook and that users can limit the parametrization via the loop_factories argument in the asyncio marker. The added code examples show an "inverted" control flow: there's no parametrization by default, unless the user explicitly lists the factory identifier in loop_factories.

I understand that we want to show both and each content makes sense, but it could be confusing that two approaches are mixed.

I'm not sure how to best solve this. We could either highlight that these are two very different approaches, e.g. "Variant 1, Variant 2" headlines or keep both variants in separate how-tos. I'm leaning towards the latter, but I'm failing to come up with distinguishable how-to titles.

Copy link
Copy Markdown
Contributor Author

@tjkuson tjkuson May 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I see what you mean.

I revisited how Diátaxis works and I think there's a reasonable argument in favour of this being three separate how-to guides: how to declare the event loop factories; how to declare factories based on item-specific logic; and how to select a subset of available factories from a test. I am curious what you think: 0a1803d f1a4d0d

Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Original file line number Diff line number Diff line change
@@ -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,
}
Original file line number Diff line number Diff line change
@@ -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
Loading