Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scoped event loops based on pytest marks #620

Merged

Conversation

seifertm
Copy link
Contributor

@seifertm seifertm commented Sep 20, 2023

This PR introduces the asyncio_event_loop mark. When applied to classes and modules, the mark provides an asyncio event loop that is class-scoped or module-scoped, respectively. This is a prerequisite for the deprecation of event_loop fixture overrides (see #631).

Fixtures and tests under the same asyncio_event_loop mark are run in the same event loop, thus addressing #127 in parts.

The asyncio_event_loop mark supports an optional policy keyword argument, which takes an event loop policy or an iterable of policies. Tests under the effect of the mark are parametrized over the provided policies. If no policy is provided, the mark falls back to the value of asyncio.get_event_loop_policy() at mark definition time. This functionality offers a workaround for #591.

The implementation dynamically creates pytest fixtures based on the presence of the asycnio_event_loop mark. The fixtures are anchored at the corresponding module or class. The generated fixtures have a unique name that is generated from the pytest node ID of the module or class.

The generated fixtures are always parametrized, even when just a single event loop policy is specified. Therefore, we need to make pytest aware which parameters to use when evaluating the fixture. This happens in pytest_generate_tests. Whenever pytest_generate_tests is called for a test that is affected by an asyncio_event_loop mark_, the name of the dynamic fixture is injected into the metafunc along with the dynamic fixture definition. This information allows pytest to perform the standard fixture parametrization.

There is one special case, where a user may have requested the event_loop fixture for an async test that also requests a scoped event loop. In this case, the code raises an error, because we cannot possibly know what the user intended to do here.

…coped asyncio event loop when a class has the mark.

Signed-off-by: Michael Seifert <[email protected]>
…est.Pytester to avoid applying pytestmark to subsequent tests in the test module.

Signed-off-by: Michael Seifert <[email protected]>
@seifertm seifertm force-pushed the feat/scope-event-loop-based-on-asyncio-mark branch from 1f09cb5 to be36ce6 Compare September 26, 2023 14:35
@codecov-commenter
Copy link

codecov-commenter commented Oct 3, 2023

Codecov Report

Attention: 5 lines in your changes are missing coverage. Please review.

Comparison is base (c99ef93) 93.95% compared to head (9392b20) 93.49%.
Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #620      +/-   ##
==========================================
- Coverage   93.95%   93.49%   -0.46%     
==========================================
  Files           2        2              
  Lines         281      338      +57     
  Branches       55       70      +15     
==========================================
+ Hits          264      316      +52     
- Misses         11       12       +1     
- Partials        6       10       +4     
Files Coverage Δ
pytest_asyncio/plugin.py 93.43% <93.42%> (-0.46%) ⬇️

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

@seifertm
Copy link
Contributor Author

seifertm commented Oct 3, 2023

Added support for module-scoped loops.

…vent loop when a module has the mark.

Signed-off-by: Michael Seifert <[email protected]>
…nt loop implementation to pollute the test environment.

Signed-off-by: Michael Seifert <[email protected]>
…event loop implementation from polluting the test environment.

Signed-off-by: Michael Seifert <[email protected]>
…tor tests no longer requires an explicit event loop argument.

The wrapper retrieves the currently set loop via asyncio.get_event_loop, instead.

Signed-off-by: Michael Seifert <[email protected]>
…the function-scoped event_loop fixture.

They rather provide a fixture with a different name, based on the nodeid of the pytest.Collector that has the "asyncio_event_loop" mark.

When a test requests the event_loop fixture and a dynamically generated event loop with class or module scope, pytest-asyncio will raise an error.

Signed-off-by: Michael Seifert <[email protected]>
…p inside the event_loop fixture override rather than on the module-level.

This prevents the custom loop from being created during test collection time.

Signed-off-by: Michael Seifert <[email protected]>
@seifertm seifertm force-pushed the feat/scope-event-loop-based-on-asyncio-mark branch from 044358b to 57d60d0 Compare October 9, 2023 11:15
@seifertm
Copy link
Contributor Author

seifertm commented Oct 9, 2023

Added support for specifying a single event loop policy as a keyword argument to the asyncio_event_loop mark.

…sing an iterable of policies.

This causes tests under the _asyncio_event_loop_ mark to be parametrized with the different loop policies.

Signed-off-by: Michael Seifert <[email protected]>
@seifertm seifertm force-pushed the feat/scope-event-loop-based-on-asyncio-mark branch from 57d60d0 to 037a101 Compare October 9, 2023 14:05
@seifertm
Copy link
Contributor Author

seifertm commented Oct 9, 2023

  • Added support for multiple policies to be specified via the asyncio_event_loop mark. Tests under the same mark are parametrized accordingly.
  • Deprecated overrides of the event_loop fixture in favour of the asyncio_event_loop mark.

…e executed in the same event loop.

Signed-off-by: Michael Seifert <[email protected]>
@seifertm seifertm changed the title Provide a class-scoped asyncio event loop when a class has the asyncio mark Deprecate event_loop fixture overrides Oct 9, 2023
@seifertm seifertm changed the title Deprecate event_loop fixture overrides Scoped event loops based on pytest marks Oct 9, 2023
@seifertm seifertm force-pushed the feat/scope-event-loop-based-on-asyncio-mark branch from f3d6d53 to b525cf3 Compare October 9, 2023 14:42
@seifertm
Copy link
Contributor Author

seifertm commented Oct 9, 2023

I decided to move the deprecation of the event loop fixture into a separate PR.
This PR is a feature PR only.

@seifertm seifertm marked this pull request as ready for review October 9, 2023 14:57
@seifertm seifertm force-pushed the feat/scope-event-loop-based-on-asyncio-mark branch from 9392b20 to 14d1c61 Compare October 9, 2023 15:02
@seifertm seifertm added this pull request to the merge queue Oct 13, 2023
@seifertm seifertm removed this pull request from the merge queue due to a manual request Oct 13, 2023
@seifertm seifertm added this pull request to the merge queue Oct 13, 2023
Merged via the queue into pytest-dev:main with commit 617b905 Oct 13, 2023
8 checks passed
@seifertm seifertm deleted the feat/scope-event-loop-based-on-asyncio-mark branch October 13, 2023 10:38
@seifertm seifertm restored the feat/scope-event-loop-based-on-asyncio-mark branch October 13, 2023 10:40
@seifertm seifertm deleted the feat/scope-event-loop-based-on-asyncio-mark branch October 23, 2023 06:14
@seifertm seifertm restored the feat/scope-event-loop-based-on-asyncio-mark branch October 23, 2023 08:17
@seifertm seifertm deleted the feat/scope-event-loop-based-on-asyncio-mark branch October 23, 2023 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants