Merge pull request #4564 from RonnyPfannschmidt/remove-markinfo

Remove MarkInfo
This commit is contained in:
Bruno Oliveira 2018-12-21 14:32:15 -02:00 committed by GitHub
commit 134ace98d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 87 additions and 437 deletions

View File

@ -0,0 +1,3 @@
Remove ``Node.get_marker(name)`` the return value was not usable for more than a existence check.
Use ``Node.get_closest_marker(name)`` as a replacement.

View File

@ -0,0 +1 @@
Remove ``testfunction.markername`` attributes - use ``Node.iter_markers(name=None)`` to iterate them.

View File

@ -77,13 +77,7 @@ Becomes:
``Node.get_marker``
~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.6
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
:ref:`the documentation <update marker code>` on tips on how to update your code.
Result log (``--result-log``) Result log (``--result-log``)
@ -497,3 +491,21 @@ Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points
were never documented and a leftover from a pre-virtualenv era. These entry were never documented and a leftover from a pre-virtualenv era. These entry
points also created broken entry points in wheels, so removing them also points also created broken entry points in wheels, so removing them also
removes a source of confusion for users. removes a source of confusion for users.
``Node.get_marker``
~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0*
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
:ref:`the documentation <update marker code>` on tips on how to update your code.
``somefunction.markname``
~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 4.0*
As part of a large :ref:`marker-revamp` we already deprecated using ``MarkInfo``
the only correct way to get markers of an element is via ``node.iter_markers(name)``.

View File

@ -724,13 +724,6 @@ MarkGenerator
:members: :members:
MarkInfo
~~~~~~~~
.. autoclass:: _pytest.mark.MarkInfo
:members:
Mark Mark
~~~~ ~~~~

View File

@ -268,10 +268,14 @@ class PytestPluginManager(PluginManager):
# collect unmarked hooks as long as they have the `pytest_' prefix # collect unmarked hooks as long as they have the `pytest_' prefix
if opts is None and name.startswith("pytest_"): if opts is None and name.startswith("pytest_"):
opts = {} opts = {}
if opts is not None: if opts is not None:
# TODO: DeprecationWarning, people should use hookimpl
# https://github.com/pytest-dev/pytest/issues/4562
known_marks = {m.name for m in getattr(method, "pytestmark", [])}
for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"): for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"):
opts.setdefault(name, hasattr(method, name))
opts.setdefault(name, hasattr(method, name) or name in known_marks)
return opts return opts
def parse_hookspec_opts(self, module_or_class, name): def parse_hookspec_opts(self, module_or_class, name):
@ -280,10 +284,16 @@ class PytestPluginManager(PluginManager):
) )
if opts is None: if opts is None:
method = getattr(module_or_class, name) method = getattr(module_or_class, name)
if name.startswith("pytest_"): if name.startswith("pytest_"):
# todo: deprecate hookspec hacks
# https://github.com/pytest-dev/pytest/issues/4562
known_marks = {m.name for m in getattr(method, "pytestmark", [])}
opts = { opts = {
"firstresult": hasattr(method, "firstresult"), "firstresult": hasattr(method, "firstresult")
"historic": hasattr(method, "historic"), or "firstresult" in known_marks,
"historic": hasattr(method, "historic")
or "historic" in known_marks,
} }
return opts return opts

View File

@ -1207,19 +1207,20 @@ class FixtureManager(object):
if faclist: if faclist:
fixturedef = faclist[-1] fixturedef = faclist[-1]
if fixturedef.params is not None: if fixturedef.params is not None:
parametrize_func = getattr(metafunc.function, "parametrize", None) markers = list(metafunc.definition.iter_markers("parametrize"))
if parametrize_func is not None: for parametrize_mark in markers:
parametrize_func = parametrize_func.combined if "argnames" in parametrize_mark.kwargs:
func_params = getattr(parametrize_func, "args", [[None]]) argnames = parametrize_mark.kwargs["argnames"]
func_kwargs = getattr(parametrize_func, "kwargs", {}) else:
# skip directly parametrized arguments argnames = parametrize_mark.args[0]
if "argnames" in func_kwargs:
argnames = parametrize_func.kwargs["argnames"] if not isinstance(argnames, (tuple, list)):
argnames = [
x.strip() for x in argnames.split(",") if x.strip()
]
if argname in argnames:
break
else: else:
argnames = func_params[0]
if not isinstance(argnames, (tuple, list)):
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
if argname not in func_params and argname not in argnames:
metafunc.parametrize( metafunc.parametrize(
argname, argname,
fixturedef.params, fixturedef.params,

View File

@ -11,19 +11,10 @@ from .structures import Mark
from .structures import MARK_GEN from .structures import MARK_GEN
from .structures import MarkDecorator from .structures import MarkDecorator
from .structures import MarkGenerator from .structures import MarkGenerator
from .structures import MarkInfo
from .structures import ParameterSet from .structures import ParameterSet
from .structures import transfer_markers
from _pytest.config import UsageError from _pytest.config import UsageError
__all__ = [ __all__ = ["Mark", "MarkDecorator", "MarkGenerator", "get_empty_parameterset_mark"]
"Mark",
"MarkInfo",
"MarkDecorator",
"MarkGenerator",
"transfer_markers",
"get_empty_parameterset_mark",
]
def param(*values, **kw): def param(*values, **kw):

View File

@ -1,18 +1,15 @@
import inspect import inspect
import warnings import warnings
from collections import namedtuple from collections import namedtuple
from functools import reduce
from operator import attrgetter from operator import attrgetter
import attr import attr
import six import six
from six.moves import map
from ..compat import ascii_escaped from ..compat import ascii_escaped
from ..compat import getfslineno from ..compat import getfslineno
from ..compat import MappingMixin from ..compat import MappingMixin
from ..compat import NOTSET from ..compat import NOTSET
from ..deprecated import MARK_INFO_ATTRIBUTE
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -233,11 +230,7 @@ class MarkDecorator(object):
func = args[0] func = args[0]
is_class = inspect.isclass(func) is_class = inspect.isclass(func)
if len(args) == 1 and (istestfunc(func) or is_class): if len(args) == 1 and (istestfunc(func) or is_class):
if is_class: store_mark(func, self.mark)
store_mark(func, self.mark)
else:
store_legacy_markinfo(func, self.mark)
store_mark(func, self.mark)
return func return func
return self.with_args(*args, **kwargs) return self.with_args(*args, **kwargs)
@ -259,7 +252,13 @@ def normalize_mark_list(mark_list):
:type mark_list: List[Union[Mark, Markdecorator]] :type mark_list: List[Union[Mark, Markdecorator]]
:rtype: List[Mark] :rtype: List[Mark]
""" """
return [getattr(mark, "mark", mark) for mark in mark_list] # unpack MarkDecorator extracted = [
getattr(mark, "mark", mark) for mark in mark_list
] # unpack MarkDecorator
for mark in extracted:
if not isinstance(mark, Mark):
raise TypeError("got {!r} instead of Mark".format(mark))
return [x for x in extracted if isinstance(x, Mark)]
def store_mark(obj, mark): def store_mark(obj, mark):
@ -272,90 +271,6 @@ def store_mark(obj, mark):
obj.pytestmark = get_unpacked_marks(obj) + [mark] obj.pytestmark = get_unpacked_marks(obj) + [mark]
def store_legacy_markinfo(func, mark):
"""create the legacy MarkInfo objects and put them onto the function
"""
if not isinstance(mark, Mark):
raise TypeError("got {mark!r} instead of a Mark".format(mark=mark))
holder = getattr(func, mark.name, None)
if holder is None:
holder = MarkInfo.for_mark(mark)
setattr(func, mark.name, holder)
elif isinstance(holder, MarkInfo):
holder.add_mark(mark)
def transfer_markers(funcobj, cls, mod):
"""
this function transfers class level markers and module level markers
into function level markinfo objects
this is the main reason why marks are so broken
the resolution will involve phasing out function level MarkInfo objects
"""
for obj in (cls, mod):
for mark in get_unpacked_marks(obj):
if not _marked(funcobj, mark):
store_legacy_markinfo(funcobj, mark)
def _marked(func, mark):
""" Returns True if :func: is already marked with :mark:, False otherwise.
This can happen if marker is applied to class and the test file is
invoked more than once.
"""
try:
func_mark = getattr(func, getattr(mark, "combined", mark).name)
except AttributeError:
return False
return any(mark == info.combined for info in func_mark)
@attr.s(repr=False)
class MarkInfo(object):
""" Marking object created by :class:`MarkDecorator` instances. """
_marks = attr.ib(converter=list)
@_marks.validator
def validate_marks(self, attribute, value):
for item in value:
if not isinstance(item, Mark):
raise ValueError(
"MarkInfo expects Mark instances, got {!r} ({!r})".format(
item, type(item)
)
)
combined = attr.ib(
repr=False,
default=attr.Factory(
lambda self: reduce(Mark.combined_with, self._marks), takes_self=True
),
)
name = alias("combined.name", warning=MARK_INFO_ATTRIBUTE)
args = alias("combined.args", warning=MARK_INFO_ATTRIBUTE)
kwargs = alias("combined.kwargs", warning=MARK_INFO_ATTRIBUTE)
@classmethod
def for_mark(cls, mark):
return cls([mark])
def __repr__(self):
return "<MarkInfo {!r}>".format(self.combined)
def add_mark(self, mark):
""" add a MarkInfo with the given args and kwargs. """
self._marks.append(mark)
self.combined = self.combined.combined_with(mark)
def __iter__(self):
""" yield MarkInfo objects each relating to a marking-call. """
return map(MarkInfo.for_mark, self._marks)
class MarkGenerator(object): class MarkGenerator(object):
""" Factory for :class:`MarkDecorator` objects - exposed as """ Factory for :class:`MarkDecorator` objects - exposed as
a ``pytest.mark`` singleton instance. Example:: a ``pytest.mark`` singleton instance. Example::

View File

@ -10,7 +10,6 @@ import six
import _pytest._code import _pytest._code
from _pytest.compat import getfslineno from _pytest.compat import getfslineno
from _pytest.mark.structures import MarkInfo
from _pytest.mark.structures import NodeKeywords from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import fail from _pytest.outcomes import fail
@ -211,20 +210,6 @@ class Node(object):
""" """
return next(self.iter_markers(name=name), default) return next(self.iter_markers(name=name), default)
def get_marker(self, name):
""" get a marker object from this node or None if
the node doesn't have a marker with that name.
.. deprecated:: 3.6
This function has been deprecated in favor of
:meth:`Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker>` and
:meth:`Node.iter_markers <_pytest.nodes.Node.iter_markers>`, see :ref:`update marker code`
for more details.
"""
markers = list(self.iter_markers(name=name))
if markers:
return MarkInfo(markers)
def listextrakeywords(self): def listextrakeywords(self):
""" Return a set of all extra keywords in self and any parents.""" """ Return a set of all extra keywords in self and any parents."""
extra_keywords = set() extra_keywords = set()

View File

@ -41,7 +41,6 @@ from _pytest.main import FSHookProxy
from _pytest.mark import MARK_GEN from _pytest.mark import MARK_GEN
from _pytest.mark.structures import get_unpacked_marks from _pytest.mark.structures import get_unpacked_marks
from _pytest.mark.structures import normalize_mark_list from _pytest.mark.structures import normalize_mark_list
from _pytest.mark.structures import transfer_markers
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.pathlib import parts from _pytest.pathlib import parts
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
@ -125,10 +124,10 @@ def pytest_generate_tests(metafunc):
# those alternative spellings are common - raise a specific error to alert # those alternative spellings are common - raise a specific error to alert
# the user # the user
alt_spellings = ["parameterize", "parametrise", "parameterise"] alt_spellings = ["parameterize", "parametrise", "parameterise"]
for attr in alt_spellings: for mark_name in alt_spellings:
if hasattr(metafunc.function, attr): if metafunc.definition.get_closest_marker(mark_name):
msg = "{0} has '{1}' mark, spelling should be 'parametrize'" msg = "{0} has '{1}' mark, spelling should be 'parametrize'"
fail(msg.format(metafunc.function.__name__, attr), pytrace=False) fail(msg.format(metafunc.function.__name__, mark_name), pytrace=False)
for marker in metafunc.definition.iter_markers(name="parametrize"): for marker in metafunc.definition.iter_markers(name="parametrize"):
metafunc.parametrize(*marker.args, **marker.kwargs) metafunc.parametrize(*marker.args, **marker.kwargs)
@ -385,7 +384,6 @@ class PyCollector(PyobjMixin, nodes.Collector):
module = self.getparent(Module).obj module = self.getparent(Module).obj
clscol = self.getparent(Class) clscol = self.getparent(Class)
cls = clscol and clscol.obj or None cls = clscol and clscol.obj or None
transfer_markers(funcobj, cls, module)
fm = self.session._fixturemanager fm = self.session._fixturemanager
definition = FunctionDefinition(name=name, parent=self, callobj=funcobj) definition = FunctionDefinition(name=name, parent=self, callobj=funcobj)
@ -1291,6 +1289,20 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
if keywords: if keywords:
self.keywords.update(keywords) self.keywords.update(keywords)
# todo: this is a hell of a hack
# https://github.com/pytest-dev/pytest/issues/4569
self.keywords.update(
dict.fromkeys(
[
mark.name
for mark in self.iter_markers()
if mark.name not in self.keywords
],
True,
)
)
if fixtureinfo is None: if fixtureinfo is None:
fixtureinfo = self.session._fixturemanager.getfixtureinfo( fixtureinfo = self.session._fixturemanager.getfixtureinfo(
self, self.obj, self.cls, funcargs=not self._isyieldedfunction() self, self.obj, self.cls, funcargs=not self._isyieldedfunction()

View File

@ -14,8 +14,6 @@ from _pytest.outcomes import skip
from _pytest.outcomes import xfail from _pytest.outcomes import xfail
from _pytest.python import Class from _pytest.python import Class
from _pytest.python import Function from _pytest.python import Function
from _pytest.python import Module
from _pytest.python import transfer_markers
def pytest_pycollect_makeitem(collector, name, obj): def pytest_pycollect_makeitem(collector, name, obj):
@ -54,14 +52,12 @@ class UnitTestCase(Class):
return return
self.session._fixturemanager.parsefactories(self, unittest=True) self.session._fixturemanager.parsefactories(self, unittest=True)
loader = TestLoader() loader = TestLoader()
module = self.getparent(Module).obj
foundsomething = False foundsomething = False
for name in loader.getTestCaseNames(self.obj): for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name) x = getattr(self.obj, name)
if not getattr(x, "__test__", True): if not getattr(x, "__test__", True):
continue continue
funcobj = getimfunc(x) funcobj = getimfunc(x)
transfer_markers(funcobj, cls, module)
yield TestCaseFunction(name, parent=self, callobj=funcobj) yield TestCaseFunction(name, parent=self, callobj=funcobj)
foundsomething = True foundsomething = True

View File

@ -10,7 +10,6 @@ import six
import pytest import pytest
from _pytest.mark import EMPTY_PARAMETERSET_OPTION from _pytest.mark import EMPTY_PARAMETERSET_OPTION
from _pytest.mark import MarkGenerator as Mark from _pytest.mark import MarkGenerator as Mark
from _pytest.mark import transfer_markers
from _pytest.nodes import Collector from _pytest.nodes import Collector
from _pytest.nodes import Node from _pytest.nodes import Node
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
@ -26,12 +25,6 @@ ignore_markinfo = pytest.mark.filterwarnings(
class TestMark(object): class TestMark(object):
def test_markinfo_repr(self):
from _pytest.mark import MarkInfo, Mark
m = MarkInfo.for_mark(Mark("hello", (1, 2), {}))
repr(m)
@pytest.mark.parametrize("attr", ["mark", "param"]) @pytest.mark.parametrize("attr", ["mark", "param"])
@pytest.mark.parametrize("modulename", ["py.test", "pytest"]) @pytest.mark.parametrize("modulename", ["py.test", "pytest"])
def test_pytest_exists_in_namespace_all(self, attr, modulename): def test_pytest_exists_in_namespace_all(self, attr, modulename):
@ -57,105 +50,8 @@ class TestMark(object):
def test_pytest_mark_name_starts_with_underscore(self): def test_pytest_mark_name_starts_with_underscore(self):
mark = Mark() mark = Mark()
pytest.raises(AttributeError, getattr, mark, "_some_name") with pytest.raises(AttributeError):
mark._some_name
def test_pytest_mark_bare(self):
mark = Mark()
def f():
pass
mark.hello(f)
assert f.hello
def test_mark_legacy_ignore_fail(self):
def add_attribute(func):
func.foo = 1
return func
@pytest.mark.foo
@add_attribute
def test_fun():
pass
assert test_fun.foo == 1
assert test_fun.pytestmark
@ignore_markinfo
def test_pytest_mark_keywords(self):
mark = Mark()
def f():
pass
mark.world(x=3, y=4)(f)
assert f.world
assert f.world.kwargs["x"] == 3
assert f.world.kwargs["y"] == 4
@ignore_markinfo
def test_apply_multiple_and_merge(self):
mark = Mark()
def f():
pass
mark.world
mark.world(x=3)(f)
assert f.world.kwargs["x"] == 3
mark.world(y=4)(f)
assert f.world.kwargs["x"] == 3
assert f.world.kwargs["y"] == 4
mark.world(y=1)(f)
assert f.world.kwargs["y"] == 1
assert len(f.world.args) == 0
@ignore_markinfo
def test_pytest_mark_positional(self):
mark = Mark()
def f():
pass
mark.world("hello")(f)
assert f.world.args[0] == "hello"
mark.world("world")(f)
@ignore_markinfo
def test_pytest_mark_positional_func_and_keyword(self):
mark = Mark()
def f():
raise Exception
m = mark.world(f, omega="hello")
def g():
pass
assert m(g) == g
assert g.world.args[0] is f
assert g.world.kwargs["omega"] == "hello"
@ignore_markinfo
def test_pytest_mark_reuse(self):
mark = Mark()
def f():
pass
w = mark.some
w("hello", reason="123")(f)
assert f.some.args[0] == "hello"
assert f.some.kwargs["reason"] == "123"
def g():
pass
w("world", reason2="456")(g)
assert g.some.args[0] == "world"
assert "reason" not in g.some.kwargs
assert g.some.kwargs["reason2"] == "456"
def test_marked_class_run_twice(testdir, request): def test_marked_class_run_twice(testdir, request):
@ -505,116 +401,6 @@ def test_parametrized_with_kwargs(testdir):
class TestFunctional(object): class TestFunctional(object):
def test_mark_per_function(self, testdir):
p = testdir.makepyfile(
"""
import pytest
@pytest.mark.hello
def test_hello():
assert hasattr(test_hello, 'hello')
"""
)
result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["*1 passed*"])
def test_mark_per_module(self, testdir):
item = testdir.getitem(
"""
import pytest
pytestmark = pytest.mark.hello
def test_func():
pass
"""
)
keywords = item.keywords
assert "hello" in keywords
def test_marklist_per_class(self, testdir):
item = testdir.getitem(
"""
import pytest
class TestClass(object):
pytestmark = [pytest.mark.hello, pytest.mark.world]
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
"""
)
keywords = item.keywords
assert "hello" in keywords
def test_marklist_per_module(self, testdir):
item = testdir.getitem(
"""
import pytest
pytestmark = [pytest.mark.hello, pytest.mark.world]
class TestClass(object):
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
"""
)
keywords = item.keywords
assert "hello" in keywords
assert "world" in keywords
def test_mark_per_class_decorator(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.hello
class TestClass(object):
def test_func(self):
assert TestClass.test_func.hello
"""
)
keywords = item.keywords
assert "hello" in keywords
def test_mark_per_class_decorator_plus_existing_dec(self, testdir):
item = testdir.getitem(
"""
import pytest
@pytest.mark.hello
class TestClass(object):
pytestmark = pytest.mark.world
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
"""
)
keywords = item.keywords
assert "hello" in keywords
assert "world" in keywords
@ignore_markinfo
def test_merging_markers(self, testdir):
p = testdir.makepyfile(
"""
import pytest
pytestmark = pytest.mark.hello("pos1", x=1, y=2)
class TestClass(object):
# classlevel overrides module level
pytestmark = pytest.mark.hello(x=3)
@pytest.mark.hello("pos0", z=4)
def test_func(self):
pass
"""
)
items, rec = testdir.inline_genitems(p)
item, = items
keywords = item.keywords
marker = keywords["hello"]
assert marker.args == ("pos0", "pos1")
assert marker.kwargs == {"x": 1, "y": 2, "z": 4}
# test the new __iter__ interface
values = list(marker)
assert len(values) == 3
assert values[0].args == ("pos0",)
assert values[1].args == ()
assert values[2].args == ("pos1",)
def test_merging_markers_deep(self, testdir): def test_merging_markers_deep(self, testdir):
# issue 199 - propagate markers into nested classes # issue 199 - propagate markers into nested classes
p = testdir.makepyfile( p = testdir.makepyfile(
@ -677,11 +463,6 @@ class TestFunctional(object):
items, rec = testdir.inline_genitems(p) items, rec = testdir.inline_genitems(p)
base_item, sub_item, sub_item_other = items base_item, sub_item, sub_item_other = items
print(items, [x.nodeid for x in items]) print(items, [x.nodeid for x in items])
# legacy api smears
assert hasattr(base_item.obj, "b")
assert hasattr(sub_item_other.obj, "b")
assert hasattr(sub_item.obj, "b")
# new api seregates # new api seregates
assert not list(base_item.iter_markers(name="b")) assert not list(base_item.iter_markers(name="b"))
assert not list(sub_item_other.iter_markers(name="b")) assert not list(sub_item_other.iter_markers(name="b"))
@ -767,26 +548,6 @@ class TestFunctional(object):
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines(["keyword: *hello*"]) result.stdout.fnmatch_lines(["keyword: *hello*"])
@ignore_markinfo
def test_merging_markers_two_functions(self, testdir):
p = testdir.makepyfile(
"""
import pytest
@pytest.mark.hello("pos1", z=4)
@pytest.mark.hello("pos0", z=3)
def test_func():
pass
"""
)
items, rec = testdir.inline_genitems(p)
item, = items
keywords = item.keywords
marker = keywords["hello"]
values = list(marker)
assert len(values) == 2
assert values[0].args == ("pos0",)
assert values[1].args == ("pos1",)
def test_no_marker_match_on_unmarked_names(self, testdir): def test_no_marker_match_on_unmarked_names(self, testdir):
p = testdir.makepyfile( p = testdir.makepyfile(
""" """
@ -860,7 +621,7 @@ class TestFunctional(object):
assert "mark2" in request.keywords assert "mark2" in request.keywords
assert "mark3" in request.keywords assert "mark3" in request.keywords
assert 10 not in request.keywords assert 10 not in request.keywords
marker = request.node.get_marker("mark1") marker = request.node.get_closest_marker("mark1")
assert marker.name == "mark1" assert marker.name == "mark1"
assert marker.args == () assert marker.args == ()
assert marker.kwargs == {} assert marker.kwargs == {}
@ -876,15 +637,11 @@ class TestFunctional(object):
.. note:: this could be moved to ``testdir`` if proven to be useful .. note:: this could be moved to ``testdir`` if proven to be useful
to other modules. to other modules.
""" """
from _pytest.mark import MarkInfo
items = {x.name: x for x in items} items = {x.name: x for x in items}
for name, expected_markers in expected.items(): for name, expected_markers in expected.items():
markers = items[name].keywords._markers markers = {m.name for m in items[name].iter_markers()}
marker_names = { assert markers == set(expected_markers)
name for (name, v) in markers.items() if isinstance(v, MarkInfo)
}
assert marker_names == set(expected_markers)
@pytest.mark.issue1540 @pytest.mark.issue1540
@pytest.mark.filterwarnings("ignore") @pytest.mark.filterwarnings("ignore")
@ -1043,26 +800,6 @@ class TestKeywordSelection(object):
assert_test_is_not_selected("()") assert_test_is_not_selected("()")
def test_legacy_transfer():
class FakeModule(object):
pytestmark = []
class FakeClass(object):
pytestmark = pytest.mark.nofun
@pytest.mark.fun
def fake_method(self):
pass
transfer_markers(fake_method, FakeClass, FakeModule)
# legacy marks transfer smeared
assert fake_method.nofun
assert fake_method.fun
# pristine marks dont transfer
assert fake_method.pytestmark == [pytest.mark.fun.mark]
class TestMarkDecorator(object): class TestMarkDecorator(object):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"lhs, rhs, expected", "lhs, rhs, expected",
@ -1163,19 +900,12 @@ def test_mark_expressions_no_smear(testdir):
deselected_tests = dlist[0].items deselected_tests = dlist[0].items
assert len(deselected_tests) == 1 assert len(deselected_tests) == 1
# todo: fixed
# keywords smear - expected behaviour # keywords smear - expected behaviour
reprec_keywords = testdir.inline_run("-k", "FOO") # reprec_keywords = testdir.inline_run("-k", "FOO")
passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes() # passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes()
assert passed_k == 2 # assert passed_k == 2
assert skipped_k == failed_k == 0 # 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
def test_addmarker_order(): def test_addmarker_order():
@ -1199,7 +929,7 @@ def test_markers_from_parametrize(testdir):
custom_mark = pytest.mark.custom_mark custom_mark = pytest.mark.custom_mark
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def trigger(request): def trigger(request):
custom_mark =request.node.get_marker('custom_mark') custom_mark = list(request.node.iter_markers('custom_mark'))
print("Custom mark %s" % custom_mark) print("Custom mark %s" % custom_mark)
@custom_mark("custom mark non parametrized") @custom_mark("custom mark non parametrized")

View File

@ -121,6 +121,7 @@ setenv=
setenv = {[testenv:py27-pluggymaster]setenv} setenv = {[testenv:py27-pluggymaster]setenv}
[testenv:docs] [testenv:docs]
basepython = python3
skipsdist = True skipsdist = True
usedevelop = True usedevelop = True
changedir = doc/en changedir = doc/en