python: fix scope assignment for indirect parameter sets (#11277)
Previously, when assigning a scope for a fully-indirect parameter set, when there are multiple fixturedefs for a param (i.e. same-name fixture chain), the highest scope was used, but it should be the lowest scope, since that's the effective scope of the fixture.
This commit is contained in:
parent
1c04a92503
commit
e8a8a5f320
|
@ -0,0 +1,2 @@
|
||||||
|
Fixed a bug that when there are multiple fixtures for an indirect parameter,
|
||||||
|
the scope of the highest-scope fixture is picked for the parameter set, instead of that of the one with the narrowest scope.
|
|
@ -492,7 +492,7 @@ class FixtureRequest:
|
||||||
node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem
|
node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem
|
||||||
elif scope is Scope.Package:
|
elif scope is Scope.Package:
|
||||||
# FIXME: _fixturedef is not defined on FixtureRequest (this class),
|
# FIXME: _fixturedef is not defined on FixtureRequest (this class),
|
||||||
# but on FixtureRequest (a subclass).
|
# but on SubRequest (a subclass).
|
||||||
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined]
|
node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined]
|
||||||
else:
|
else:
|
||||||
node = get_scope_node(self._pyfuncitem, scope)
|
node = get_scope_node(self._pyfuncitem, scope)
|
||||||
|
|
|
@ -1516,7 +1516,7 @@ def _find_parametrized_scope(
|
||||||
if all_arguments_are_fixtures:
|
if all_arguments_are_fixtures:
|
||||||
fixturedefs = arg2fixturedefs or {}
|
fixturedefs = arg2fixturedefs or {}
|
||||||
used_scopes = [
|
used_scopes = [
|
||||||
fixturedef[0]._scope
|
fixturedef[-1]._scope
|
||||||
for name, fixturedef in fixturedefs.items()
|
for name, fixturedef in fixturedefs.items()
|
||||||
if name in argnames
|
if name in argnames
|
||||||
]
|
]
|
||||||
|
@ -1682,7 +1682,7 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
:param config:
|
:param config:
|
||||||
The pytest Config object.
|
The pytest Config object.
|
||||||
:param callspec:
|
:param callspec:
|
||||||
If given, this is function has been parametrized and the callspec contains
|
If given, this function has been parametrized and the callspec contains
|
||||||
meta information about the parametrization.
|
meta information about the parametrization.
|
||||||
:param callobj:
|
:param callobj:
|
||||||
If given, the object which will be called when the Function is invoked,
|
If given, the object which will be called when the Function is invoked,
|
||||||
|
|
|
@ -151,6 +151,7 @@ class TestMetafunc:
|
||||||
module_fix=[DummyFixtureDef(Scope.Module)],
|
module_fix=[DummyFixtureDef(Scope.Module)],
|
||||||
class_fix=[DummyFixtureDef(Scope.Class)],
|
class_fix=[DummyFixtureDef(Scope.Class)],
|
||||||
func_fix=[DummyFixtureDef(Scope.Function)],
|
func_fix=[DummyFixtureDef(Scope.Function)],
|
||||||
|
mixed_fix=[DummyFixtureDef(Scope.Module), DummyFixtureDef(Scope.Class)],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -187,6 +188,7 @@ class TestMetafunc:
|
||||||
)
|
)
|
||||||
== Scope.Module
|
== Scope.Module
|
||||||
)
|
)
|
||||||
|
assert find_scope(["mixed_fix"], indirect=True) == Scope.Class
|
||||||
|
|
||||||
def test_parametrize_and_id(self) -> None:
|
def test_parametrize_and_id(self) -> None:
|
||||||
def func(x, y):
|
def func(x, y):
|
||||||
|
@ -1503,6 +1505,66 @@ class TestMetafuncFunctional:
|
||||||
result = pytester.runpytest()
|
result = pytester.runpytest()
|
||||||
assert result.ret == 0
|
assert result.ret == 0
|
||||||
|
|
||||||
|
def test_reordering_with_scopeless_and_just_indirect_parametrization(
|
||||||
|
self, pytester: Pytester
|
||||||
|
) -> None:
|
||||||
|
pytester.makeconftest(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope="package")
|
||||||
|
def fixture1():
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
pytester.makepyfile(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def fixture0():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def fixture1(fixture0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("fixture1", [0], indirect=True)
|
||||||
|
def test_0(fixture1):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def fixture():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("fixture", [0], indirect=True)
|
||||||
|
def test_1(fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_2():
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test:
|
||||||
|
@pytest.fixture(scope="class")
|
||||||
|
def fixture(self, fixture):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("fixture", [0], indirect=True)
|
||||||
|
def test_3(self, fixture):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = pytester.runpytest("-v")
|
||||||
|
assert result.ret == 0
|
||||||
|
result.stdout.fnmatch_lines(
|
||||||
|
[
|
||||||
|
"*test_0*",
|
||||||
|
"*test_1*",
|
||||||
|
"*test_2*",
|
||||||
|
"*test_3*",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestMetafuncFunctionalAuto:
|
class TestMetafuncFunctionalAuto:
|
||||||
"""Tests related to automatically find out the correct scope for
|
"""Tests related to automatically find out the correct scope for
|
||||||
|
|
Loading…
Reference in New Issue