[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.main import Session
from _pytest.python import CallSpec2
from _pytest.python import Metafunc
@ -152,7 +151,7 @@ def resolve_unique_values_and_their_indices_in_parametersets(
parametersets: Sequence[ParameterSet],
) -> Tuple[Dict[str, List[object]], List[Tuple[int]]]:
"""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:
::
@ -161,7 +160,7 @@ def resolve_unique_values_and_their_indices_in_parametersets(
parametersets = [("a1", "b1", "c1"), ("a1", "b2", "c1"), ("a1", "b3", "c2")]
result[0] = {"A": ["a1"], "B": ["b1", "b2", "b3"], "C": ["c1", "c2"]}
result[1] = [(0, 0, 0), (0, 1, 0), (0, 2, 1)]
result is used in reordering `indirect`ly parametrized with multiple
parameters or directly parametrized tests to keep items using the same fixture or
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.
"""
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)
unique_values: Dict[str, List[object]] = defaultdict(list)
for i, argname in enumerate(argnames):
@ -183,13 +184,17 @@ def resolve_unique_values_and_their_indices_in_parametersets(
for parameterset in parametersets:
value = parameterset.values[i]
try:
argname_indices.append(argname_value_indices_for_hashable_ones[argname][value])
except KeyError: # New unique value
argname_value_indices_for_hashable_ones[argname][value] = argvalues_count[argname]
argname_indices.append(
argname_value_indices_for_hashable_ones[argname][value]
)
except KeyError: # New unique value
argname_value_indices_for_hashable_ones[argname][
value
] = argvalues_count[argname]
argname_indices.append(argvalues_count[argname])
argvalues_count[argname] += 1
unique_values[argname].append(value)
except TypeError: # `value` is not hashable
except TypeError: # `value` is not hashable
argname_indices.append(argvalues_count[argname])
argvalues_count[argname] += 1
unique_values[argname].append(value)
@ -222,7 +227,7 @@ class FixtureArgKey:
def get_fixture_arg_key(item: nodes.Item, argname: str, scope: Scope) -> FixtureArgKey:
param_index = 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.
if isinstance(item.callspec.params[argname], Hashable):
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]
else:
item_cls = None
return FixtureArgKey(argname, param_index, param_value, scoped_item_path, item_cls)
def get_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
if hasattr(item, '_fixtureinfo'):
if hasattr(item, "_fixtureinfo"):
# sort this so that different calls to
# get_fixture_keys will be deterministic.
for argname, fixture_def in sorted(item._fixtureinfo.name2fixturedefs.items()):
# In the case item is parametrized on the `argname` with
# 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:
continue
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 key in items_by_argkey[scope]:
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:
continue
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,
functools.partial(fixturedef.finish, last_item_dependent_on_key._request)
functools.partial(
fixturedef.finish, last_item_dependent_on_key._request
),
)
return reordered_items
@ -307,7 +318,7 @@ def fix_cache_order(
argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[FixtureArgKey, None]]],
items_by_argkey: Dict[Scope, Dict[FixtureArgKey, "Deque[nodes.Item]"]],
ignore: Set[Optional[FixtureArgKey]],
current_scope: Scope
current_scope: Scope,
) -> None:
for scope in HIGH_SCOPES:
if current_scope < scope:

View File

@ -38,7 +38,6 @@ from _pytest._code.code import TerminalRepr
from _pytest._io import TerminalWriter
from _pytest._io.saferepr import saferepr
from _pytest.compat import ascii_escaped
from _pytest.compat import assert_never
from _pytest.compat import final
from _pytest.compat import get_default_arg_names
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 INSTANCE_COLLECTOR
from _pytest.deprecated import NOSE_SUPPORT_METHOD
from _pytest.fixtures import (FixtureDef,
FixtureRequest,
FuncFixtureInfo,
get_scope_node,
name2pseudofixturedef_key,
resolve_unique_values_and_their_indices_in_parametersets,)
from _pytest.fixtures import FixtureDef
from _pytest.fixtures import FixtureRequest
from _pytest.fixtures import FuncFixtureInfo
from _pytest.fixtures import get_scope_node
from _pytest.fixtures import name2pseudofixturedef_key
from _pytest.fixtures import resolve_unique_values_and_their_indices_in_parametersets
from _pytest.main import Session
from _pytest.mark import MARK_GEN
from _pytest.mark import ParameterSet
@ -81,7 +80,6 @@ from _pytest.pathlib import ImportPathMismatchError
from _pytest.pathlib import parts
from _pytest.pathlib import visit
from _pytest.scope import Scope
from _pytest.stash import StashKey
from _pytest.warning_types import PytestCollectionWarning
from _pytest.warning_types import PytestReturnNotNoneWarning
from _pytest.warning_types import PytestUnhandledCoroutineWarning
@ -505,7 +503,6 @@ class PyCollector(PyobjMixin, nodes.Collector):
if not metafunc._calls:
yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo)
else:
# Direct parametrization may have shadowed some fixtures
# so make sure we update what the function really needs.
fixtureinfo.prune_dependency_tree()
@ -1336,7 +1333,12 @@ class Metafunc:
ids = self._resolve_parameter_set_ids(
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.
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)
@ -1377,19 +1379,20 @@ class Metafunc:
params=params_values[argname],
unittest=False,
ids=None,
is_pseudo=True
is_pseudo=True,
)
arg2fixturedefs[argname] = [fixturedef]
if name2pseudofixturedef is not None:
name2pseudofixturedef[argname] = fixturedef
# 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
# of all calls.
newcalls = []
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(
argnames=argnames,
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
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(
"""
import pytest
@ -4486,24 +4488,28 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple(pytester: Pyt
def test_0(fixture):
pass
def test_1(fixture):
print("Running test_1!")
def test_2():
print("Running test_2!")
"""
)
result = pytester.runpytest("-s")
assert result.ret == 0
result.stdout.fnmatch_lines([
"*Running test_1!*",
"*Tearing down fixture!*",
"*Running test_2!*",
])
result.stdout.fnmatch_lines(
[
"*Running test_1!*",
"*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(
"""
import pytest
@ -4511,7 +4517,7 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(pytester: P
def fixture1():
yield
print("Tearing down fixture!")
@pytest.fixture(scope='module', params=[None])
def fixture2():
yield
@ -4519,36 +4525,42 @@ def test_teardown_high_scope_fixture_at_last_dependent_item_simple_2(pytester: P
def test_0(fixture1):
pass
def test_1(fixture1, fixture2):
print("Running test_1!")
def test_2():
print("Running test_2!")
"""
)
result = pytester.runpytest("-s")
assert result.ret == 0
result.stdout.fnmatch_lines([
"*Running test_1!*",
"*Tearing down fixture!*",
"*Tearing down fixture!*",
"*Running test_2!*",
])
result.stdout.fnmatch_lines(
[
"*Running test_1!*",
"*Tearing down fixture!*",
"*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(
**{
"tests/conftest.py": "import pytest\n"
+ "\n".join(
[
textwrap.dedent(f"""
textwrap.dedent(
f"""
@pytest.fixture(scope='{scope.value}', params=[None])
def {scope.value}_scope_fixture(request):
yield None
print("Tearing down {scope.value}_scope_fixture")
""")
"""
)
for scope in HIGH_SCOPES
]
),
@ -4643,10 +4655,10 @@ def test_reorder_with_nonparametrized_fixtures(pytester: Pytester):
def test_2(a):
pass
def test_3(b):
pass
def test_4(b):
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]])
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(
"""
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)
result = pytester.runpytest(path, "-s")
result.stdout.fnmatch_lines([
"*Tearing down fixture!*",
"*Running test_1!*"
])
result.stdout.fnmatch_lines(["*Tearing down fixture!*", "*Running test_1!*"])
test_module_string += """
def test_2(fixture):
pass
"""
path = pytester.makepyfile(test_module_string)
result = pytester.runpytest(path, "--new-first", "-s")
result.stdout.fnmatch_lines([
"*Tearing down fixture!*",
"*Running test_1!*",
"*Tearing down fixture!*",
])
result.stdout.fnmatch_lines(
[
"*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 = """
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):
print("Running test_1!")
assert True
def test_2():
print("Running test_2!")
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)
path = pytester.makepyfile(test_module_string.format("True"))
result = pytester.runpytest(path, "--last-failed", "-s")
result.stdout.fnmatch_lines([
"*Running test_0!*",
"*Running test_2!*",
"*Tearing down fixture!*",
])
result.stdout.fnmatch_lines(
[
"*Running test_0!*",
"*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")
def test_early_teardown_of_overridden_and_being_used_fixture(pytester: Pytester) -> None:
pytester.makeconftest(
"""
@pytest.mark.xfail(
reason="We do not attempt to tear down early the fixture that is overridden and also is used"
)
def test_early_teardown_of_overridden_and_being_used_fixture(
pytester: Pytester,
) -> None:
pytester.makeconftest(
"""
import pytest
@pytest.fixture(scope='module')
def fixture0():
yield None
print("Tearing down higher-level fixture0")
"""
)
pytester.makepyfile(
"""
)
pytester.makepyfile(
"""
import pytest
@pytest.fixture(scope='module')
def fixture0(fixture0):
yield None
@ -4771,20 +4792,24 @@ def test_early_teardown_of_overridden_and_being_used_fixture(pytester: Pytester)
def test_0(fixture0):
pass
def test_1():
print("Both `fixture0`s should have been torn down")
"""
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines(
[
"*Tearing down lower-level fixture0*",
"*Tearing down higher-level fixture0*",
"*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(
"""
import pytest
@ -4804,39 +4829,46 @@ def test_basing_fixture_argkeys_on_param_values_rather_than_on_param_indices(pyt
def test_2():
print("fixture1 should have been torn down 3 times")
@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" <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\]>",
])
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\]>",
]
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([
"*Tearing down fixture1 with param value `1`*",
"*Tearing down fixture1 with param value `0`*",
"*Tearing down fixture1 with param value `2`*",
"*fixture1 should have been torn down 3 times*",
])
result.stdout.fnmatch_lines(
[
"*Tearing down fixture1 with param value `1`*",
"*Tearing down fixture1 with param value `0`*",
"*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(
"""
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)
def test_2(fixture1, fixture2):
pass
def test_3():
print("All fixtures should have been torn down")
@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\]>",
])
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\]>",
]
)
result = pytester.runpytest("-s")
result.stdout.fnmatch_lines([
"*Tearing down fixture2 with param value `0`*",
"*Tearing down fixture2 with param value `2`*",
"*Tearing down fixture2 with param value `3`*",
"*Tearing down fixture1 with param value `a`*",
"*Tearing down fixture2 with param value `1`*",
"*Tearing down fixture1 with param value `b`*",
"*Tearing down fixture2 with param value `4`*",
"*Tearing down fixture1 with param value `c`*",
"*All fixtures should have been torn down*",
])
result.stdout.fnmatch_lines(
[
"*Tearing down fixture2 with param value `0`*",
"*Tearing down fixture2 with param value `2`*",
"*Tearing down fixture2 with param value `3`*",
"*Tearing down fixture1 with param value `a`*",
"*Tearing down fixture2 with param value `1`*",
"*Tearing down fixture1 with param value `b`*",
"*Tearing down fixture2 with param value `4`*",
"*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(
"""
import pytest
@ -4907,7 +4946,7 @@ def test_early_teardown_when_an_item_is_the_last_dependent_on_multiple_fixtures(
def fixture1():
yield None
print("Tearing down fixture1")
@pytest.fixture(scope='module')
def fixture2():
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):
print("No fixture should have been torn down")
def test_4():
print("All fixtures should have been torn down")
""")
"""
)
result = pytester.runpytest("-s")
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*",
"*Tearing down fixture3*",
"*Tearing down fixture2*",
"*Tearing down fixture1*",
"*All fixtures should have been torn down*",
])
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*",
"*Tearing down fixture3*",
"*Tearing down fixture2*",
"*Tearing down fixture1*",
"*All fixtures should have been torn down*",
]
)
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')
def test_0(param):
pass
@pytest.mark.parametrize("param", [0,1,2], scope='module')
def test_1(param):
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
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].funcargs == {}
assert metafunc._calls[1].id == "3-4"
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)])