Skip to content

Commit 7342f4f

Browse files
author
Sylvain MARIE
committed
param_fixtures now delegates to param_fixture when a single parameter name is provided. This is more consistent. Fixed #36
Also, now `param_fixture[s]` offer all arguments from `fixture` (added `autouse` and kwargs).
1 parent b96dc3b commit 7342f4f

File tree

2 files changed

+47
-29
lines changed

2 files changed

+47
-29
lines changed

pytest_cases/main_fixtures.py

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,40 @@
4242
from pytest_cases.main_params import cases_data
4343

4444

45-
def param_fixture(argname, argvalues, ids=None, scope="function"):
45+
def param_fixture(argname, argvalues, autouse=False, ids=None, scope="function", **kwargs):
4646
"""
4747
Identical to `param_fixtures` but for a single parameter name.
4848
49-
:param argname:
50-
:param argvalues:
51-
:param ids:
52-
:param scope: the scope of created fixtures
49+
:param argname: see fixture `name`
50+
:param argvalues: see fixture `params`
51+
:param autouse: see fixture `autouse`
52+
:param ids: see fixture `ids`
53+
:param scope: see fixture `scope`
54+
:param kwargs: any other argument for 'fixture'
5355
:return:
5456
"""
5557
if "," in argname:
5658
raise ValueError("`param_fixture` is an alias for `param_fixtures` that can only be used for a single "
5759
"parameter name. Use `param_fixtures` instead - but note that it creates several fixtures.")
60+
elif len(argname.replace(' ', '')) == 0:
61+
raise ValueError("empty argname")
62+
return _param_fixture(argname, argvalues, autouse=autouse, ids=ids, scope=scope, **kwargs)
63+
64+
65+
def _param_fixture(argname, argvalues, autouse=False, ids=None, scope="function", **kwargs):
66+
""" Internal method shared with param_fixture and param_fixtures """
5867

5968
# create the fixture
60-
def _param_fixture(request):
69+
def __param_fixture(request):
6170
return request.param
62-
_param_fixture.__name__ = argname
6371

64-
fix = pytest.fixture(scope=scope, params=argvalues, ids=ids)(_param_fixture)
72+
fix = pytest_fixture_plus(name=argname, scope=scope, autouse=autouse, params=argvalues, ids=ids,
73+
**kwargs)(__param_fixture)
6574

6675
# Add the fixture dynamically: we have to add it to the corresponding module as explained in
6776
# https://github.com/pytest-dev/pytest/issues/2424
6877
# grab context from the caller frame
69-
frame = _get_callerframe()
78+
frame = _get_callerframe(offset=1)
7079
module = getmodule(frame)
7180
if argname in dir(module):
7281
warn("`param_fixture` Overriding symbol %s in module %s" % (argname, module))
@@ -75,23 +84,30 @@ def _param_fixture(request):
7584
return fix
7685

7786

78-
def param_fixtures(argnames, argvalues, ids=None):
87+
def param_fixtures(argnames, argvalues, autouse=False, ids=None, scope="function", **kwargs):
7988
"""
8089
Creates one or several "parameters" fixtures - depending on the number or coma-separated names in `argnames`.
8190
8291
Note that the (argnames, argvalues, ids) signature is similar to `@pytest.mark.parametrize` for consistency,
8392
see https://docs.pytest.org/en/latest/reference.html?highlight=pytest.param#pytest-mark-parametrize
8493
85-
:param argnames:
86-
:param argvalues:
87-
:param ids:
94+
:param argnames: same as `@pytest.mark.parametrize` `argnames`.
95+
:param argvalues: same as `@pytest.mark.parametrize` `argvalues`.
96+
:param autouse: see fixture `autouse`
97+
:param ids: same as `@pytest.mark.parametrize` `ids`
98+
:param scope: see fixture `scope`
99+
:param kwargs: any other argument for the created 'fixtures'
88100
:return:
89101
"""
90102
created_fixtures = []
91103
argnames_lst = argnames.replace(' ', '').split(',')
92104

105+
if len(argnames_lst) < 2:
106+
return _param_fixture(argnames, argvalues, autouse=autouse, ids=ids, scope=scope, **kwargs)
107+
93108
# create the root fixture that will contain all parameter values
94-
root_fixture_name = "param_fixtures_root__%s" % ('_'.join(argnames_lst))
109+
# note: we sort the list so that the first in alphabetical order appears first. Indeed pytest uses this order.
110+
root_fixture_name = "%s__param_fixtures_root" % ('_'.join(sorted(argnames_lst)))
95111

96112
# Add the fixture dynamically: we have to add it to the corresponding module as explained in
97113
# https://github.com/pytest-dev/pytest/issues/2424
@@ -107,7 +123,7 @@ def param_fixtures(argnames, argvalues, ids=None):
107123
i += 1
108124
root_fixture_name[-1] += str(i)
109125

110-
@pytest_fixture_plus(name=root_fixture_name)
126+
@pytest_fixture_plus(name=root_fixture_name, autouse=autouse, scope=scope, **kwargs)
111127
@pytest.mark.parametrize(argnames, argvalues, ids=ids)
112128
@with_signature("(%s)" % argnames)
113129
def _root_fixture(**kwargs):
@@ -121,7 +137,7 @@ def _root_fixture(**kwargs):
121137
# To fix late binding issue with `param_idx` we add an extra layer of scope
122138
# See https://stackoverflow.com/questions/3431676/creating-functions-in-a-loop
123139
def _create_fixture(param_idx):
124-
@pytest_fixture_plus(name=argname)
140+
@pytest_fixture_plus(name=argname, scope=scope, autouse=autouse, **kwargs)
125141
@with_signature("(%s)" % root_fixture_name)
126142
def _param_fixture(**kwargs):
127143
params = kwargs.pop(root_fixture_name)
@@ -139,10 +155,7 @@ def _param_fixture(**kwargs):
139155
# collect to return the whole list eventually
140156
created_fixtures.append(fix)
141157

142-
if len(argnames_lst) > 1:
143-
return created_fixtures
144-
else:
145-
return created_fixtures[0]
158+
return created_fixtures
146159

147160

148161
def _get_callerframe(offset=0):
@@ -274,7 +287,7 @@ def pytest_fixture_plus(scope="function",
274287
# (1) Collect all @pytest.mark.parametrize markers (including those created by usage of @cases_data)
275288
parametrizer_marks = get_pytest_parametrize_marks(fixture_func)
276289
if len(parametrizer_marks) < 1:
277-
return _create_fixture_without_marks(fixture_func, scope, autouse, kwargs)
290+
return _create_fixture_without_marks(fixture_func, scope, autouse, **kwargs)
278291
else:
279292
if 'params' in kwargs:
280293
raise ValueError(
@@ -410,7 +423,7 @@ def wrapped_fixture_func(*args, **kwargs):
410423
return fixture_decorator(wrapped_fixture_func)
411424

412425

413-
def _create_fixture_without_marks(fixture_func, scope, autouse, kwargs):
426+
def _create_fixture_without_marks(fixture_func, scope, autouse, **kwargs):
414427
"""
415428
creates a fixture for decorated fixture function `fixture_func`.
416429

pytest_cases/tests/fixtures/test_fixtures_paramfixtures.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ def test_uses_param(my_parameter, my_parameter2, fixture_uses_param):
3333
param_fixtures("arg1, arg2", [(1, 2), (3, 4)])
3434

3535
# Testing param_fixtures with single arg
36-
parg3 = param_fixtures("parg3", [5, 6])
36+
arg3 = param_fixture("arg3", [5, 6])
3737

3838

3939
@pytest.fixture
4040
def fixture_uses_param2(arg2):
4141
return arg2
4242

4343

44-
def test_uses_param2(arg1, arg2, parg3, fixture_uses_param2):
44+
def test_uses_param2(arg1, arg2, arg3, fixture_uses_param2):
4545
# check that the parameter injected in both is the same
4646
assert arg2 == fixture_uses_param2
4747
assert arg1, arg2 in [(1, 2), (3, 4)]
48-
assert parg3 in [5, 6]
48+
assert arg3 in [5, 6]
4949

5050

5151
# ---------- (3)
@@ -104,8 +104,13 @@ def test_synthesis(module_results_dct):
104104
'test_uses_param[1-4]',
105105
'test_uses_param[2-3]',
106106
'test_uses_param[2-4]',
107-
'test_uses_param2[1-2-5]',
108-
'test_uses_param2[1-2-6]',
109-
'test_uses_param2[3-4-5]',
110-
'test_uses_param2[3-4-6]',
107+
# see https://github.com/pytest-dev/pytest/issues/5054
108+
# 'test_uses_param2[1-2-5]',
109+
# 'test_uses_param2[1-2-6]',
110+
# 'test_uses_param2[3-4-5]',
111+
# 'test_uses_param2[3-4-6]',
112+
'test_uses_param2[5-1-2]',
113+
'test_uses_param2[5-3-4]',
114+
'test_uses_param2[6-1-2]',
115+
'test_uses_param2[6-3-4]',
111116
] + end_list

0 commit comments

Comments
 (0)