diff --git a/changelog/3555.bugfix.rst b/changelog/3555.bugfix.rst new file mode 100644 index 000000000..1911e1df5 --- /dev/null +++ b/changelog/3555.bugfix.rst @@ -0,0 +1 @@ +Fix regression in Node.add_marker by extracting the mark object of a markdecorator. diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 7e86aee44..2b8dbf855 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -281,7 +281,14 @@ def _marked(func, mark): class MarkInfo(object): """ Marking object created by :class:`MarkDecorator` instances. """ - _marks = attr.ib() + _marks = attr.ib(convert=list) + + @_marks.validator + def validate_marks(self, attribute, value): + for item in value: + if not isinstance(item, Mark): + raise ValueError(item) + combined = attr.ib( repr=False, default=attr.Factory( diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 8d82bf606..264077f5d 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -173,10 +173,12 @@ class Node(object): chain.reverse() return chain - def add_marker(self, marker): + def add_marker(self, marker, append=True): """ dynamically add a marker object to the node. ``marker`` can be a string or pytest.mark.* instance. + ``append=True`` whether to append the marker, + if false insert at position 0 """ from _pytest.mark import MarkDecorator, MARK_GEN @@ -185,7 +187,7 @@ class Node(object): elif not isinstance(marker, MarkDecorator): raise ValueError("is not a string or pytest.mark.* Marker") self.keywords[marker.name] = marker - self.own_markers.append(marker) + self.own_markers.append(marker.mark) def iter_markers(self, name=None): """ diff --git a/testing/test_mark.py b/testing/test_mark.py index e96af888a..e2e7369dc 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function import os import sys - +import mock import pytest from _pytest.mark import ( MarkGenerator as Mark, @@ -9,6 +9,7 @@ from _pytest.mark import ( transfer_markers, EMPTY_PARAMETERSET_OPTION, ) +from _pytest.nodes import Node ignore_markinfo = pytest.mark.filterwarnings( "ignore:MarkInfo objects:_pytest.deprecated.RemovedInPytest4Warning" @@ -1123,3 +1124,11 @@ def test_mark_expressions_no_smear(testdir): passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes() assert passed_k == 2 assert skipped_k == failed_k == 0 + + +def test_addmarker_getmarker(): + node = Node("Test", config=mock.Mock(), session=mock.Mock(), nodeid="Test") + node.add_marker(pytest.mark.a(1)) + node.add_marker("b") + node.get_marker("a").combined + node.get_marker("b").combined