Skip to content

Commit

Permalink
A few improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
sadra-barikbin committed Aug 1, 2023
1 parent 96be57a commit 9ac1f5c
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 60 deletions.
13 changes: 8 additions & 5 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,11 @@ def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]:
if not metafunc._calls:
yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo)
else:
# Dynamic direct parametrization may have shadowed some fixtures,
# so make sure we update what the function really needs.
# Direct parametrizations taking place in module/class-specific
# `metafunc.parametrize` calls may have shadowed some fixtures, so make sure
# we update what the function really needs a.k.a its fixture closure. Note that
# direct parametrizations using `@pytest.mark.parametrize` have already been considered
# into making the closure using `ignore_args` arg to `getfixtureclosure`.
fixtureinfo.prune_dependency_tree()

for callspec in metafunc._calls:
Expand Down Expand Up @@ -1170,7 +1173,7 @@ def get_direct_param_fixture_func(request: FixtureRequest) -> Any:
return request.param


# Used for storing artificial fixturedefs for direct parametrization.
# Used for storing pseudo fixturedefs for direct parametrization.
name2pseudofixturedef_key = StashKey[Dict[str, FixtureDef[Any]]]()


Expand Down Expand Up @@ -1330,8 +1333,8 @@ def parametrize(
object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)

# Add funcargs as fixturedefs to fixtureinfo.arg2fixturedefs by registering
# artificial FixtureDef's so that later at test execution time we can rely
# on a proper FixtureDef to exist for fixture setup.
# artificial "pseudo" FixtureDef's so that later at test execution time we can
# rely on a proper FixtureDef to exist for fixture setup.
arg2fixturedefs = self._arg2fixturedefs
node = None
# If we have a scope that is higher than function, we need
Expand Down
69 changes: 14 additions & 55 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from _pytest.compat import NOTSET
from _pytest.outcomes import fail
from _pytest.pytester import Pytester
from _pytest.python import Function
from _pytest.python import IdMaker
from _pytest.scope import Scope

Expand Down Expand Up @@ -974,16 +975,6 @@ def test_parametrize_twoargs(self) -> None:
assert metafunc._calls[1].params == dict(x=3, y=4)
assert metafunc._calls[1].id == "3-4"

@pytest.mark.xfail(reason="Will pass upon merging PR#11257")
def test_parametrize_with_duplicate_values(self) -> None:
metafunc = self.Metafunc(lambda x, y: None)
metafunc.parametrize(("x", "y"), [(1, 2), (3, 4), (1, 5), (2, 2)])
assert len(metafunc._calls) == 4
assert metafunc._calls[0].indices == dict(x=0, y=0)
assert metafunc._calls[1].indices == dict(x=1, y=1)
assert metafunc._calls[2].indices == dict(x=0, y=2)
assert metafunc._calls[3].indices == dict(x=2, y=0)

def test_high_scoped_parametrize_reordering(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
Expand Down Expand Up @@ -1018,36 +1009,6 @@ def test3(arg1):
]
)

@pytest.mark.xfail(reason="Will pass upon merging PR#11257")
def test_high_scoped_parametrize_with_duplicate_values_reordering(
self, pytester: Pytester
) -> None:
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(fixture1, fixture2):
pass
"""
)
result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines(
[
r" <Function test\[a-0\]>",
r" <Function test\[a-2\]>",
r" <Function test\[b-1\]>",
]
)

def test_parametrize_multiple_times(self, pytester: Pytester) -> None:
pytester.makepyfile(
"""
Expand Down Expand Up @@ -1590,29 +1551,27 @@ def test_it(x): pass
def test_parametrize_module_level_test_with_class_scope(
self, pytester: Pytester
) -> None:
pytester.makepyfile(
module = pytester.makepyfile(
"""
import pytest
@pytest.fixture
def item(request):
return request._pyfuncitem
fixturedef = None
@pytest.mark.parametrize("x", [0, 1], scope="class")
def test_1(item, x):
global fixturedef
fixturedef = item._fixtureinfo.name2fixturedefs['x'][-1]
def test_1(x):
pass
@pytest.mark.parametrize("x", [1, 2], scope="module")
def test_2(item, x):
global fixturedef
assert fixturedef == item._fixtureinfo.name2fixturedefs['x'][-1]
def test_2(x):
pass
"""
)
result = pytester.runpytest()
assert result.ret == 0
test_1_0, _, test_2_0, _ = pytester.genitems((pytester.getmodulecol(module),))
test_1_fixture_x = cast(Function, test_1_0)._fixtureinfo.name2fixturedefs["x"][
-1
]
test_2_fixture_x = cast(Function, test_2_0)._fixtureinfo.name2fixturedefs["x"][
-1
]
assert test_1_fixture_x == test_2_fixture_x


class TestMetafuncFunctionalAuto:
Expand Down

0 comments on commit 9ac1f5c

Please sign in to comment.