Merge pull request #4564 from RonnyPfannschmidt/remove-markinfo
Remove MarkInfo
This commit is contained in:
commit
134ace98d9
|
@ -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.
|
|
@ -0,0 +1 @@
|
|||
Remove ``testfunction.markername`` attributes - use ``Node.iter_markers(name=None)`` to iterate them.
|
|
@ -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``)
|
||||
|
@ -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
|
||||
points also created broken entry points in wheels, so removing them also
|
||||
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)``.
|
||||
|
|
|
@ -724,13 +724,6 @@ MarkGenerator
|
|||
:members:
|
||||
|
||||
|
||||
MarkInfo
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: _pytest.mark.MarkInfo
|
||||
:members:
|
||||
|
||||
|
||||
Mark
|
||||
~~~~
|
||||
|
||||
|
|
|
@ -268,10 +268,14 @@ class PytestPluginManager(PluginManager):
|
|||
# collect unmarked hooks as long as they have the `pytest_' prefix
|
||||
if opts is None and name.startswith("pytest_"):
|
||||
opts = {}
|
||||
|
||||
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"):
|
||||
opts.setdefault(name, hasattr(method, name))
|
||||
|
||||
opts.setdefault(name, hasattr(method, name) or name in known_marks)
|
||||
return opts
|
||||
|
||||
def parse_hookspec_opts(self, module_or_class, name):
|
||||
|
@ -280,10 +284,16 @@ class PytestPluginManager(PluginManager):
|
|||
)
|
||||
if opts is None:
|
||||
method = getattr(module_or_class, name)
|
||||
|
||||
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 = {
|
||||
"firstresult": hasattr(method, "firstresult"),
|
||||
"historic": hasattr(method, "historic"),
|
||||
"firstresult": hasattr(method, "firstresult")
|
||||
or "firstresult" in known_marks,
|
||||
"historic": hasattr(method, "historic")
|
||||
or "historic" in known_marks,
|
||||
}
|
||||
return opts
|
||||
|
||||
|
|
|
@ -1207,19 +1207,20 @@ class FixtureManager(object):
|
|||
if faclist:
|
||||
fixturedef = faclist[-1]
|
||||
if fixturedef.params is not None:
|
||||
parametrize_func = getattr(metafunc.function, "parametrize", None)
|
||||
if parametrize_func is not None:
|
||||
parametrize_func = parametrize_func.combined
|
||||
func_params = getattr(parametrize_func, "args", [[None]])
|
||||
func_kwargs = getattr(parametrize_func, "kwargs", {})
|
||||
# skip directly parametrized arguments
|
||||
if "argnames" in func_kwargs:
|
||||
argnames = parametrize_func.kwargs["argnames"]
|
||||
markers = list(metafunc.definition.iter_markers("parametrize"))
|
||||
for parametrize_mark in markers:
|
||||
if "argnames" in parametrize_mark.kwargs:
|
||||
argnames = parametrize_mark.kwargs["argnames"]
|
||||
else:
|
||||
argnames = func_params[0]
|
||||
argnames = parametrize_mark.args[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:
|
||||
argnames = [
|
||||
x.strip() for x in argnames.split(",") if x.strip()
|
||||
]
|
||||
if argname in argnames:
|
||||
break
|
||||
else:
|
||||
metafunc.parametrize(
|
||||
argname,
|
||||
fixturedef.params,
|
||||
|
|
|
@ -11,19 +11,10 @@ from .structures import Mark
|
|||
from .structures import MARK_GEN
|
||||
from .structures import MarkDecorator
|
||||
from .structures import MarkGenerator
|
||||
from .structures import MarkInfo
|
||||
from .structures import ParameterSet
|
||||
from .structures import transfer_markers
|
||||
from _pytest.config import UsageError
|
||||
|
||||
__all__ = [
|
||||
"Mark",
|
||||
"MarkInfo",
|
||||
"MarkDecorator",
|
||||
"MarkGenerator",
|
||||
"transfer_markers",
|
||||
"get_empty_parameterset_mark",
|
||||
]
|
||||
__all__ = ["Mark", "MarkDecorator", "MarkGenerator", "get_empty_parameterset_mark"]
|
||||
|
||||
|
||||
def param(*values, **kw):
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
import inspect
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from functools import reduce
|
||||
from operator import attrgetter
|
||||
|
||||
import attr
|
||||
import six
|
||||
from six.moves import map
|
||||
|
||||
from ..compat import ascii_escaped
|
||||
from ..compat import getfslineno
|
||||
from ..compat import MappingMixin
|
||||
from ..compat import NOTSET
|
||||
from ..deprecated import MARK_INFO_ATTRIBUTE
|
||||
from _pytest.outcomes import fail
|
||||
|
||||
|
||||
|
@ -233,10 +230,6 @@ class MarkDecorator(object):
|
|||
func = args[0]
|
||||
is_class = inspect.isclass(func)
|
||||
if len(args) == 1 and (istestfunc(func) or is_class):
|
||||
if is_class:
|
||||
store_mark(func, self.mark)
|
||||
else:
|
||||
store_legacy_markinfo(func, self.mark)
|
||||
store_mark(func, self.mark)
|
||||
return func
|
||||
return self.with_args(*args, **kwargs)
|
||||
|
@ -259,7 +252,13 @@ def normalize_mark_list(mark_list):
|
|||
:type mark_list: List[Union[Mark, Markdecorator]]
|
||||
: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):
|
||||
|
@ -272,90 +271,6 @@ def store_mark(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):
|
||||
""" Factory for :class:`MarkDecorator` objects - exposed as
|
||||
a ``pytest.mark`` singleton instance. Example::
|
||||
|
|
|
@ -10,7 +10,6 @@ import six
|
|||
|
||||
import _pytest._code
|
||||
from _pytest.compat import getfslineno
|
||||
from _pytest.mark.structures import MarkInfo
|
||||
from _pytest.mark.structures import NodeKeywords
|
||||
from _pytest.outcomes import fail
|
||||
|
||||
|
@ -211,20 +210,6 @@ class Node(object):
|
|||
"""
|
||||
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):
|
||||
""" Return a set of all extra keywords in self and any parents."""
|
||||
extra_keywords = set()
|
||||
|
|
|
@ -41,7 +41,6 @@ from _pytest.main import FSHookProxy
|
|||
from _pytest.mark import MARK_GEN
|
||||
from _pytest.mark.structures import get_unpacked_marks
|
||||
from _pytest.mark.structures import normalize_mark_list
|
||||
from _pytest.mark.structures import transfer_markers
|
||||
from _pytest.outcomes import fail
|
||||
from _pytest.pathlib import parts
|
||||
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
|
||||
# the user
|
||||
alt_spellings = ["parameterize", "parametrise", "parameterise"]
|
||||
for attr in alt_spellings:
|
||||
if hasattr(metafunc.function, attr):
|
||||
for mark_name in alt_spellings:
|
||||
if metafunc.definition.get_closest_marker(mark_name):
|
||||
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"):
|
||||
metafunc.parametrize(*marker.args, **marker.kwargs)
|
||||
|
||||
|
@ -385,7 +384,6 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
|||
module = self.getparent(Module).obj
|
||||
clscol = self.getparent(Class)
|
||||
cls = clscol and clscol.obj or None
|
||||
transfer_markers(funcobj, cls, module)
|
||||
fm = self.session._fixturemanager
|
||||
|
||||
definition = FunctionDefinition(name=name, parent=self, callobj=funcobj)
|
||||
|
@ -1291,6 +1289,20 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
|
|||
if 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:
|
||||
fixtureinfo = self.session._fixturemanager.getfixtureinfo(
|
||||
self, self.obj, self.cls, funcargs=not self._isyieldedfunction()
|
||||
|
|
|
@ -14,8 +14,6 @@ from _pytest.outcomes import skip
|
|||
from _pytest.outcomes import xfail
|
||||
from _pytest.python import Class
|
||||
from _pytest.python import Function
|
||||
from _pytest.python import Module
|
||||
from _pytest.python import transfer_markers
|
||||
|
||||
|
||||
def pytest_pycollect_makeitem(collector, name, obj):
|
||||
|
@ -54,14 +52,12 @@ class UnitTestCase(Class):
|
|||
return
|
||||
self.session._fixturemanager.parsefactories(self, unittest=True)
|
||||
loader = TestLoader()
|
||||
module = self.getparent(Module).obj
|
||||
foundsomething = False
|
||||
for name in loader.getTestCaseNames(self.obj):
|
||||
x = getattr(self.obj, name)
|
||||
if not getattr(x, "__test__", True):
|
||||
continue
|
||||
funcobj = getimfunc(x)
|
||||
transfer_markers(funcobj, cls, module)
|
||||
yield TestCaseFunction(name, parent=self, callobj=funcobj)
|
||||
foundsomething = True
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import six
|
|||
import pytest
|
||||
from _pytest.mark import EMPTY_PARAMETERSET_OPTION
|
||||
from _pytest.mark import MarkGenerator as Mark
|
||||
from _pytest.mark import transfer_markers
|
||||
from _pytest.nodes import Collector
|
||||
from _pytest.nodes import Node
|
||||
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
||||
|
@ -26,12 +25,6 @@ ignore_markinfo = pytest.mark.filterwarnings(
|
|||
|
||||
|
||||
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("modulename", ["py.test", "pytest"])
|
||||
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):
|
||||
mark = Mark()
|
||||
pytest.raises(AttributeError, getattr, 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"
|
||||
with pytest.raises(AttributeError):
|
||||
mark._some_name
|
||||
|
||||
|
||||
def test_marked_class_run_twice(testdir, request):
|
||||
|
@ -505,116 +401,6 @@ def test_parametrized_with_kwargs(testdir):
|
|||
|
||||
|
||||
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):
|
||||
# issue 199 - propagate markers into nested classes
|
||||
p = testdir.makepyfile(
|
||||
|
@ -677,11 +463,6 @@ class TestFunctional(object):
|
|||
items, rec = testdir.inline_genitems(p)
|
||||
base_item, sub_item, sub_item_other = 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
|
||||
assert not list(base_item.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.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):
|
||||
p = testdir.makepyfile(
|
||||
"""
|
||||
|
@ -860,7 +621,7 @@ class TestFunctional(object):
|
|||
assert "mark2" in request.keywords
|
||||
assert "mark3" 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.args == ()
|
||||
assert marker.kwargs == {}
|
||||
|
@ -876,15 +637,11 @@ class TestFunctional(object):
|
|||
.. note:: this could be moved to ``testdir`` if proven to be useful
|
||||
to other modules.
|
||||
"""
|
||||
from _pytest.mark import MarkInfo
|
||||
|
||||
items = {x.name: x for x in items}
|
||||
for name, expected_markers in expected.items():
|
||||
markers = items[name].keywords._markers
|
||||
marker_names = {
|
||||
name for (name, v) in markers.items() if isinstance(v, MarkInfo)
|
||||
}
|
||||
assert marker_names == set(expected_markers)
|
||||
markers = {m.name for m in items[name].iter_markers()}
|
||||
assert markers == set(expected_markers)
|
||||
|
||||
@pytest.mark.issue1540
|
||||
@pytest.mark.filterwarnings("ignore")
|
||||
|
@ -1043,26 +800,6 @@ class TestKeywordSelection(object):
|
|||
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):
|
||||
@pytest.mark.parametrize(
|
||||
"lhs, rhs, expected",
|
||||
|
@ -1163,19 +900,12 @@ def test_mark_expressions_no_smear(testdir):
|
|||
deselected_tests = dlist[0].items
|
||||
assert len(deselected_tests) == 1
|
||||
|
||||
# todo: fixed
|
||||
# keywords smear - expected behaviour
|
||||
reprec_keywords = testdir.inline_run("-k", "FOO")
|
||||
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
|
||||
# reprec_keywords = testdir.inline_run("-k", "FOO")
|
||||
# passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes()
|
||||
# assert passed_k == 2
|
||||
# assert skipped_k == failed_k == 0
|
||||
|
||||
|
||||
def test_addmarker_order():
|
||||
|
@ -1199,7 +929,7 @@ def test_markers_from_parametrize(testdir):
|
|||
custom_mark = pytest.mark.custom_mark
|
||||
@pytest.fixture(autouse=True)
|
||||
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)
|
||||
|
||||
@custom_mark("custom mark non parametrized")
|
||||
|
|
Loading…
Reference in New Issue