Skip to content

fix: apply loop factories for asyncio marks via parametrize#1509

Open
l46983284-cpu wants to merge 6 commits into
pytest-dev:mainfrom
l46983284-cpu:fix/parametrize-asyncio-loop-factories
Open

fix: apply loop factories for asyncio marks via parametrize#1509
l46983284-cpu wants to merge 6 commits into
pytest-dev:mainfrom
l46983284-cpu:fix/parametrize-asyncio-loop-factories

Conversation

@l46983284-cpu

@l46983284-cpu l46983284-cpu commented Jul 16, 2026

Copy link
Copy Markdown

Summary

In strict mode, pytest.mark.asyncio can be attached only to individual @pytest.mark.parametrize parameter sets. Collection already turns those async parameter sets into Coroutine items, but pytest_generate_tests only looked for a function-level asyncio marker. As a result, pytest_asyncio_loop_factories was never applied and the test kept the default event loop.

This change resolves the asyncio marker from parametrize parameter sets when the function itself has no asyncio marker, so configured loop factories still parametrize _asyncio_loop_factory.

Scope

Supported slice only: discover pytest.mark.asyncio on a ParameterSet so loop factories apply, and the test body sees that loop.

This does not implement multi-backend partial ownership (for example asyncio + trio on one function without affecting the other path). That still needs the public pytest API discussed in pytest#13233, same as on the issue.

Tests

  • Regression: asyncio mark only via parametrize + custom loop factory, with a skipped non-asyncio parameter set and a body assert on the custom loop type.
  • Local:
    python -m pytest tests/test_loop_factory_parametrization.py::test_asyncio_mark_via_parametrize_uses_hook_loop_factories -q

Fixes #1463

When pytest.mark.asyncio is attached only to individual parameter sets,
pytest_generate_tests still needs to resolve that marker so
pytest_asyncio_loop_factories can parametrize the event loop.

Fixes pytest-dev#1463

Signed-off-by: Alex Chen <l46983284@gmail.com>
Signed-off-by: Alex Chen <l46983284@gmail.com>
@codecov-commenter

codecov-commenter commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 55.17241% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.39%. Comparing base (1975f90) to head (1e46cc2).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
pytest_asyncio/plugin.py 55.17% 6 Missing and 7 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1509      +/-   ##
==========================================
- Coverage   94.50%   92.39%   -2.12%     
==========================================
  Files           2        2              
  Lines         510      539      +29     
  Branches       62       71       +9     
==========================================
+ Hits          482      498      +16     
- Misses         22       28       +6     
- Partials        6       13       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

],
)
async def test_async(backend: str) -> None:
assert type(asyncio.get_running_loop()).__name__ == "CustomEventLoop"

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.

I don't think this test covers the failure described in #1463. I would expect this PR to include a test that is parametrized via both pytest.mark.asyncio and pytest.mark.trio (or something analogous) with an assertion on loop type within the test body.

Address review on pytest-dev#1509: assert loop type for asyncio and an analogous
non-asyncio backend mark in the same parametrize, matching the pytest-dev#1463 shape
without adding pytest-trio to CI deps.

Signed-off-by: Alex Chen <l46983284@gmail.com>
Move the pytest-dev#1509 review residual into its own test module so ruff format
does not thrash the large existing pytester file. Covers asyncio +
analogous non-asyncio backend marks with loop-type asserts (pytest-dev#1463 shape).

Signed-off-by: Alex Chen <l46983284@gmail.com>
@l46983284-cpu

Copy link
Copy Markdown
Author

Thanks for the review — agreed the first regression was too narrow for the #1463 multi-backend shape.

I added test_asyncio_and_analogous_backend_parametrize_uses_loop_factories: one parametrize with pytest.mark.asyncio and an analogous non-asyncio backend mark, and loop-type asserts inside the test body. CI no longer depends on pytest-trio, so the second backend is a tiny inline plugin instead of a hard trio dep; with pytest-trio installed locally the same product path also passes the real trio pair.

Focused tests green on this head.

Match pre-commit shed/black parentheses collapse on pytester.dedent calls.

Signed-off-by: Alex Chen <l46983284@gmail.com>


@pytest.hookimpl(tryfirst=True)
def pytest_pyfunc_call(pyfuncitem):

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.

Thank you for adding the test in response to my feedback, but this hook implementation should not be present here. Similar to my previous comment, I do not think this meaningfully covers the reported issue.

Remove the test-local pytest_pyfunc_call runner that invented a second
async backend. Keep the ParameterSet asyncio + skip + CustomEventLoop
regression that covers the supported product slice for pytest-dev#1463.

Signed-off-by: Alex Chen <l46983284@gmail.com>
@l46983284-cpu

Copy link
Copy Markdown
Author

Thanks — agreed. The local pytest_pyfunc_call was inventing a second runner instead of testing pytest-asyncio, so I removed that module.

What remains is the part of #1463 this change can actually fix without pytest internals: if pytest.mark.asyncio is only on a parameter set, configured loop factories still apply, and the test body sees that loop. Full multi-backend partial ownership (asyncio + trio on one function without affecting the other path) still needs the public API discussed in pytest#13233, same as on the issue.

Happy to adjust further if you want a different regression shape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pytest_asyncio_loop_factories hook is not called when pytest.mark.asyncio is added via parametrization

3 participants