From 81464b3e68ea23d1932813f003a88cce68d2f578 Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Wed, 19 Jul 2023 21:26:06 +0330 Subject: [PATCH 1/6] Implement the feature --- src/_pytest/fixtures.py | 56 +++++++---- testing/example_scripts/issue_519.py | 4 +- testing/python/fixtures.py | 140 +++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 20 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index f2bf5320cd4..f98f774c7ca 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -15,6 +15,7 @@ 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 @@ -239,11 +240,18 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: ) -# Parametrized fixture key, helper alias for code below. -_Key = Tuple[object, ...] +@dataclasses.dataclass(frozen=True) +class FixtureArgKey: + argname: str + param_index: Optional[int] + param_value: Optional[Hashable] + scoped_item_path: Optional[Path] + item_cls: Optional[type] -def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_Key]: +def get_parametrized_fixture_keys( + item: nodes.Item, scope: Scope +) -> Iterator[FixtureArgKey]: """Return list of keys for all parametrized arguments which match the specified scope.""" assert scope is not Scope.Function @@ -256,21 +264,33 @@ def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_K # cs.indices.items() is random order of argnames. Need to # sort this so that different calls to # get_parametrized_fixture_keys will be deterministic. - for argname, param_index in sorted(cs.indices.items()): + for argname in sorted(cs.indices): if cs._arg2scope[argname] != scope: continue + + param_index: Optional[int] = cs.indices[argname] + param_value = cs.params[argname] + if isinstance(cs.params[argname], Hashable): + param_index = None + else: + param_value = None + + item_cls = None if scope is Scope.Session: - key: _Key = (argname, param_index) + scoped_item_path = None elif scope is Scope.Package: - key = (argname, param_index, item.path) + scoped_item_path = item.path.parent elif scope is Scope.Module: - key = (argname, param_index, item.path) + scoped_item_path = item.path elif scope is Scope.Class: + scoped_item_path = item.path item_cls = item.cls # type: ignore[attr-defined] - key = (argname, param_index, item.path, item_cls) else: assert_never(scope) - yield key + + yield FixtureArgKey( + argname, param_index, param_value, scoped_item_path, item_cls + ) # Algorithm for sorting on a per-parametrized resource setup basis. @@ -280,12 +300,12 @@ def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_K def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]: - argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]] = {} - items_by_argkey: Dict[Scope, Dict[_Key, Deque[nodes.Item]]] = {} + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]] = {} + items_by_argkey: Dict[Scope, Dict[FixtureArgKey, Deque[nodes.Item]]] = {} for scope in HIGH_SCOPES: - d: Dict[nodes.Item, Dict[_Key, None]] = {} + d: Dict[nodes.Item, Dict[FixtureArgKey, None]] = {} argkeys_cache[scope] = d - item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque) + item_d: Dict[FixtureArgKey, Deque[nodes.Item]] = defaultdict(deque) items_by_argkey[scope] = item_d for item in items: keys = dict.fromkeys(get_parametrized_fixture_keys(item, scope), None) @@ -301,8 +321,8 @@ def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]: def fix_cache_order( item: nodes.Item, - argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], - items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]], + items_by_argkey: Dict[Scope, Dict[FixtureArgKey, "Deque[nodes.Item]"]], ) -> None: for scope in HIGH_SCOPES: for key in argkeys_cache[scope].get(item, []): @@ -311,13 +331,13 @@ def fix_cache_order( def reorder_items_atscope( items: Dict[nodes.Item, None], - argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], - items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]], + items_by_argkey: Dict[Scope, Dict[FixtureArgKey, "Deque[nodes.Item]"]], scope: Scope, ) -> Dict[nodes.Item, None]: if scope is Scope.Function or len(items) < 3: return items - ignore: Set[Optional[_Key]] = set() + ignore: Set[Optional[FixtureArgKey]] = set() items_deque = deque(items) items_done: Dict[nodes.Item, None] = {} scoped_items_by_argkey = items_by_argkey[scope] diff --git a/testing/example_scripts/issue_519.py b/testing/example_scripts/issue_519.py index e44367fca04..73437ef7bdb 100644 --- a/testing/example_scripts/issue_519.py +++ b/testing/example_scripts/issue_519.py @@ -22,13 +22,13 @@ def checked_order(): assert order == [ ("issue_519.py", "fix1", "arg1v1"), ("test_one[arg1v1-arg2v1]", "fix2", "arg2v1"), - ("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"), ("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"), + ("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"), ("test_two[arg1v1-arg2v2]", "fix2", "arg2v2"), ("issue_519.py", "fix1", "arg1v2"), ("test_one[arg1v2-arg2v1]", "fix2", "arg2v1"), - ("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"), ("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"), + ("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"), ("test_two[arg1v2-arg2v2]", "fix2", "arg2v2"), ] diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 191689d1c2e..99c23e51352 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -4536,3 +4536,143 @@ def test_fixt(custom): result.assert_outcomes(errors=1) result.stdout.fnmatch_lines([expected]) assert result.ret == ExitCode.TESTS_FAILED + + +def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices( + pytester: Pytester, +): + pytester.makepyfile( + """ + import pytest + + @pytest.fixture(scope='module') + 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='module') + def test_3(param): + pass + + @pytest.mark.parametrize("param", [2,1,0], scope='module') + def test_4(param): + pass + """ + ) + result = pytester.runpytest("--collect-only") + result.stdout.re_match_lines( + [ + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + ] + ) + + +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" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + ] + ) + + +@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" ", + r" ", + r" ", + r" ", + r" ", + ] + ) From 2c270b8fbbdab040fd3c80ade5a75b0477273faa Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Fri, 21 Jul 2023 16:53:06 +0330 Subject: [PATCH 2/6] Improve a test --- testing/python/fixtures.py | 70 +++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 99c23e51352..f880f36b2f2 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -4538,51 +4538,57 @@ def test_fixt(custom): 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, ): - pytester.makepyfile( - """ - import pytest + package = pytester.mkdir("package") + package.joinpath("__init__.py").write_text("") + package.joinpath("test_a.py").write_text( + textwrap.dedent( + f"""\ + import pytest - @pytest.fixture(scope='module') - def fixture1(request): - pass + @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", [1, 0], indirect=True) + def test_0(fixture1): + pass - @pytest.mark.parametrize("fixture1",[2, 1],indirect=True) - def test_1(fixture1): - pass + @pytest.mark.parametrize("fixture1", [2, 1], indirect=True) + def test_1(fixture1): + pass - def test_2(): - pass + def test_2(): + pass - @pytest.mark.parametrize("param", [0,1,2], scope='module') - def test_3(param): - pass + @pytest.mark.parametrize("param", [0, 1, 2], scope='{scope}') + def test_3(param): + pass - @pytest.mark.parametrize("param", [2,1,0], scope='module') - def test_4(param): - pass - """ + @pytest.mark.parametrize("param", [2, 1, 0], scope='{scope}') + def test_4(param): + pass + """ + ), ) result = pytester.runpytest("--collect-only") result.stdout.re_match_lines( [ - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", + r" ", ] ) From e653fa9e3a652f80bfe54c165bbfa4518524f456 Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Fri, 21 Jul 2023 18:29:33 +0330 Subject: [PATCH 3/6] Fix a tiny bug in a test --- testing/python/fixtures.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index f880f36b2f2..8fa5a430322 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -4544,7 +4544,7 @@ def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices( pytester: Pytester, ): package = pytester.mkdir("package") - package.joinpath("__init__.py").write_text("") + package.joinpath("__init__.py").write_text("", encoding="utf-8") package.joinpath("test_a.py").write_text( textwrap.dedent( f"""\ @@ -4574,6 +4574,7 @@ def test_4(param): pass """ ), + encoding="utf-8", ) result = pytester.runpytest("--collect-only") result.stdout.re_match_lines( From fdc1b10b61e3b3880191e8d4b440a1b9fc035d78 Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Tue, 1 Aug 2023 21:24:10 +0330 Subject: [PATCH 4/6] Apply comments --- src/_pytest/fixtures.py | 36 ++++++++++++++++---------- testing/python/fixtures.py | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index f98f774c7ca..8882486b0d4 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -241,14 +241,24 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: @dataclasses.dataclass(frozen=True) -class FixtureArgKey: +class FixtureArgKeyByIndex: argname: str - param_index: Optional[int] - param_value: Optional[Hashable] + 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]: @@ -268,13 +278,6 @@ def get_parametrized_fixture_keys( if cs._arg2scope[argname] != scope: continue - param_index: Optional[int] = cs.indices[argname] - param_value = cs.params[argname] - if isinstance(cs.params[argname], Hashable): - param_index = None - else: - param_value = None - item_cls = None if scope is Scope.Session: scoped_item_path = None @@ -288,9 +291,16 @@ def get_parametrized_fixture_keys( else: assert_never(scope) - yield FixtureArgKey( - argname, param_index, param_value, scoped_item_path, item_cls - ) + param_index = cs.indices[argname] + 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. diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 8fa5a430322..1e05bf4c410 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -12,6 +12,7 @@ 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(): @@ -4683,3 +4684,54 @@ def test_3(fixture): r" ", ] ) + + +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*", + ] + ) From cd4a26a4c77677e8c5b24d4a0b77fbbb4754dba0 Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Wed, 2 Aug 2023 02:10:51 +0330 Subject: [PATCH 5/6] Separate PR#11271 from this PR --- src/_pytest/fixtures.py | 24 +--- testing/example_scripts/issue_519.py | 4 +- testing/python/fixtures.py | 161 --------------------------- 3 files changed, 4 insertions(+), 185 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 8882486b0d4..7f3d479e739 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -15,7 +15,6 @@ 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 @@ -241,24 +240,13 @@ def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: @dataclasses.dataclass(frozen=True) -class FixtureArgKeyByIndex: +class FixtureArgKey: 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]: @@ -292,15 +280,7 @@ def get_parametrized_fixture_keys( assert_never(scope) param_index = cs.indices[argname] - 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 - ) + yield FixtureArgKey(argname, param_index, scoped_item_path, item_cls) # Algorithm for sorting on a per-parametrized resource setup basis. diff --git a/testing/example_scripts/issue_519.py b/testing/example_scripts/issue_519.py index 73437ef7bdb..e44367fca04 100644 --- a/testing/example_scripts/issue_519.py +++ b/testing/example_scripts/issue_519.py @@ -22,13 +22,13 @@ def checked_order(): assert order == [ ("issue_519.py", "fix1", "arg1v1"), ("test_one[arg1v1-arg2v1]", "fix2", "arg2v1"), - ("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"), ("test_two[arg1v1-arg2v1]", "fix2", "arg2v1"), + ("test_one[arg1v1-arg2v2]", "fix2", "arg2v2"), ("test_two[arg1v1-arg2v2]", "fix2", "arg2v2"), ("issue_519.py", "fix1", "arg1v2"), ("test_one[arg1v2-arg2v1]", "fix2", "arg2v1"), - ("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"), ("test_two[arg1v2-arg2v1]", "fix2", "arg2v1"), + ("test_one[arg1v2-arg2v2]", "fix2", "arg2v2"), ("test_two[arg1v2-arg2v2]", "fix2", "arg2v2"), ] diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 1e05bf4c410..5f855e6b4d4 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -12,7 +12,6 @@ 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(): @@ -4539,115 +4538,6 @@ def test_fixt(custom): 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" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - ] - ) - - -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" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - r" ", - ] - ) - - @pytest.mark.xfail( reason="It isn't differentiated between direct `fixture` param and fixture `fixture`. Will be" "solved by adding `baseid` to `FixtureArgKey`." @@ -4684,54 +4574,3 @@ def test_3(fixture): r" ", ] ) - - -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*", - ] - ) From 5b7ebee35055f3c79297c9a622dbace77b638e8b Mon Sep 17 00:00:00 2001 From: Sadra Barikbin Date: Wed, 2 Aug 2023 11:58:33 +0330 Subject: [PATCH 6/6] Apply comments --- src/_pytest/fixtures.py | 4 ++-- testing/python/fixtures.py | 38 -------------------------------------- 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 7f3d479e739..00c2a8ef432 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -259,7 +259,7 @@ def get_parametrized_fixture_keys( pass else: cs: CallSpec2 = callspec - # cs.indices.items() is random order of argnames. Need to + # cs.indices is random order of argnames. Need to # sort this so that different calls to # get_parametrized_fixture_keys will be deterministic. for argname in sorted(cs.indices): @@ -270,7 +270,7 @@ def get_parametrized_fixture_keys( if scope is Scope.Session: scoped_item_path = None elif scope is Scope.Package: - scoped_item_path = item.path.parent + scoped_item_path = item.path elif scope is Scope.Module: scoped_item_path = item.path elif scope is Scope.Class: diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 5f855e6b4d4..191689d1c2e 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -4536,41 +4536,3 @@ def test_fixt(custom): result.assert_outcomes(errors=1) result.stdout.fnmatch_lines([expected]) assert result.ret == ExitCode.TESTS_FAILED - - -@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" ", - r" ", - r" ", - r" ", - r" ", - ] - )