This commit is contained in:
Sadra Barikbin 2023-09-04 13:33:36 -03:00 committed by GitHub
commit c7c40c16b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 221 additions and 2 deletions

View File

@ -16,6 +16,7 @@ from typing import Final
from typing import final
from typing import Generator
from typing import Generic
from typing import Hashable
from typing import Iterable
from typing import Iterator
from typing import List
@ -157,13 +158,24 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]:
@dataclasses.dataclass(frozen=True)
class FixtureArgKey:
class FixtureArgKeyByIndex:
argname: str
param_index: int
scoped_item_path: Optional[Path]
item_cls: Optional[type]
@dataclasses.dataclass(frozen=True)
class FixtureArgKeyByValue:
argname: str
param_value: Hashable
scoped_item_path: Optional[Path]
item_cls: Optional[type]
FixtureArgKey = Union[FixtureArgKeyByIndex, FixtureArgKeyByValue]
def get_parametrized_fixture_keys(
item: nodes.Item, scope: Scope
) -> Iterator[FixtureArgKey]:
@ -197,7 +209,15 @@ def get_parametrized_fixture_keys(
assert_never(scope)
param_index = cs.indices[argname]
yield FixtureArgKey(argname, param_index, scoped_item_path, item_cls)
param_value = cs.params[argname]
if isinstance(param_value, Hashable):
yield FixtureArgKeyByValue(
argname, param_value, scoped_item_path, item_cls
)
else:
yield FixtureArgKeyByIndex( # type: ignore[unreachable]
argname, param_index, scoped_item_path, item_cls
)
# Algorithm for sorting on a per-parametrized resource setup basis.

View File

@ -11,6 +11,7 @@ from _pytest.monkeypatch import MonkeyPatch
from _pytest.pytester import get_public_names
from _pytest.pytester import Pytester
from _pytest.python import Function
from _pytest.scope import Scope
def test_getfuncargnames_functions():
@ -4531,3 +4532,201 @@ def test_yield_fixture_with_no_value(pytester: Pytester) -> None:
result.assert_outcomes(errors=1)
result.stdout.fnmatch_lines([expected])
assert result.ret == ExitCode.TESTS_FAILED
@pytest.mark.parametrize("scope", ["module", "package"])
def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices(
scope,
pytester: Pytester,
):
package = pytester.mkdir("package")
package.joinpath("__init__.py").write_text("", encoding="utf-8")
package.joinpath("test_a.py").write_text(
textwrap.dedent(
f"""\
import pytest
@pytest.fixture(scope='{scope}')
def fixture1(request):
pass
@pytest.mark.parametrize("fixture1", [1, 0], indirect=True)
def test_0(fixture1):
pass
@pytest.mark.parametrize("fixture1", [2, 1], indirect=True)
def test_1(fixture1):
pass
def test_2():
pass
@pytest.mark.parametrize("param", [0, 1, 2], scope='{scope}')
def test_3(param):
pass
@pytest.mark.parametrize("param", [2, 1, 0], scope='{scope}')
def test_4(param):
pass
"""
),
encoding="utf-8",
)
result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines(
[
r" <Function test_0\[1\]>",
r" <Function test_1\[1\]>",
r" <Function test_0\[0\]>",
r" <Function test_1\[2\]>",
r" <Function test_2>",
r" <Function test_3\[0\]>",
r" <Function test_4\[0\]>",
r" <Function test_3\[1\]>",
r" <Function test_4\[1\]>",
r" <Function test_3\[2\]>",
r" <Function test_4\[2\]>",
]
)
def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices_2(
pytester: Pytester,
):
pytester.makepyfile(
"""
import pytest
@pytest.fixture(scope='module')
def fixture1(request):
pass
@pytest.fixture(scope='module')
def fixture2(request):
pass
@pytest.mark.parametrize("fixture1, fixture2", [("a", 0), ("b", 1), ("a", 2)], indirect=True)
def test_1(fixture1, fixture2):
pass
@pytest.mark.parametrize("fixture1, fixture2", [("c", 4), ("a", 3)], indirect=True)
def test_2(fixture1, fixture2):
pass
def test_3():
pass
@pytest.mark.parametrize("param1, param2", [("a", 0), ("b", 1), ("a", 2)], scope='module')
def test_4(param1, param2):
pass
@pytest.mark.parametrize("param1, param2", [("c", 4), ("a", 3)], scope='module')
def test_5(param1, param2):
pass
"""
)
result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines(
[
r" <Function test_1\[a-0\]>",
r" <Function test_1\[a-2\]>",
r" <Function test_2\[a-3\]>",
r" <Function test_1\[b-1\]>",
r" <Function test_2\[c-4\]>",
r" <Function test_3>",
r" <Function test_4\[a-0\]>",
r" <Function test_4\[a-2\]>",
r" <Function test_5\[a-3\]>",
r" <Function test_4\[b-1\]>",
r" <Function test_5\[c-4\]>",
]
)
@pytest.mark.xfail(
reason="It isn't differentiated between direct `fixture` param and fixture `fixture`. Will be"
"solved by adding `baseid` to `FixtureArgKey`."
)
def test_reorder_with_high_scoped_direct_and_fixture_parametrization(
pytester: Pytester,
):
pytester.makepyfile(
"""
import pytest
@pytest.fixture(params=[0, 1], scope='module')
def fixture(request):
pass
def test_1(fixture):
pass
def test_2():
pass
@pytest.mark.parametrize("fixture", [1, 2], scope='module')
def test_3(fixture):
pass
"""
)
result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines(
[
r" <Function test_1\[0\]>",
r" <Function test_1\[1\]>",
r" <Function test_2>",
r" <Function test_3\[1\]>",
r" <Function test_3\[2\]>",
]
)
def test_get_parametrized_fixture_keys_with_unhashable_params(
pytester: Pytester,
) -> None:
module = pytester.makepyfile(
"""
import pytest
@pytest.mark.parametrize("arg", [[1], [2]], scope='module')
def test(arg):
pass
"""
)
test_0, test_1 = pytester.genitems((pytester.getmodulecol(module),))
test_0_keys = list(fixtures.get_parametrized_fixture_keys(test_0, Scope.Module))
test_1_keys = list(fixtures.get_parametrized_fixture_keys(test_1, Scope.Module))
assert len(test_0_keys) == len(test_1_keys) == 1
assert isinstance(test_0_keys[0], fixtures.FixtureArgKeyByIndex)
assert test_0_keys[0].param_index == 0
assert isinstance(test_1_keys[0], fixtures.FixtureArgKeyByIndex)
assert test_1_keys[0].param_index == 1
def test_reordering_with_unhashable_parametrize_args(pytester: Pytester) -> None:
pytester.makepyfile(
"""
import pytest
@pytest.mark.parametrize("arg", [[1], [2]], scope='module')
def test_1(arg):
print(arg)
def test_2():
print("test_2")
@pytest.mark.parametrize("arg", [[3], [4]], scope='module')
def test_3(arg):
print(arg)
"""
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines(
[
r"*1*",
r"*3*",
r"*2*",
r"*4*",
r"*test_2*",
]
)