Skip to content

Commit b63b123

Browse files
Allow parametrize argvalues and ids to accept generators
1 parent ae28e4b commit b63b123

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

_pytest/python.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,8 @@ def __init__(self, function, fixtureinfo, config, cls=None, module=None):
826826
self.cls = cls
827827
self._calls = []
828828
self._ids = py.builtin.set()
829+
self._used_ids = []
830+
self._used_argvalues = []
829831

830832
def parametrize(self, argnames, argvalues, indirect=False, ids=None,
831833
scope=None):
@@ -837,7 +839,7 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None,
837839
:arg argnames: a comma-separated string denoting one or more argument
838840
names, or a list/tuple of argument strings.
839841
840-
:arg argvalues: The list of argvalues determines how often a
842+
:arg argvalues: The list/generator of argvalues determines how often a
841843
test is invoked with different argument values. If only one
842844
argname was specified argvalues is a list of simple values. If N
843845
argnames were specified, argvalues must be a list of N-tuples,
@@ -849,7 +851,7 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None,
849851
function so that it can perform more expensive setups during the
850852
setup phase of a test rather than at collection time.
851853
852-
:arg ids: list of string ids, or a callable.
854+
:arg ids: list of string ids, generator or a callable.
853855
If strings, each is corresponding to the argvalues so that they are
854856
part of the test id.
855857
If callable, it should take one argument (a single argvalue) and return
@@ -869,6 +871,9 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None,
869871
# at Function init
870872
newkeywords = {}
871873
unwrapped_argvalues = []
874+
if not self._used_argvalues:
875+
self._used_argvalues = argvalues = list(argvalues)
876+
872877
for i, argval in enumerate(argvalues):
873878
while isinstance(argval, MarkDecorator):
874879
newmark = MarkDecorator(argval.markname,
@@ -900,6 +905,8 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None,
900905
if callable(ids):
901906
idfn = ids
902907
ids = None
908+
if not self._used_ids and ids:
909+
self._used_ids = ids = list(ids)
903910
if ids and len(ids) != len(argvalues):
904911
raise ValueError('%d tests specified with %d ids' %(
905912
len(argvalues), len(ids)))

testing/python/metafunc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,24 @@ def test_3(self, arg, arg2):
342342
*6 passed*
343343
""")
344344

345+
def test_parametrize_generators(self):
346+
def generator_ids():
347+
for value in ['1', '2']:
348+
yield value
349+
350+
def generator_argvalues():
351+
for value in [(1, 2), (3, 4)]:
352+
yield value
353+
354+
metafunc = self.Metafunc(lambda x, y: None)
355+
metafunc.parametrize(("x", "y"), generator_argvalues(), ids=generator_ids())
356+
for i in [1, 2]:
357+
ids = [x.id for x in metafunc._calls]
358+
assert ids == ['1', '2']
359+
assert len(metafunc._calls) == 2
360+
assert metafunc._calls[0].funcargs == dict(x=1, y=2)
361+
assert metafunc._calls[1].funcargs == dict(x=3, y=4)
362+
345363
class TestMetafuncFunctional:
346364
def test_attributes(self, testdir):
347365
p = testdir.makepyfile("""

0 commit comments

Comments
 (0)