Do the improvement
This commit is contained in:
parent
9791e1d5a2
commit
ae5849f362
|
@ -1136,12 +1136,12 @@ class CallSpec2:
|
||||||
id: str,
|
id: str,
|
||||||
marks: Iterable[Union[Mark, MarkDecorator]],
|
marks: Iterable[Union[Mark, MarkDecorator]],
|
||||||
scope: Scope,
|
scope: Scope,
|
||||||
param_index: int,
|
param_indices: Tuple[int, ...],
|
||||||
) -> "CallSpec2":
|
) -> "CallSpec2":
|
||||||
params = self.params.copy()
|
params = self.params.copy()
|
||||||
indices = self.indices.copy()
|
indices = self.indices.copy()
|
||||||
arg2scope = self._arg2scope.copy()
|
arg2scope = self._arg2scope.copy()
|
||||||
for arg, val in zip(argnames, valset):
|
for arg, val, param_index in zip(argnames, valset, param_indices):
|
||||||
if arg in params:
|
if arg in params:
|
||||||
raise ValueError(f"duplicate {arg!r}")
|
raise ValueError(f"duplicate {arg!r}")
|
||||||
params[arg] = val
|
params[arg] = val
|
||||||
|
@ -1170,6 +1170,54 @@ def get_direct_param_fixture_func(request: FixtureRequest) -> Any:
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_values_indices_in_parametersets(
|
||||||
|
argnames: Sequence[str],
|
||||||
|
parametersets: Sequence[ParameterSet],
|
||||||
|
) -> List[Tuple[int, ...]]:
|
||||||
|
"""Resolve indices of the values in parameter sets. The index of a value is determined by
|
||||||
|
where the value first appears in the existing values of the argname. For example, given
|
||||||
|
``argnames`` and ``parametersets`` below, the result would be:
|
||||||
|
::
|
||||||
|
argnames = ["A", "B", "C"]
|
||||||
|
parametersets = [("a1", "b1", "c1"), ("a1", "b2", "c1"), ("a1", "b3", "c2")]
|
||||||
|
result = [(0, 0, 0), (0, 1, 0), (0, 2, 1)]
|
||||||
|
|
||||||
|
result is used in reordering tests to keep items using the same fixture close together.
|
||||||
|
|
||||||
|
:param argnames:
|
||||||
|
Argument names passed to ``metafunc.parametrize()``.
|
||||||
|
:param parametersets:
|
||||||
|
The parameter sets, each containing a set of values corresponding
|
||||||
|
to ``argnames``.
|
||||||
|
:returns:
|
||||||
|
List of tuples of indices, each tuple for a parameter set.
|
||||||
|
"""
|
||||||
|
indices = []
|
||||||
|
argname_value_indices_for_hashable_ones: Dict[str, Dict[object, int]] = defaultdict(
|
||||||
|
dict
|
||||||
|
)
|
||||||
|
argvalues_count: Dict[str, int] = defaultdict(lambda: 0)
|
||||||
|
for i, argname in enumerate(argnames):
|
||||||
|
argname_indices = []
|
||||||
|
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(argvalues_count[argname])
|
||||||
|
argvalues_count[argname] += 1
|
||||||
|
except TypeError: # `value` is not hashable
|
||||||
|
argname_indices.append(argvalues_count[argname])
|
||||||
|
argvalues_count[argname] += 1
|
||||||
|
indices.append(argname_indices)
|
||||||
|
return list(cast(Iterable[Tuple[int]], zip(*indices)))
|
||||||
|
|
||||||
|
|
||||||
# Used for storing artificial fixturedefs for direct parametrization.
|
# Used for storing artificial fixturedefs for direct parametrization.
|
||||||
name2pseudofixturedef_key = StashKey[Dict[str, FixtureDef[Any]]]()
|
name2pseudofixturedef_key = StashKey[Dict[str, FixtureDef[Any]]]()
|
||||||
|
|
||||||
|
@ -1324,7 +1372,9 @@ 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
|
||||||
)
|
)
|
||||||
|
param_indices_list = resolve_values_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)
|
||||||
|
@ -1387,8 +1437,8 @@ class Metafunc:
|
||||||
# of all calls.
|
# of all calls.
|
||||||
newcalls = []
|
newcalls = []
|
||||||
for callspec in self._calls or [CallSpec2()]:
|
for callspec in self._calls or [CallSpec2()]:
|
||||||
for param_index, (param_id, param_set) in enumerate(
|
for param_id, param_set, param_indices in zip(
|
||||||
zip(ids, parametersets)
|
ids, parametersets, param_indices_list
|
||||||
):
|
):
|
||||||
newcallspec = callspec.setmulti(
|
newcallspec = callspec.setmulti(
|
||||||
argnames=argnames,
|
argnames=argnames,
|
||||||
|
@ -1396,7 +1446,7 @@ class Metafunc:
|
||||||
id=param_id,
|
id=param_id,
|
||||||
marks=param_set.marks,
|
marks=param_set.marks,
|
||||||
scope=scope_,
|
scope=scope_,
|
||||||
param_index=param_index,
|
param_indices=param_indices,
|
||||||
)
|
)
|
||||||
newcalls.append(newcallspec)
|
newcalls.append(newcallspec)
|
||||||
self._calls = newcalls
|
self._calls = newcalls
|
||||||
|
|
|
@ -974,7 +974,6 @@ 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].id == "3-4"
|
assert metafunc._calls[1].id == "3-4"
|
||||||
|
|
||||||
@pytest.mark.xfail(reason="Will pass upon merging PR#")
|
|
||||||
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)])
|
||||||
|
@ -1018,7 +1017,6 @@ class TestMetafunc:
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@pytest.mark.xfail(reason="Will pass upon merging PR#")
|
|
||||||
def test_high_scoped_parametrize_with_duplicate_values_reordering(
|
def test_high_scoped_parametrize_with_duplicate_values_reordering(
|
||||||
self, pytester: Pytester
|
self, pytester: Pytester
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
Loading…
Reference in New Issue