From 8395b9e25dd968124c239c303af4088aa6a348b9 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 18 Nov 2018 14:16:13 -0800 Subject: [PATCH] Require id=... to be a string This was documented before, but never enforced. Passing non-strings could have strange side-effects and enforcing a string simplifies other implementation. --- src/_pytest/mark/structures.py | 11 +++++++---- testing/test_mark.py | 32 ++++++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index b8fa011d1..f1892aa3f 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -5,6 +5,7 @@ from functools import reduce from operator import attrgetter import attr +import six from six.moves import map from ..compat import getfslineno @@ -70,10 +71,12 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")): else: assert isinstance(marks, (tuple, list, set)) - def param_extract_id(id=None): - return id - - id_ = param_extract_id(**kw) + id_ = kw.pop("id", None) + if id_ is not None: + if not isinstance(id_, six.string_types): + raise TypeError( + "Expected id to be a string, got {}: {!r}".format(type(id_), id_) + ) return cls(values, marks, id_) @classmethod diff --git a/testing/test_mark.py b/testing/test_mark.py index 1f50045c5..80979d7ee 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -5,20 +5,21 @@ from __future__ import print_function import os import sys +import six + +import pytest +from _pytest.mark import EMPTY_PARAMETERSET_OPTION +from _pytest.mark import MarkGenerator as Mark +from _pytest.mark import ParameterSet +from _pytest.mark import transfer_markers +from _pytest.nodes import Collector +from _pytest.nodes import Node from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG try: import mock except ImportError: import unittest.mock as mock -import pytest -from _pytest.mark import ( - MarkGenerator as Mark, - ParameterSet, - transfer_markers, - EMPTY_PARAMETERSET_OPTION, -) -from _pytest.nodes import Node, Collector ignore_markinfo = pytest.mark.filterwarnings( "ignore:MarkInfo objects:pytest.RemovedInPytest4Warning" @@ -1252,3 +1253,18 @@ def test_markers_from_parametrize(testdir): result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG) result.assert_outcomes(passed=4) + + +def test_pytest_param_id_requires_string(): + with pytest.raises(TypeError) as excinfo: + pytest.param(id=True) + msg, = excinfo.value.args + if six.PY2: + assert msg == "Expected id to be a string, got : True" + else: + assert msg == "Expected id to be a string, got : True" + + +@pytest.mark.parametrize("s", (None, "hello world")) +def test_pytest_param_id_allows_none_or_string(s): + assert pytest.param(id=s)