Skip to content

Commit

Permalink
convert, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed committed Nov 13, 2019
1 parent 1b1468f commit ea2b62f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 10 deletions.
1 change: 1 addition & 0 deletions changelog/759.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``pytest.mark.parametrize`` supports iterators and generators for ``ids``.
25 changes: 15 additions & 10 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,20 +1040,25 @@ def _validate_ids(self, ids, parameters, func_name):
import itertools

ids = list(itertools.islice(it, len(parameters)))
len_ids = len(ids)

if len_ids != len(parameters):
msg = "In {}: {} parameter sets specified, with different number of ids: {}"
fail(msg.format(func_name, len(parameters), len(ids)), pytrace=False)
for id_value in ids:
if id_value is not None and not isinstance(id_value, str):
from _pytest._io.saferepr import saferepr

msg = "In {}: ids must be list of strings, found: {} (type: {!r})"
fail(
msg.format(func_name, saferepr(id_value), type(id_value)),
pytrace=False,
)
return ids
new_ids = ids[:]
for idx, id_value in enumerate(new_ids):
if id_value is not None:
if isinstance(id_value, int):
new_ids[idx] = str(id_value)
elif not isinstance(id_value, str):
from _pytest._io.saferepr import saferepr

msg = "In {}: ids must be list of strings, found: {} (type: {!r}) at index {}"
fail(
msg.format(func_name, saferepr(id_value), type(id_value), idx),
pytrace=False,
)
return new_ids

def _resolve_arg_value_types(self, argnames, indirect):
"""Resolves if each parametrized argument must be considered a parameter to a fixture or a "funcarg"
Expand Down
62 changes: 62 additions & 0 deletions testing/python/metafunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest
from _pytest import fixtures
from _pytest import python
from _pytest.outcomes import fail


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

def test_parametrize_error_iterator(self):
def func(x):
pass

class Exc(Exception):
def __repr__(self):
return "Exc(from_gen)"

def gen():
yield 0
yield None
yield Exc()

metafunc = self.Metafunc(func)
metafunc.parametrize("x", [1, 2], ids=gen())
assert [(x.funcargs, x.id) for x in metafunc._calls] == [
({"x": 1}, "0"),
({"x": 2}, "2"),
]
with pytest.raises(
fail.Exception,
match=r"In func: ids must be list of strings, found: Exc\(from_gen\) \(type: <class .*Exc'>\) at index 2",
):
metafunc.parametrize("x", [1, 2, 3], ids=gen())

def test_parametrize_bad_scope(self, testdir):
def func(x):
pass
Expand Down Expand Up @@ -1807,3 +1833,39 @@ def test_foo(a):
)
result = testdir.runpytest()
result.assert_outcomes(passed=1)

def test_parametrize_iterator(self, testdir):
testdir.makepyfile(
"""
import itertools
import pytest
id_parametrize = pytest.mark.parametrize(
ids=("param%d" % i for i in itertools.count()
))
@id_parametrize('y', ['a', 'b'])
def test1(y):
pass
@id_parametrize('y', ['a', 'b'])
def test2(y):
pass
@pytest.mark.parametrize("a, b", [(1, 2), (3, 4)], ids=itertools.count(1))
def test_converted_to_str(a, b):
pass
"""
)
result = testdir.runpytest("-vv", "-s")
result.stdout.fnmatch_lines(
[
"test_parametrize_iterator.py::test1[param0] PASSED",
"test_parametrize_iterator.py::test1[param1] PASSED",
"test_parametrize_iterator.py::test2[param2] PASSED",
"test_parametrize_iterator.py::test2[param3] PASSED",
"test_parametrize_iterator.py::test_converted_to_str[1] PASSED",
"test_parametrize_iterator.py::test_converted_to_str[2] PASSED",
"*= 6 passed in *",
]
)

0 comments on commit ea2b62f

Please sign in to comment.