Skip to content

Commit ea2b62f

Browse files
committed
convert, tests
1 parent 1b1468f commit ea2b62f

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

changelog/759.improvement.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``pytest.mark.parametrize`` supports iterators and generators for ``ids``.

src/_pytest/python.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,20 +1040,25 @@ def _validate_ids(self, ids, parameters, func_name):
10401040
import itertools
10411041

10421042
ids = list(itertools.islice(it, len(parameters)))
1043+
len_ids = len(ids)
10431044

10441045
if len_ids != len(parameters):
10451046
msg = "In {}: {} parameter sets specified, with different number of ids: {}"
10461047
fail(msg.format(func_name, len(parameters), len(ids)), pytrace=False)
1047-
for id_value in ids:
1048-
if id_value is not None and not isinstance(id_value, str):
1049-
from _pytest._io.saferepr import saferepr
1050-
1051-
msg = "In {}: ids must be list of strings, found: {} (type: {!r})"
1052-
fail(
1053-
msg.format(func_name, saferepr(id_value), type(id_value)),
1054-
pytrace=False,
1055-
)
1056-
return ids
1048+
new_ids = ids[:]
1049+
for idx, id_value in enumerate(new_ids):
1050+
if id_value is not None:
1051+
if isinstance(id_value, int):
1052+
new_ids[idx] = str(id_value)
1053+
elif not isinstance(id_value, str):
1054+
from _pytest._io.saferepr import saferepr
1055+
1056+
msg = "In {}: ids must be list of strings, found: {} (type: {!r}) at index {}"
1057+
fail(
1058+
msg.format(func_name, saferepr(id_value), type(id_value), idx),
1059+
pytrace=False,
1060+
)
1061+
return new_ids
10571062

10581063
def _resolve_arg_value_types(self, argnames, indirect):
10591064
"""Resolves if each parametrized argument must be considered a parameter to a fixture or a "funcarg"

testing/python/metafunc.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import pytest
88
from _pytest import fixtures
99
from _pytest import python
10+
from _pytest.outcomes import fail
1011

1112

1213
class TestMetafunc:
@@ -59,6 +60,31 @@ def func(x, y):
5960
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
6061
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
6162

63+
def test_parametrize_error_iterator(self):
64+
def func(x):
65+
pass
66+
67+
class Exc(Exception):
68+
def __repr__(self):
69+
return "Exc(from_gen)"
70+
71+
def gen():
72+
yield 0
73+
yield None
74+
yield Exc()
75+
76+
metafunc = self.Metafunc(func)
77+
metafunc.parametrize("x", [1, 2], ids=gen())
78+
assert [(x.funcargs, x.id) for x in metafunc._calls] == [
79+
({"x": 1}, "0"),
80+
({"x": 2}, "2"),
81+
]
82+
with pytest.raises(
83+
fail.Exception,
84+
match=r"In func: ids must be list of strings, found: Exc\(from_gen\) \(type: <class .*Exc'>\) at index 2",
85+
):
86+
metafunc.parametrize("x", [1, 2, 3], ids=gen())
87+
6288
def test_parametrize_bad_scope(self, testdir):
6389
def func(x):
6490
pass
@@ -1807,3 +1833,39 @@ def test_foo(a):
18071833
)
18081834
result = testdir.runpytest()
18091835
result.assert_outcomes(passed=1)
1836+
1837+
def test_parametrize_iterator(self, testdir):
1838+
testdir.makepyfile(
1839+
"""
1840+
import itertools
1841+
import pytest
1842+
1843+
id_parametrize = pytest.mark.parametrize(
1844+
ids=("param%d" % i for i in itertools.count()
1845+
))
1846+
1847+
@id_parametrize('y', ['a', 'b'])
1848+
def test1(y):
1849+
pass
1850+
1851+
@id_parametrize('y', ['a', 'b'])
1852+
def test2(y):
1853+
pass
1854+
1855+
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4)], ids=itertools.count(1))
1856+
def test_converted_to_str(a, b):
1857+
pass
1858+
"""
1859+
)
1860+
result = testdir.runpytest("-vv", "-s")
1861+
result.stdout.fnmatch_lines(
1862+
[
1863+
"test_parametrize_iterator.py::test1[param0] PASSED",
1864+
"test_parametrize_iterator.py::test1[param1] PASSED",
1865+
"test_parametrize_iterator.py::test2[param2] PASSED",
1866+
"test_parametrize_iterator.py::test2[param3] PASSED",
1867+
"test_parametrize_iterator.py::test_converted_to_str[1] PASSED",
1868+
"test_parametrize_iterator.py::test_converted_to_str[2] PASSED",
1869+
"*= 6 passed in *",
1870+
]
1871+
)

0 commit comments

Comments
 (0)