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``)
|
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)``.
|
||||||
|
|
|
@ -724,13 +724,6 @@ MarkGenerator
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
||||||
MarkInfo
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
.. autoclass:: _pytest.mark.MarkInfo
|
|
||||||
:members:
|
|
||||||
|
|
||||||
|
|
||||||
Mark
|
Mark
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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::
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue