Skip to content

Commit 124375e

Browse files
author
Sylvain MARIE
committed
Fixed ids precedence order when using pytest.mark.parametrize in a fixture_plus. Fixed #87
1 parent 0e2965d commit 124375e

File tree

3 files changed

+81
-43
lines changed

3 files changed

+81
-43
lines changed

pytest_cases/common.py

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,18 @@ def get_parametrize_signature():
259259

260260

261261
# ---------- test ids utils ---------
262+
def combine_ids(paramid_tuples):
263+
"""
264+
Receives a list of tuples containing ids for each parameterset.
265+
Returns the final ids, that are obtained by joining the various param ids by '-' for each test node
266+
267+
:param paramid_tuples:
268+
:return:
269+
"""
270+
#
271+
return ['-'.join(pid for pid in testid) for testid in paramid_tuples]
272+
273+
262274
def get_test_ids_from_param_values(param_names,
263275
param_values,
264276
):
@@ -285,43 +297,81 @@ def get_test_ids_from_param_values(param_names,
285297

286298

287299
# ---- ParameterSet api ---
288-
def extract_parameterset_info(pnames, pmark):
300+
def analyze_parameter_set(pmark=None, argnames=None, argvalues=None, ids=None):
289301
"""
302+
analyzes a parameter set passed either as a pmark or as distinct
303+
(argnames, argvalues, ids) to extract/construct the various ids, marks, and
304+
values
290305
291-
:param pnames: the names in this parameterset
292-
:param pmark: the parametrization mark (a _ParametrizationMark)
306+
:return: ids, marks, values
307+
"""
308+
if pmark is not None:
309+
if any(a is not None for a in (argnames, argvalues, ids)):
310+
raise ValueError("Either provide a pmark OR the details")
311+
argnames = pmark.param_names
312+
argvalues = pmark.param_values
313+
ids = pmark.param_ids
314+
315+
# extract all parameters that have a specific configuration (pytest.param())
316+
custom_pids, p_marks, p_values = extract_parameterset_info(argnames, argvalues)
317+
318+
# Create the proper id for each test
319+
if ids is not None:
320+
# overridden at global pytest.mark.parametrize level - this takes precedence.
321+
try: # an explicit list of ids ?
322+
p_ids = list(ids)
323+
except TypeError: # a callable to apply on the values
324+
p_ids = list(ids(v) for v in p_values)
325+
else:
326+
# default: values-based
327+
p_ids = get_test_ids_from_param_values(argnames, p_values)
328+
329+
# Finally, local pytest.param takes precedence over everything else
330+
for i, _id in enumerate(custom_pids):
331+
if _id is not None:
332+
p_ids[i] = _id
333+
334+
return p_ids, p_marks, p_values
335+
336+
337+
def extract_parameterset_info(argnames, argvalues):
338+
"""
339+
340+
:param argnames: the names in this parameterset
341+
:param argvalues: the values in this parameterset
293342
:return:
294343
"""
295-
_pids = []
296-
_pmarks = []
297-
_pvalues = []
298-
for v in pmark.param_values:
344+
pids = []
345+
pmarks = []
346+
pvalues = []
347+
for v in argvalues:
299348
if is_marked_parameter_value(v):
300349
# --id
301350
id = get_marked_parameter_id(v)
302-
_pids.append(id)
351+
pids.append(id)
303352
# --marks
304353
marks = get_marked_parameter_marks(v)
305-
_pmarks.append(marks) # note: there might be several
354+
pmarks.append(marks) # note: there might be several
306355
# --value(a tuple if this is a tuple parameter)
307356
vals = get_marked_parameter_values(v)
308-
if len(vals) != len(pnames):
357+
if len(vals) != len(argnames):
309358
raise ValueError("Internal error - unsupported pytest parametrization+mark combination. Please "
310359
"report this issue")
311360
if len(vals) == 1:
312-
_pvalues.append(vals[0])
361+
pvalues.append(vals[0])
313362
else:
314-
_pvalues.append(vals)
363+
pvalues.append(vals)
315364
else:
316-
_pids.append(None)
317-
_pmarks.append(None)
318-
_pvalues.append(v)
365+
pids.append(None)
366+
pmarks.append(None)
367+
pvalues.append(v)
319368

320-
return _pids, _pmarks, _pvalues
369+
return pids, pmarks, pvalues
321370

322371

323372
try: # pytest 3.x+
324373
from _pytest.mark import ParameterSet
374+
325375
def is_marked_parameter_value(v):
326376
return isinstance(v, ParameterSet)
327377

pytest_cases/main_fixtures.py

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
pass
4141

4242
from pytest_cases.common import yield_fixture, get_pytest_parametrize_marks, get_test_ids_from_param_values, \
43-
make_marked_parameter_value, extract_parameterset_info, get_fixture_name, get_param_argnames_as_list, \
43+
make_marked_parameter_value, get_fixture_name, get_param_argnames_as_list, analyze_parameter_set, combine_ids, \
4444
get_fixture_scope, remove_duplicates
4545
from pytest_cases.main_params import cases_data
4646

@@ -579,34 +579,21 @@ def _decorate_fixture_plus(fixture_func,
579579
params_ids = []
580580
params_marks = []
581581
for pmark in parametrizer_marks:
582+
# -- pmark is a single @pytest.parametrize mark. --
583+
582584
# check number of parameter names in this parameterset
583585
if len(pmark.param_names) < 1:
584586
raise ValueError("Fixture function '%s' decorated with '@fixture_plus' has an empty parameter "
585587
"name in a @pytest.mark.parametrize mark")
586588

587-
# remember
589+
# remember the argnames
588590
params_names_or_name_combinations.append(pmark.param_names)
589591

590-
# extract all parameters that have a specific configuration (pytest.param())
591-
_pids, _pmarks, _pvalues = extract_parameterset_info(pmark.param_names, pmark)
592-
593-
# Create the proper id for each test
594-
if pmark.param_ids is not None:
595-
# overridden at global pytest.mark.parametrize level - this takes precedence.
596-
try: # an explicit list of ids ?
597-
paramids = list(pmark.param_ids)
598-
except TypeError: # a callable to apply on the values
599-
paramids = list(pmark.param_ids(v) for v in _pvalues)
600-
else:
601-
# default: values-based...
602-
paramids = get_test_ids_from_param_values(pmark.param_names, _pvalues)
603-
# ...but local pytest.param takes precedence
604-
for i, _id in enumerate(_pids):
605-
if _id is not None:
606-
paramids[i] = _id
592+
# analyse contents, extract marks and custom ids, apply custom ids
593+
_paramids, _pmarks, _pvalues = analyze_parameter_set(pmark)
607594

608595
# Finally store the ids, marks, and values for this parameterset
609-
params_ids.append(paramids)
596+
params_ids.append(_paramids)
610597
params_marks.append(tuple(_pmarks))
611598
params_values.append(tuple(_pvalues))
612599

@@ -623,7 +610,7 @@ def _decorate_fixture_plus(fixture_func,
623610
final_values[i] = make_marked_parameter_value(final_values[i], marks=marks)
624611
else:
625612
final_values = list(product(*params_values))
626-
final_ids = get_test_ids_from_param_values(params_names_or_name_combinations, product(*params_ids))
613+
final_ids = combine_ids(product(*params_ids))
627614
final_marks = tuple(product(*params_marks))
628615

629616
# reapply the marks

pytest_cases/tests/fixtures/test_fixtures_parametrize.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,31 @@ def test_one(myfix):
2525

2626

2727
@pytest_fixture_plus
28+
@pytest.mark.parametrize("arg3", [pytest_param(0, id='!0!')], ids=str)
2829
@pytest.mark.parametrize("arg1, arg2", [
2930
(1, 2),
3031
pytest_param(3, 4, id="p_a"),
3132
pytest_param(5, 6, id="skipped", marks=pytest.mark.skip)
3233
])
33-
def myfix2(arg1, arg2):
34-
return arg1, arg2
34+
def myfix2(arg1, arg2, arg3):
35+
return arg1, arg2, arg3
3536

3637

3738
def test_two(myfix2):
38-
assert myfix2 in {(1, 2), (3, 4), (5, 6)}
39+
assert myfix2 in {(1, 2, 0), (3, 4, 0), (5, 6, 0)}
3940
print(myfix2)
4041

4142

4243
@pytest_fixture_plus
4344
@pytest.mark.parametrize("arg1, arg2", [
44-
pytest_param(5, 6, id="ignored_id")
45-
], ids=['a'])
45+
pytest_param(5, 6, id="a")
46+
], ids=['ignored_id'])
4647
def myfix3(arg1, arg2):
4748
return arg1, arg2
4849

4950

5051
def test_two(myfix2, myfix3):
51-
assert myfix2 in {(1, 2), (3, 4), (5, 6)}
52+
assert myfix2 in {(1, 2, 0), (3, 4, 0), (5, 6, 0)}
5253
print(myfix2)
5354

5455

0 commit comments

Comments
 (0)