diff --git a/CHANGELOG b/CHANGELOG index bc4c74aa3e7..ce75fced13d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ 2.8.0.dev (compared to 2.7.X) ----------------------------- +- parametrize now also generates meaningful test IDs for enum, regex and class + objects (as opposed to class instances). + Thanks to Florian Bruhin for the PR. + - Add 'warns' to assert that warnings are thrown (like 'raises'). Thanks to Eric Hunsberger for the PR. diff --git a/_pytest/python.py b/_pytest/python.py index fe93c938e51..cdd51a810f8 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1,4 +1,5 @@ """ Python test discovery, setup and run of test functions. """ +import re import fnmatch import functools import py @@ -8,6 +9,12 @@ from _pytest.mark import MarkDecorator, MarkerError from py._code.code import TerminalRepr +try: + import enum +except ImportError: # pragma: no cover + # Only available in Python 3.4+ or as a backport + enum = None + import _pytest import pluggy @@ -22,6 +29,8 @@ callable = py.builtin.callable # used to work around a python2 exception info leak exc_clear = getattr(sys, 'exc_clear', lambda: None) +# The type of re.compile objects is not exposed in Python. +REGEX_TYPE = type(re.compile('')) def filter_traceback(entry): return entry.path != cutdir1 and not entry.path.relto(cutdir2) @@ -976,8 +985,15 @@ def _idval(val, argname, idx, idfn): return s except Exception: pass + if isinstance(val, (float, int, str, bool, NoneType)): return str(val) + elif isinstance(val, REGEX_TYPE): + return val.pattern + elif enum is not None and isinstance(val, enum.Enum): + return str(val) + elif isclass(val) and hasattr(val, '__name__'): + return val.__name__ return str(argname)+str(idx) def _idvalset(idx, valset, argnames, idfn): diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 7a6d1eebfe8..90346a5b633 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -1,3 +1,4 @@ +import re import pytest, py from _pytest import python as funcargs @@ -138,6 +139,8 @@ def test_idmaker_native_strings(self): ("three", "three hundred"), (True, False), (None, None), + (re.compile('foo'), re.compile('bar')), + (str, int), (list("six"), [66, 66]), (set([7]), set("seven")), (tuple("eight"), (8, -8, 8)) @@ -147,9 +150,18 @@ def test_idmaker_native_strings(self): "three-three hundred", "True-False", "None-None", - "a5-b5", - "a6-b6", - "a7-b7"] + "foo-bar", + "str-int", + "a7-b7", + "a8-b8", + "a9-b9"] + + def test_idmaker_enum(self): + from _pytest.python import idmaker + enum = pytest.importorskip("enum") + e = enum.Enum("Foo", "one, two") + result = idmaker(("a", "b"), [(e.one, e.two)]) + assert result == ["Foo.one-Foo.two"] @pytest.mark.issue351 def test_idmaker_idfn(self):