diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a6f9f6265..d47d3810d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,13 +3,17 @@ * -* +* Improve error message when passing non-string ids to ``pytest.mark.parametrize`` (`#1857`_). + Thanks `@okken`_ for the report and `@nicoddemus`_ for the PR. * * +.. _#1857: https://github.com/pytest-dev/pytest/issues/1857 + + 3.0.1 ===== diff --git a/_pytest/python.py b/_pytest/python.py index 75d139df3..ae0a2f571 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -778,6 +778,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): """ from _pytest.fixtures import scopes from _pytest.mark import extract_argvalue + from py.io import saferepr unwrapped_argvalues = [] newkeywords = [] @@ -831,9 +832,14 @@ class Metafunc(fixtures.FuncargnamesCompatAttr): if callable(ids): idfn = ids ids = None - if ids and len(ids) != len(argvalues): - raise ValueError('%d tests specified with %d ids' %( - len(argvalues), len(ids))) + if ids: + if len(ids) != len(argvalues): + raise ValueError('%d tests specified with %d ids' %( + len(argvalues), len(ids))) + for id_value in ids: + if id_value is not None and not isinstance(id_value, str): + msg = 'ids must be list of strings, found: %s (type: %s)' + raise ValueError(msg % (saferepr(id_value), type(id_value).__name__)) ids = idmaker(argnames, argvalues, idfn, ids, self.config) newcalls = [] for callspec in self._calls or [CallSpec2(self)]: diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 61ace1867..58f566973 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -916,6 +916,18 @@ class TestMetafuncFunctional: result = testdir.runpytest() result.stdout.fnmatch_lines(['* 1 skipped *']) + def test_parametrized_ids_invalid_type(self, testdir): + """Tests parametrized with ids as non-strings (#1857).""" + testdir.makepyfile(''' + import pytest + + @pytest.mark.parametrize("x, expected", [(10, 20), (40, 80)], ids=(None, 2)) + def test_ids_numbers(x,expected): + assert x * 2 == expected + ''') + result = testdir.runpytest() + result.stdout.fnmatch_lines(['*ids must be list of strings, found: 2 (type: int)*']) + def test_parametrize_with_identical_ids_get_unique_names(self, testdir): testdir.makepyfile(""" import pytest