From 71e627aa8f4eecb9f13e69285069480f063dd118 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Fri, 28 Jul 2023 13:54:11 +0300 Subject: [PATCH] fixtures: fix crash when `parametrize(scope="package")` is used without a Package There as handling for `scope="class"` without a class, but not for `scope="package"` without a package. It would fail the assert. --- changelog/11255.bugfix.rst | 1 + src/_pytest/fixtures.py | 18 +++++++++++++----- testing/python/metafunc.py | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 changelog/11255.bugfix.rst diff --git a/changelog/11255.bugfix.rst b/changelog/11255.bugfix.rst new file mode 100644 index 00000000000..2a2a42667a3 --- /dev/null +++ b/changelog/11255.bugfix.rst @@ -0,0 +1 @@ +Fixed crash on `parametrize(..., scope="package")` without a package present. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 516a595efee..c35f842db59 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -155,6 +155,8 @@ def get_scope_node( def add_funcarg_pseudo_fixture_def( collector: nodes.Collector, metafunc: "Metafunc", fixturemanager: "FixtureManager" ) -> None: + import _pytest.python + # This function will transform all collected calls to functions # if they use direct funcargs (i.e. direct parametrization) # because we want later test execution to be able to rely on @@ -192,11 +194,17 @@ def add_funcarg_pseudo_fixture_def( if scope is not Scope.Function: node = get_scope_node(collector, scope) if node is None: - assert scope is Scope.Class and isinstance( - collector, _pytest.python.Module - ) - # Use module-level collector for class-scope (for now). - node = collector + # If used class scope and there is no class, use module-level + # collector (for now). + if scope is Scope.Class: + assert isinstance(collector, _pytest.python.Module) + node = collector + # If used package scope and there is no package, use session + # (for now). + elif scope is Scope.Package: + node = collector.session + else: + assert False, f"Unhandled missing scope: {scope}" if node is None: name2pseudofixturedef = None else: diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 08ea8f9107f..bb4ae9d9af3 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -1486,6 +1486,23 @@ def test_foo(x): ] ) + @pytest.mark.parametrize("scope", ["class", "package"]) + def test_parametrize_missing_scope_doesnt_crash( + self, pytester: Pytester, scope: str + ) -> None: + """Doesn't crash when parametrize(scope=) is used without a + corresponding node.""" + pytester.makepyfile( + f""" + import pytest + + @pytest.mark.parametrize("x", [0], scope="{scope}") + def test_it(x): pass + """ + ) + result = pytester.runpytest() + assert result.ret == 0 + class TestMetafuncFunctionalAuto: """Tests related to automatically find out the correct scope for