[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot] 2023-03-26 18:55:58 +00:00
parent e6c01ca71a
commit c4edd5408f
4 changed files with 210 additions and 153 deletions

View File

@ -72,7 +72,6 @@ if TYPE_CHECKING:
from _pytest.scope import _ScopeName from _pytest.scope import _ScopeName
from _pytest.main import Session from _pytest.main import Session
from _pytest.python import CallSpec2
from _pytest.python import Metafunc from _pytest.python import Metafunc
@ -152,7 +151,7 @@ def resolve_unique_values_and_their_indices_in_parametersets(
parametersets: Sequence[ParameterSet], parametersets: Sequence[ParameterSet],
) -> Tuple[Dict[str, List[object]], List[Tuple[int]]]: ) -> Tuple[Dict[str, List[object]], List[Tuple[int]]]:
"""Resolve unique values and their indices in parameter sets. The index of a value """Resolve unique values and their indices in parameter sets. The index of a value
is determined by when it appears in the possible values for the first time. is determined by when it appears in the possible values for the first time.
For example, given ``argnames`` and ``parametersets`` below, the result would be: For example, given ``argnames`` and ``parametersets`` below, the result would be:
:: ::
@ -161,7 +160,7 @@ def resolve_unique_values_and_their_indices_in_parametersets(
parametersets = [("a1", "b1", "c1"), ("a1", "b2", "c1"), ("a1", "b3", "c2")] parametersets = [("a1", "b1", "c1"), ("a1", "b2", "c1"), ("a1", "b3", "c2")]
result[0] = {"A": ["a1"], "B": ["b1", "b2", "b3"], "C": ["c1", "c2"]} result[0] = {"A": ["a1"], "B": ["b1", "b2", "b3"], "C": ["c1", "c2"]}
result[1] = [(0, 0, 0), (0, 1, 0), (0, 2, 1)] result[1] = [(0, 0, 0), (0, 1, 0), (0, 2, 1)]
result is used in reordering `indirect`ly parametrized with multiple result is used in reordering `indirect`ly parametrized with multiple
parameters or directly parametrized tests to keep items using the same fixture or parameters or directly parametrized tests to keep items using the same fixture or
pseudo-fixture values respectively, close together. pseudo-fixture values respectively, close together.
@ -175,7 +174,9 @@ def resolve_unique_values_and_their_indices_in_parametersets(
Tuple of unique parameter values and their indices in parametersets. Tuple of unique parameter values and their indices in parametersets.
""" """
indices = [] indices = []
argname_value_indices_for_hashable_ones: Dict[str, Dict[object, int]] = defaultdict(dict) argname_value_indices_for_hashable_ones: Dict[str, Dict[object, int]] = defaultdict(
dict
)
argvalues_count: Dict[str, int] = defaultdict(lambda: 0) argvalues_count: Dict[str, int] = defaultdict(lambda: 0)
unique_values: Dict[str, List[object]] = defaultdict(list) unique_values: Dict[str, List[object]] = defaultdict(list)
for i, argname in enumerate(argnames): for i, argname in enumerate(argnames):
@ -183,13 +184,17 @@ def resolve_unique_values_and_their_indices_in_parametersets(
for parameterset in parametersets: for parameterset in parametersets:
value = parameterset.values[i] value = parameterset.values[i]
try: try:
argname_indices.append(argname_value_indices_for_hashable_ones[argname][value]) argname_indices.append(
except KeyError: # New unique value argname_value_indices_for_hashable_ones[argname][value]
argname_value_indices_for_hashable_ones[argname][value] = argvalues_count[argname] )
except KeyError: # New unique value
argname_value_indices_for_hashable_ones[argname][
value
] = argvalues_count[argname]
argname_indices.append(argvalues_count[argname]) argname_indices.append(argvalues_count[argname])
argvalues_count[argname] += 1 argvalues_count[argname] += 1
unique_values[argname].append(value) unique_values[argname].append(value)
except TypeError: # `value` is not hashable except TypeError: # `value` is not hashable
argname_indices.append(argvalues_count[argname]) argname_indices.append(argvalues_count[argname])
argvalues_count[argname] += 1 argvalues_count[argname] += 1
unique_values[argname].append(value) unique_values[argname].append(value)
@ -222,7 +227,7 @@ class FixtureArgKey:
def get_fixture_arg_key(item: nodes.Item, argname: str, scope: Scope) -> FixtureArgKey: def get_fixture_arg_key(item: nodes.Item, argname: str, scope: Scope) -> FixtureArgKey:
param_index = None param_index = None
param_value = None param_value = None
if hasattr(item, 'callspec') and argname in item.callspec.params: if hasattr(item, "callspec") and argname in item.callspec.params:
# Fixture is parametrized. # Fixture is parametrized.
if isinstance(item.callspec.params[argname], Hashable): if isinstance(item.callspec.params[argname], Hashable):
param_value = item.callspec.params[argname] param_value = item.callspec.params[argname]
@ -242,21 +247,21 @@ def get_fixture_arg_key(item: nodes.Item, argname: str, scope: Scope) -> Fixture
item_cls = item.cls # type: ignore[attr-defined] item_cls = item.cls # type: ignore[attr-defined]
else: else:
item_cls = None item_cls = None
return FixtureArgKey(argname, param_index, param_value, scoped_item_path, item_cls) return FixtureArgKey(argname, param_index, param_value, scoped_item_path, item_cls)
def get_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[FixtureArgKey]: def get_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[FixtureArgKey]:
"""Return list of keys for all parametrized arguments which match """Return list of keys for all parametrized arguments which match
the specified scope.""" the specified scope."""
assert scope is not Scope.Function assert scope is not Scope.Function
if hasattr(item, '_fixtureinfo'): if hasattr(item, "_fixtureinfo"):
# sort this so that different calls to # sort this so that different calls to
# get_fixture_keys will be deterministic. # get_fixture_keys will be deterministic.
for argname, fixture_def in sorted(item._fixtureinfo.name2fixturedefs.items()): for argname, fixture_def in sorted(item._fixtureinfo.name2fixturedefs.items()):
# In the case item is parametrized on the `argname` with # In the case item is parametrized on the `argname` with
# a scope, it overrides that of the fixture. # a scope, it overrides that of the fixture.
if hasattr(item, 'callspec') and argname in item.callspec._arg2scope: if hasattr(item, "callspec") and argname in item.callspec._arg2scope:
if item.callspec._arg2scope[argname] != scope: if item.callspec._arg2scope[argname] != scope:
continue continue
elif fixture_def[-1]._scope != scope: elif fixture_def[-1]._scope != scope:
@ -291,13 +296,19 @@ def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]:
for scope in reversed(HIGH_SCOPES): for scope in reversed(HIGH_SCOPES):
for key in items_by_argkey[scope]: for key in items_by_argkey[scope]:
last_item_dependent_on_key = items_by_argkey[scope][key].pop() last_item_dependent_on_key = items_by_argkey[scope][key].pop()
fixturedef = last_item_dependent_on_key._fixtureinfo.name2fixturedefs[key.argname][-1] fixturedef = last_item_dependent_on_key._fixtureinfo.name2fixturedefs[
key.argname
][-1]
if fixturedef.is_pseudo: if fixturedef.is_pseudo:
continue continue
last_item_dependent_on_key.teardown = functools.partial( last_item_dependent_on_key.teardown = functools.partial(
lambda other_finalizers, new_finalizer: [finalizer() for finalizer in (new_finalizer, other_finalizers)], lambda other_finalizers, new_finalizer: [
finalizer() for finalizer in (new_finalizer, other_finalizers)
],
last_item_dependent_on_key.teardown, last_item_dependent_on_key.teardown,
functools.partial(fixturedef.finish, last_item_dependent_on_key._request) functools.partial(
fixturedef.finish, last_item_dependent_on_key._request
),
) )
return reordered_items return reordered_items
@ -307,7 +318,7 @@ def fix_cache_order(
argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]], argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]],
items_by_argkey: Dict[Scope, Dict[FixtureArgKey, "Deque[nodes.Item]"]], items_by_argkey: Dict[Scope, Dict[FixtureArgKey, "Deque[nodes.Item]"]],
ignore: Set[Optional[FixtureArgKey]], ignore: Set[Optional[FixtureArgKey]],
current_scope: Scope current_scope: Scope,
) -> None: ) -> None:
for scope in HIGH_SCOPES: for scope in HIGH_SCOPES:
if current_scope < scope: if current_scope < scope:

View File

@ -38,7 +38,6 @@ from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter from _pytest._io import TerminalWriter
from _pytest._io.saferepr import saferepr from _pytest._io.saferepr import saferepr
from _pytest.compat import ascii_escaped from _pytest.compat import ascii_escaped
from _pytest.compat import assert_never
from _pytest.compat import final from _pytest.compat import final
from _pytest.compat import get_default_arg_names from _pytest.compat import get_default_arg_names
from _pytest.compat import get_real_func from _pytest.compat import get_real_func
@ -59,12 +58,12 @@ from _pytest.deprecated import check_ispytest
from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
from _pytest.deprecated import INSTANCE_COLLECTOR from _pytest.deprecated import INSTANCE_COLLECTOR
from _pytest.deprecated import NOSE_SUPPORT_METHOD from _pytest.deprecated import NOSE_SUPPORT_METHOD
from _pytest.fixtures import (FixtureDef, from _pytest.fixtures import FixtureDef
FixtureRequest, from _pytest.fixtures import FixtureRequest
FuncFixtureInfo, from _pytest.fixtures import FuncFixtureInfo
get_scope_node, from _pytest.fixtures import get_scope_node
name2pseudofixturedef_key, from _pytest.fixtures import name2pseudofixturedef_key
resolve_unique_values_and_their_indices_in_parametersets,) from _pytest.fixtures import resolve_unique_values_and_their_indices_in_parametersets
from _pytest.main import Session from _pytest.main import Session
from _pytest.mark import MARK_GEN from _pytest.mark import MARK_GEN
from _pytest.mark import ParameterSet from _pytest.mark import ParameterSet
@ -81,7 +80,6 @@ from _pytest.pathlib import ImportPathMismatchError
from _pytest.pathlib import parts from _pytest.pathlib import parts
from _pytest.pathlib import visit from _pytest.pathlib import visit
from _pytest.scope import Scope from _pytest.scope import Scope
from _pytest.stash import StashKey
from _pytest.warning_types import PytestCollectionWarning from _pytest.warning_types import PytestCollectionWarning
from _pytest.warning_types import PytestReturnNotNoneWarning from _pytest.warning_types import PytestReturnNotNoneWarning
from _pytest.warning_types import PytestUnhandledCoroutineWarning from _pytest.warning_types import PytestUnhandledCoroutineWarning
@ -505,7 +503,6 @@ class PyCollector(PyobjMixin, nodes.Collector):
if not metafunc._calls: if not metafunc._calls:
yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo) yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo)
else: else:
# Direct parametrization may have shadowed some fixtures # Direct parametrization may have shadowed some fixtures
# so make sure we update what the function really needs. # so make sure we update what the function really needs.
fixtureinfo.prune_dependency_tree() fixtureinfo.prune_dependency_tree()
@ -1336,7 +1333,12 @@ class Metafunc:
ids = self._resolve_parameter_set_ids( ids = self._resolve_parameter_set_ids(
argnames, ids, parametersets, nodeid=self.definition.nodeid argnames, ids, parametersets, nodeid=self.definition.nodeid
) )
params_values, param_indices_list = resolve_unique_values_and_their_indices_in_parametersets(argnames, parametersets) (
params_values,
param_indices_list,
) = resolve_unique_values_and_their_indices_in_parametersets(
argnames, parametersets
)
# Store used (possibly generated) ids with parametrize Marks. # Store used (possibly generated) ids with parametrize Marks.
if _param_mark and _param_mark._param_ids_from and generated_ids is None: if _param_mark and _param_mark._param_ids_from and generated_ids is None:
object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids) object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids)
@ -1377,19 +1379,20 @@ class Metafunc:
params=params_values[argname], params=params_values[argname],
unittest=False, unittest=False,
ids=None, ids=None,
is_pseudo=True is_pseudo=True,
) )
arg2fixturedefs[argname] = [fixturedef] arg2fixturedefs[argname] = [fixturedef]
if name2pseudofixturedef is not None: if name2pseudofixturedef is not None:
name2pseudofixturedef[argname] = fixturedef name2pseudofixturedef[argname] = fixturedef
# Create the new calls: if we are parametrize() multiple times (by applying the decorator # Create the new calls: if we are parametrize() multiple times (by applying the decorator
# more than once) then we accumulate those calls generating the cartesian product # more than once) then we accumulate those calls generating the cartesian product
# of all calls. # of all calls.
newcalls = [] newcalls = []
for callspec in self._calls or [CallSpec2()]: for callspec in self._calls or [CallSpec2()]:
for param_id, param_set, param_indices in zip(ids, parametersets, param_indices_list): for param_id, param_set, param_indices in zip(
ids, parametersets, param_indices_list
):
newcallspec = callspec.setmulti( newcallspec = callspec.setmulti(
argnames=argnames, argnames=argnames,
valset=param_set.values, valset=param_set.values,

View File

@ -4475,7 +4475,9 @@ def test_yield_fixture_with_no_value(pytester: Pytester) -> None:
assert result.ret == ExitCode.TESTS_FAILED assert result.ret == ExitCode.TESTS_FAILED
def test_teardown_high_scope_fixture_at_last_dependent_item_simple(pytester: Pytester) -> None: def test_teardown_high_scope_fixture_at_last_dependent_item_simple(
pytester: Pytester,
) -> None:
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -4486,24 +4488,28 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple(pytester: Pyt
def test_0(fixture): def test_0(fixture):
pass pass
def test_1(fixture): def test_1(fixture):
print("Running test_1!") print("Running test_1!")
def test_2(): def test_2():
print("Running test_2!") print("Running test_2!")
""" """
) )
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Running test_1!*", [
"*Tearing down fixture!*", "*Running test_1!*",
"*Running test_2!*", "*Tearing down fixture!*",
]) "*Running test_2!*",
]
)
def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(pytester: Pytester) -> None: def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(
pytester: Pytester,
) -> None:
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -4511,7 +4517,7 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(pytester: P
def fixture1(): def fixture1():
yield yield
print("Tearing down fixture!") print("Tearing down fixture!")
@pytest.fixture(scope='module', params=[None]) @pytest.fixture(scope='module', params=[None])
def fixture2(): def fixture2():
yield yield
@ -4519,36 +4525,42 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(pytester: P
def test_0(fixture1): def test_0(fixture1):
pass pass
def test_1(fixture1, fixture2): def test_1(fixture1, fixture2):
print("Running test_1!") print("Running test_1!")
def test_2(): def test_2():
print("Running test_2!") print("Running test_2!")
""" """
) )
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Running test_1!*", [
"*Tearing down fixture!*", "*Running test_1!*",
"*Tearing down fixture!*", "*Tearing down fixture!*",
"*Running test_2!*", "*Tearing down fixture!*",
]) "*Running test_2!*",
]
)
def test_teardown_high_scope_fixture_at_last_dependent_item_complex(pytester: Pytester) -> None: def test_teardown_high_scope_fixture_at_last_dependent_item_complex(
pytester: Pytester,
) -> None:
pytester.makepyfile( pytester.makepyfile(
**{ **{
"tests/conftest.py": "import pytest\n" "tests/conftest.py": "import pytest\n"
+ "\n".join( + "\n".join(
[ [
textwrap.dedent(f""" textwrap.dedent(
f"""
@pytest.fixture(scope='{scope.value}', params=[None]) @pytest.fixture(scope='{scope.value}', params=[None])
def {scope.value}_scope_fixture(request): def {scope.value}_scope_fixture(request):
yield None yield None
print("Tearing down {scope.value}_scope_fixture") print("Tearing down {scope.value}_scope_fixture")
""") """
)
for scope in HIGH_SCOPES for scope in HIGH_SCOPES
] ]
), ),
@ -4643,10 +4655,10 @@ def test_reorder_with_nonparametrized_fixtures(pytester: Pytester):
def test_2(a): def test_2(a):
pass pass
def test_3(b): def test_3(b):
pass pass
def test_4(b): def test_4(b):
pass pass
""" """
@ -4655,7 +4667,9 @@ def test_reorder_with_nonparametrized_fixtures(pytester: Pytester):
result.stdout.fnmatch_lines([f"*test_{i}*" for i in [0, 2, 1, 3, 4]]) result.stdout.fnmatch_lines([f"*test_{i}*" for i in [0, 2, 1, 3, 4]])
def test_reorder_with_both_parametrized_and_nonparametrized_fixtures(pytester: Pytester): def test_reorder_with_both_parametrized_and_nonparametrized_fixtures(
pytester: Pytester,
):
path = pytester.makepyfile( path = pytester.makepyfile(
""" """
import pytest import pytest
@ -4699,24 +4713,25 @@ def test_add_new_test_dependent_on_a_fixuture_and_use_nfplugin(pytester: Pyteste
""" """
path = pytester.makepyfile(test_module_string) path = pytester.makepyfile(test_module_string)
result = pytester.runpytest(path, "-s") result = pytester.runpytest(path, "-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(["*Tearing down fixture!*", "*Running test_1!*"])
"*Tearing down fixture!*",
"*Running test_1!*"
])
test_module_string += """ test_module_string += """
def test_2(fixture): def test_2(fixture):
pass pass
""" """
path = pytester.makepyfile(test_module_string) path = pytester.makepyfile(test_module_string)
result = pytester.runpytest(path, "--new-first", "-s") result = pytester.runpytest(path, "--new-first", "-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Tearing down fixture!*", [
"*Running test_1!*", "*Tearing down fixture!*",
"*Tearing down fixture!*", "*Running test_1!*",
]) "*Tearing down fixture!*",
]
)
def test_last_dependent_test_on_a_fixture_is_in_last_failed_using_lfplugin(pytester: Pytester): def test_last_dependent_test_on_a_fixture_is_in_last_failed_using_lfplugin(
pytester: Pytester,
):
test_module_string = """ test_module_string = """
import pytest import pytest
@ -4732,7 +4747,7 @@ def test_last_dependent_test_on_a_fixture_is_in_last_failed_using_lfplugin(pytes
def test_1(fixture): def test_1(fixture):
print("Running test_1!") print("Running test_1!")
assert True assert True
def test_2(): def test_2():
print("Running test_2!") print("Running test_2!")
assert {0} assert {0}
@ -4741,29 +4756,35 @@ def test_last_dependent_test_on_a_fixture_is_in_last_failed_using_lfplugin(pytes
result = pytester.runpytest(path) result = pytester.runpytest(path)
path = pytester.makepyfile(test_module_string.format("True")) path = pytester.makepyfile(test_module_string.format("True"))
result = pytester.runpytest(path, "--last-failed", "-s") result = pytester.runpytest(path, "--last-failed", "-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Running test_0!*", [
"*Running test_2!*", "*Running test_0!*",
"*Tearing down fixture!*", "*Running test_2!*",
]) "*Tearing down fixture!*",
]
)
@pytest.mark.xfail(reason="We do not attempt to tear down early the fixture that is overridden and also is used") @pytest.mark.xfail(
def test_early_teardown_of_overridden_and_being_used_fixture(pytester: Pytester) -> None: reason="We do not attempt to tear down early the fixture that is overridden and also is used"
pytester.makeconftest( )
""" def test_early_teardown_of_overridden_and_being_used_fixture(
pytester: Pytester,
) -> None:
pytester.makeconftest(
"""
import pytest import pytest
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def fixture0(): def fixture0():
yield None yield None
print("Tearing down higher-level fixture0") print("Tearing down higher-level fixture0")
""" """
) )
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def fixture0(fixture0): def fixture0(fixture0):
yield None yield None
@ -4771,20 +4792,24 @@ def test_early_teardown_of_overridden_and_being_used_fixture(pytester: Pytester)
def test_0(fixture0): def test_0(fixture0):
pass pass
def test_1(): def test_1():
print("Both `fixture0`s should have been torn down") print("Both `fixture0`s should have been torn down")
""" """
) )
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
[
"*Tearing down lower-level fixture0*", "*Tearing down lower-level fixture0*",
"*Tearing down higher-level fixture0*", "*Tearing down higher-level fixture0*",
"*Both `fixture0`s should have been torn down*", "*Both `fixture0`s should have been torn down*",
]) ]
)
def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices(pytester: Pytester): def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices(
pytester: Pytester,
):
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -4804,39 +4829,46 @@ def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices(pyt
def test_2(): def test_2():
print("fixture1 should have been torn down 3 times") print("fixture1 should have been torn down 3 times")
@pytest.mark.parametrize("param", [0,1,2], scope='module') @pytest.mark.parametrize("param", [0,1,2], scope='module')
def test_3(param): def test_3(param):
pass pass
@pytest.mark.parametrize("param", [2,1,0], scope='module') @pytest.mark.parametrize("param", [2,1,0], scope='module')
def test_4(param): def test_4(param):
pass pass
""") """
)
result = pytester.runpytest("--collect-only") result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines([ result.stdout.re_match_lines(
r" <Function test_0\[1\]>", [
r" <Function test_1\[1\]>", r" <Function test_0\[1\]>",
r" <Function test_0\[0\]>", r" <Function test_1\[1\]>",
r" <Function test_1\[2\]>", r" <Function test_0\[0\]>",
r" <Function test_2>", r" <Function test_1\[2\]>",
r" <Function test_3\[0\]>", r" <Function test_2>",
r" <Function test_4\[0\]>", r" <Function test_3\[0\]>",
r" <Function test_3\[1\]>", r" <Function test_4\[0\]>",
r" <Function test_4\[1\]>", r" <Function test_3\[1\]>",
r" <Function test_3\[2\]>", r" <Function test_4\[1\]>",
r" <Function test_4\[2\]>", r" <Function test_3\[2\]>",
]) r" <Function test_4\[2\]>",
]
)
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Tearing down fixture1 with param value `1`*", [
"*Tearing down fixture1 with param value `0`*", "*Tearing down fixture1 with param value `1`*",
"*Tearing down fixture1 with param value `2`*", "*Tearing down fixture1 with param value `0`*",
"*fixture1 should have been torn down 3 times*", "*Tearing down fixture1 with param value `2`*",
]) "*fixture1 should have been torn down 3 times*",
]
)
def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices_2(pytester: Pytester): def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices_2(
pytester: Pytester,
):
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -4858,47 +4890,54 @@ def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices_2(p
@pytest.mark.parametrize("fixture1, fixture2", [("c", 4), ("a", 3)], indirect=True) @pytest.mark.parametrize("fixture1, fixture2", [("c", 4), ("a", 3)], indirect=True)
def test_2(fixture1, fixture2): def test_2(fixture1, fixture2):
pass pass
def test_3(): def test_3():
print("All fixtures should have been torn down") print("All fixtures should have been torn down")
@pytest.mark.parametrize("param1, param2", [("a", 0), ("b", 1), ("a", 2)], scope='module') @pytest.mark.parametrize("param1, param2", [("a", 0), ("b", 1), ("a", 2)], scope='module')
def test_4(param1, param2): def test_4(param1, param2):
pass pass
@pytest.mark.parametrize("param1, param2", [("c", 4), ("a", 3)], scope='module') @pytest.mark.parametrize("param1, param2", [("c", 4), ("a", 3)], scope='module')
def test_5(param1, param2): def test_5(param1, param2):
pass pass
""") """
)
result = pytester.runpytest("--collect-only") result = pytester.runpytest("--collect-only")
result.stdout.re_match_lines([ result.stdout.re_match_lines(
r" <Function test_1\[a-0\]>", [
r" <Function test_1\[a-2\]>", r" <Function test_1\[a-0\]>",
r" <Function test_2\[a-3\]>", r" <Function test_1\[a-2\]>",
r" <Function test_1\[b-1\]>", r" <Function test_2\[a-3\]>",
r" <Function test_2\[c-4\]>", r" <Function test_1\[b-1\]>",
r" <Function test_3>", r" <Function test_2\[c-4\]>",
r" <Function test_4\[a-0\]>", r" <Function test_3>",
r" <Function test_4\[a-2\]>", r" <Function test_4\[a-0\]>",
r" <Function test_5\[a-3\]>", r" <Function test_4\[a-2\]>",
r" <Function test_4\[b-1\]>", r" <Function test_5\[a-3\]>",
r" <Function test_5\[c-4\]>", r" <Function test_4\[b-1\]>",
]) r" <Function test_5\[c-4\]>",
]
)
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*Tearing down fixture2 with param value `0`*", [
"*Tearing down fixture2 with param value `2`*", "*Tearing down fixture2 with param value `0`*",
"*Tearing down fixture2 with param value `3`*", "*Tearing down fixture2 with param value `2`*",
"*Tearing down fixture1 with param value `a`*", "*Tearing down fixture2 with param value `3`*",
"*Tearing down fixture2 with param value `1`*", "*Tearing down fixture1 with param value `a`*",
"*Tearing down fixture1 with param value `b`*", "*Tearing down fixture2 with param value `1`*",
"*Tearing down fixture2 with param value `4`*", "*Tearing down fixture1 with param value `b`*",
"*Tearing down fixture1 with param value `c`*", "*Tearing down fixture2 with param value `4`*",
"*All fixtures should have been torn down*", "*Tearing down fixture1 with param value `c`*",
]) "*All fixtures should have been torn down*",
]
)
def test_early_teardown_when_an_item_is_the_last_dependent_on_multiple_fixtures(pytester: Pytester): def test_early_teardown_when_an_item_is_the_last_dependent_on_multiple_fixtures(
pytester: Pytester,
):
pytester.makepyfile( pytester.makepyfile(
""" """
import pytest import pytest
@ -4907,7 +4946,7 @@ def test_early_teardown_when_an_item_is_the_last_dependent_on_multiple_fixtures(
def fixture1(): def fixture1():
yield None yield None
print("Tearing down fixture1") print("Tearing down fixture1")
@pytest.fixture(scope='module') @pytest.fixture(scope='module')
def fixture2(): def fixture2():
yield None yield None
@ -4929,21 +4968,24 @@ def test_early_teardown_when_an_item_is_the_last_dependent_on_multiple_fixtures(
def test_3(fixture1, fixture2, fixture3): def test_3(fixture1, fixture2, fixture3):
print("No fixture should have been torn down") print("No fixture should have been torn down")
def test_4(): def test_4():
print("All fixtures should have been torn down") print("All fixtures should have been torn down")
""") """
)
result = pytester.runpytest("-s") result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines(
"*No fixture should have been torn down*", [
"*No fixture should have been torn down*", "*No fixture should have been torn down*",
"*No fixture should have been torn down*", "*No fixture should have been torn down*",
"*No fixture should have been torn down*", "*No fixture should have been torn down*",
"*Tearing down fixture3*", "*No fixture should have been torn down*",
"*Tearing down fixture2*", "*Tearing down fixture3*",
"*Tearing down fixture1*", "*Tearing down fixture2*",
"*All fixtures should have been torn down*", "*Tearing down fixture1*",
]) "*All fixtures should have been torn down*",
]
)
def test_early_teardown_does_not_occur_for_pseudo_fixtures(pytester: Pytester) -> None: def test_early_teardown_does_not_occur_for_pseudo_fixtures(pytester: Pytester) -> None:
@ -4958,7 +5000,7 @@ def test_early_teardown_does_not_occur_for_pseudo_fixtures(pytester: Pytester) -
@pytest.mark.parametrize("param", [0,1,2], scope='module') @pytest.mark.parametrize("param", [0,1,2], scope='module')
def test_0(param): def test_0(param):
pass pass
@pytest.mark.parametrize("param", [0,1,2], scope='module') @pytest.mark.parametrize("param", [0,1,2], scope='module')
def test_1(param): def test_1(param):
pass pass
@ -4966,4 +5008,5 @@ def test_early_teardown_does_not_occur_for_pseudo_fixtures(pytester: Pytester) -
) )
items = pytester.inline_run().getcalls("pytest_collection_finish")[0].session.items items = pytester.inline_run().getcalls("pytest_collection_finish")[0].session.items
import functools import functools
assert not any([isinstance(item.teardown, functools.partial) for item in items])
assert not any([isinstance(item.teardown, functools.partial) for item in items])

View File

@ -982,7 +982,7 @@ class TestMetafunc:
assert metafunc._calls[1].params == dict(x=3, y=4) assert metafunc._calls[1].params == dict(x=3, y=4)
assert metafunc._calls[1].funcargs == {} assert metafunc._calls[1].funcargs == {}
assert metafunc._calls[1].id == "3-4" assert metafunc._calls[1].id == "3-4"
def test_parametrize_with_duplicate_values(self) -> None: def test_parametrize_with_duplicate_values(self) -> None:
metafunc = self.Metafunc(lambda x, y: None) metafunc = self.Metafunc(lambda x, y: None)
metafunc.parametrize(("x", "y"), [(1, 2), (3, 4), (1, 5), (2, 2)]) metafunc.parametrize(("x", "y"), [(1, 2), (3, 4), (1, 5), (2, 2)])