From 3e8b6f8d9492bdbbdfeff5d9e193d4b89210ac3b Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Wed, 20 Dec 2023 18:14:00 +0100 Subject: [PATCH 1/3] [fix] Fixes a bug that caused an internal pytest error when using ImportWarning in a module. The fix monkey patches the pytest.Module.collect to attach the scoped event loop fixture to the module, rather than directly accessing Module.obj. This allows dropping all error handling related to module imports that has been added, because pytest_collectstart isn't meant to deal with those errors. Signed-off-by: Michael Seifert --- docs/source/reference/changelog.rst | 1 + pytest_asyncio/plugin.py | 31 +++++++++++++++-------------- tests/test_import.py | 18 +++++++++++++++++ 3 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 tests/test_import.py diff --git a/docs/source/reference/changelog.rst b/docs/source/reference/changelog.rst index f06157e4..834d65e5 100644 --- a/docs/source/reference/changelog.rst +++ b/docs/source/reference/changelog.rst @@ -6,6 +6,7 @@ Changelog =================== - Fixes a bug that caused event loops to be closed prematurely when using async generator fixtures with class scope or wider in a function-scoped test `#708 `_ - Fixes a bug that caused an internal pytest error when using unittest.SkipTest in a module `#711 `_ +- Fixes a bug that caused an internal pytest error when an ImportWarning is emitted in a module `#713 `_ 0.23.2 (2023-12-04) diff --git a/pytest_asyncio/plugin.py b/pytest_asyncio/plugin.py index 4af34fec..eb013f46 100644 --- a/pytest_asyncio/plugin.py +++ b/pytest_asyncio/plugin.py @@ -26,10 +26,8 @@ Union, overload, ) -from unittest import SkipTest import pytest -from _pytest.outcomes import OutcomeException from pytest import ( Class, Collector, @@ -608,25 +606,28 @@ def scoped_event_loop( # @pytest.fixture does not register the fixture anywhere, so pytest doesn't # know it exists. We work around this by attaching the fixture function to the - # collected Python class, where it will be picked up by pytest.Class.collect() + # collected Python object, where it will be picked up by pytest.Class.collect() # or pytest.Module.collect(), respectively - try: - pyobject = collector.obj - # If the collected module is a DoctestTextfile, collector.obj is None - if pyobject is None: - return - pyobject.__pytest_asyncio_scoped_event_loop = scoped_event_loop - except (OutcomeException, Collector.CollectError): + if type(collector) is Module: # Accessing Module.obj triggers a module import executing module-level # statements. A module-level pytest.skip statement raises the "Skipped" # OutcomeException or a Collector.CollectError, if the "allow_module_level" # kwargs is missing. These cases are handled correctly when they happen inside # Collector.collect(), but this hook runs before the actual collect call. - return - except SkipTest: - # Users may also have a unittest suite that they run with pytest. - # Therefore, we need to handle SkipTest to avoid breaking test collection. - return + # Therefore, we monkey patch Module.collect to add the scoped fixture to the + # module before it runs the actual collection. + def _patched_collect(): + collector.obj.__pytest_asyncio_scoped_event_loop = scoped_event_loop + return collector.__original_collect() + + collector.__original_collect = collector.collect + collector.collect = _patched_collect + else: + pyobject = collector.obj + # If the collected module is a DoctestTextfile, collector.obj is None + if pyobject is None: + return + pyobject.__pytest_asyncio_scoped_event_loop = scoped_event_loop # When collector is a package, collector.obj is the package's __init__.py. # pytest doesn't seem to collect fixtures in __init__.py. # Using parsefactories to collect fixtures in __init__.py their baseid will end diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 00000000..77352150 --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,18 @@ +from textwrap import dedent + +from pytest import Pytester + + +def test_import_warning(pytester: Pytester): + pytester.makepyfile( + dedent( + """\ + raise ImportWarning() + + async def test_errors_out(): + pass + """ + ) + ) + result = pytester.runpytest("--asyncio-mode=auto") + result.assert_outcomes(errors=1) From 3afb62d823422380793bace6b1c9537cb4d32e6e Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Sun, 24 Dec 2023 06:58:45 +0100 Subject: [PATCH 2/3] [docs] Mention correct issue in changelog. Signed-off-by: Michael Seifert --- docs/source/reference/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/changelog.rst b/docs/source/reference/changelog.rst index 834d65e5..7aadd6a2 100644 --- a/docs/source/reference/changelog.rst +++ b/docs/source/reference/changelog.rst @@ -4,7 +4,7 @@ Changelog 0.23.3 (UNRELEASED) =================== -- Fixes a bug that caused event loops to be closed prematurely when using async generator fixtures with class scope or wider in a function-scoped test `#708 `_ +- Fixes a bug that caused event loops to be closed prematurely when using async generator fixtures with class scope or wider in a function-scoped test `#706 `_ - Fixes a bug that caused an internal pytest error when using unittest.SkipTest in a module `#711 `_ - Fixes a bug that caused an internal pytest error when an ImportWarning is emitted in a module `#713 `_ From 7297584b1da646d950337c3ff64c93775af8d2d3 Mon Sep 17 00:00:00 2001 From: Michael Seifert Date: Sun, 24 Dec 2023 07:04:14 +0100 Subject: [PATCH 3/3] [docs] Shorten changelog by combining multiple issues. Signed-off-by: Michael Seifert --- docs/source/reference/changelog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/changelog.rst b/docs/source/reference/changelog.rst index 7aadd6a2..f00163c6 100644 --- a/docs/source/reference/changelog.rst +++ b/docs/source/reference/changelog.rst @@ -5,8 +5,8 @@ Changelog 0.23.3 (UNRELEASED) =================== - Fixes a bug that caused event loops to be closed prematurely when using async generator fixtures with class scope or wider in a function-scoped test `#706 `_ -- Fixes a bug that caused an internal pytest error when using unittest.SkipTest in a module `#711 `_ -- Fixes a bug that caused an internal pytest error when an ImportWarning is emitted in a module `#713 `_ +- Fixes various bugs that caused an internal pytest error during test collection `#711 `_ `#713 `_ `#719 `_ + 0.23.2 (2023-12-04)