deprecate markinfo and fix up most marker scoping access while completely breaking metafunc testing
This commit is contained in:
parent
e8feee0612
commit
180ae09202
|
@ -32,7 +32,8 @@ RESULT_LOG = (
|
|||
)
|
||||
|
||||
MARK_INFO_ATTRIBUTE = RemovedInPytest4Warning(
|
||||
"MarkInfo objects are deprecated as they contain the merged marks"
|
||||
"MarkInfo objects are deprecated as they contain the merged marks.\n"
|
||||
"Please use node.find_markers to iterate over markers correctly"
|
||||
)
|
||||
|
||||
MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
|
||||
|
|
|
@ -5,6 +5,7 @@ import inspect
|
|||
import sys
|
||||
import warnings
|
||||
from collections import OrderedDict, deque, defaultdict
|
||||
from more_itertools import flatten
|
||||
|
||||
import attr
|
||||
import py
|
||||
|
@ -982,10 +983,10 @@ class FixtureManager(object):
|
|||
argnames = getfuncargnames(func, cls=cls)
|
||||
else:
|
||||
argnames = ()
|
||||
usefixtures = getattr(func, "usefixtures", None)
|
||||
usefixtures = flatten(uf_mark.args for uf_mark in node.find_markers("usefixtures"))
|
||||
initialnames = argnames
|
||||
if usefixtures is not None:
|
||||
initialnames = usefixtures.args + initialnames
|
||||
initialnames = tuple(usefixtures) + initialnames
|
||||
fm = node.session._fixturemanager
|
||||
names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames,
|
||||
node)
|
||||
|
@ -1067,6 +1068,8 @@ class FixtureManager(object):
|
|||
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
|
||||
|
|
|
@ -4,7 +4,7 @@ from operator import attrgetter
|
|||
import inspect
|
||||
|
||||
import attr
|
||||
from ..deprecated import MARK_PARAMETERSET_UNPACKING
|
||||
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
|
||||
from ..compat import NOTSET, getfslineno
|
||||
from six.moves import map
|
||||
|
||||
|
@ -260,10 +260,10 @@ def _marked(func, mark):
|
|||
invoked more than once.
|
||||
"""
|
||||
try:
|
||||
func_mark = getattr(func, mark.name)
|
||||
func_mark = getattr(func, getattr(mark, 'combined', mark).name)
|
||||
except AttributeError:
|
||||
return False
|
||||
return mark.args == func_mark.args and mark.kwargs == func_mark.kwargs
|
||||
return any(mark == info.combined for info in func_mark)
|
||||
|
||||
|
||||
class MarkInfo(object):
|
||||
|
@ -274,9 +274,9 @@ class MarkInfo(object):
|
|||
self.combined = mark
|
||||
self._marks = [mark]
|
||||
|
||||
name = alias('combined.name')
|
||||
args = alias('combined.args')
|
||||
kwargs = alias('combined.kwargs')
|
||||
name = alias('combined.name', warning=MARK_INFO_ATTRIBUTE)
|
||||
args = alias('combined.args', warning=MARK_INFO_ATTRIBUTE)
|
||||
kwargs = alias('combined.kwargs', warning=MARK_INFO_ATTRIBUTE)
|
||||
|
||||
def __repr__(self):
|
||||
return "<MarkInfo {0!r}>".format(self.combined)
|
||||
|
|
|
@ -117,11 +117,7 @@ def pytest_generate_tests(metafunc):
|
|||
if hasattr(metafunc.function, attr):
|
||||
msg = "{0} has '{1}', spelling should be 'parametrize'"
|
||||
raise MarkerError(msg.format(metafunc.function.__name__, attr))
|
||||
try:
|
||||
markers = metafunc.function.parametrize
|
||||
except AttributeError:
|
||||
return
|
||||
for marker in markers:
|
||||
for marker in metafunc.definition.find_markers('parametrize'):
|
||||
metafunc.parametrize(*marker.args, **marker.kwargs)
|
||||
|
||||
|
||||
|
@ -212,6 +208,7 @@ class PyobjContext(object):
|
|||
|
||||
|
||||
class PyobjMixin(PyobjContext):
|
||||
_ALLOW_MARKERS = True
|
||||
|
||||
def __init__(self, *k, **kw):
|
||||
super(PyobjMixin, self).__init__(*k, **kw)
|
||||
|
@ -221,8 +218,9 @@ class PyobjMixin(PyobjContext):
|
|||
obj = getattr(self, '_obj', None)
|
||||
if obj is None:
|
||||
self._obj = obj = self._getobj()
|
||||
# XXX evil hacn
|
||||
self._markers.update(get_unpacked_marks(self.obj))
|
||||
# XXX evil hack
|
||||
if self._ALLOW_MARKERS:
|
||||
self._markers.update(get_unpacked_marks(self.obj))
|
||||
return obj
|
||||
|
||||
def fset(self, value):
|
||||
|
@ -370,8 +368,13 @@ class PyCollector(PyobjMixin, nodes.Collector):
|
|||
transfer_markers(funcobj, cls, module)
|
||||
fm = self.session._fixturemanager
|
||||
fixtureinfo = fm.getfixtureinfo(self, funcobj, cls)
|
||||
metafunc = Metafunc(funcobj, fixtureinfo, self.config,
|
||||
cls=cls, module=module)
|
||||
|
||||
definition = FunctionDefinition(
|
||||
name=name,
|
||||
parent=self,
|
||||
callobj=funcobj,
|
||||
)
|
||||
metafunc = Metafunc(definition, fixtureinfo, self.config, cls=cls, module=module)
|
||||
methods = []
|
||||
if hasattr(module, "pytest_generate_tests"):
|
||||
methods.append(module.pytest_generate_tests)
|
||||
|
@ -530,6 +533,8 @@ class Class(PyCollector):
|
|||
|
||||
|
||||
class Instance(PyCollector):
|
||||
_ALLOW_MARKERS = False # hack, destroy later
|
||||
|
||||
def _getobj(self):
|
||||
return self.parent.obj()
|
||||
|
||||
|
@ -729,15 +734,17 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
|
|||
test function is defined.
|
||||
"""
|
||||
|
||||
def __init__(self, function, fixtureinfo, config, cls=None, module=None):
|
||||
def __init__(self, definition, fixtureinfo, config, cls=None, module=None):
|
||||
#: access to the :class:`_pytest.config.Config` object for the test session
|
||||
assert isinstance(definition, FunctionDefinition)
|
||||
self.definition = definition
|
||||
self.config = config
|
||||
|
||||
#: the module object where the test function is defined in.
|
||||
self.module = module
|
||||
|
||||
#: underlying python test function
|
||||
self.function = function
|
||||
self.function = definition.obj
|
||||
|
||||
#: set of fixture names required by the test function
|
||||
self.fixturenames = fixtureinfo.names_closure
|
||||
|
@ -1189,3 +1196,15 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
|
|||
def setup(self):
|
||||
super(Function, self).setup()
|
||||
fixtures.fillfixtures(self)
|
||||
|
||||
|
||||
class FunctionDefinition(Function):
|
||||
"""
|
||||
internal hack until we get actual definition nodes instead of the
|
||||
crappy metafunc hack
|
||||
"""
|
||||
|
||||
def runtest(self):
|
||||
raise RuntimeError("function definitions are not supposed to be used")
|
||||
|
||||
setup = runtest
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from _pytest.config import hookimpl
|
||||
from _pytest.mark import MarkInfo, MarkDecorator
|
||||
from _pytest.mark.evaluate import MarkEvaluator
|
||||
from _pytest.outcomes import fail, skip, xfail
|
||||
|
||||
|
@ -60,15 +59,12 @@ def pytest_configure(config):
|
|||
def pytest_runtest_setup(item):
|
||||
# Check if skip or skipif are specified as pytest marks
|
||||
item._skipped_by_mark = False
|
||||
skipif_info = item.keywords.get('skipif')
|
||||
if isinstance(skipif_info, (MarkInfo, MarkDecorator)):
|
||||
eval_skipif = MarkEvaluator(item, 'skipif')
|
||||
if eval_skipif.istrue():
|
||||
item._skipped_by_mark = True
|
||||
skip(eval_skipif.getexplanation())
|
||||
eval_skipif = MarkEvaluator(item, 'skipif')
|
||||
if eval_skipif.istrue():
|
||||
item._skipped_by_mark = True
|
||||
skip(eval_skipif.getexplanation())
|
||||
|
||||
skip_info = item.keywords.get('skip')
|
||||
if isinstance(skip_info, (MarkInfo, MarkDecorator)):
|
||||
for skip_info in item.find_markers('skip'):
|
||||
item._skipped_by_mark = True
|
||||
if 'reason' in skip_info.kwargs:
|
||||
skip(skip_info.kwargs['reason'])
|
||||
|
|
|
@ -1781,6 +1781,8 @@ class TestAutouseManagement(object):
|
|||
import pytest
|
||||
values = []
|
||||
def pytest_generate_tests(metafunc):
|
||||
if metafunc.cls is None:
|
||||
assert metafunc.function is test_finish
|
||||
if metafunc.cls is not None:
|
||||
metafunc.parametrize("item", [1,2], scope="class")
|
||||
class TestClass(object):
|
||||
|
@ -1798,7 +1800,7 @@ class TestAutouseManagement(object):
|
|||
assert values == ["setup-1", "step1-1", "step2-1", "teardown-1",
|
||||
"setup-2", "step1-2", "step2-2", "teardown-2",]
|
||||
""")
|
||||
reprec = testdir.inline_run()
|
||||
reprec = testdir.inline_run('-s')
|
||||
reprec.assertoutcome(passed=5)
|
||||
|
||||
def test_ordering_autouse_before_explicit(self, testdir):
|
||||
|
|
|
@ -26,11 +26,17 @@ class TestMetafunc(object):
|
|||
|
||||
names = fixtures.getfuncargnames(func)
|
||||
fixtureinfo = FixtureInfo(names)
|
||||
return python.Metafunc(func, fixtureinfo, config)
|
||||
definition = python.FunctionDefinition(
|
||||
name=func.__name__,
|
||||
parent=None,
|
||||
callobj=func,
|
||||
)
|
||||
return python.Metafunc(definition, fixtureinfo, config)
|
||||
|
||||
def test_no_funcargs(self, testdir):
|
||||
def function():
|
||||
pass
|
||||
|
||||
metafunc = self.Metafunc(function)
|
||||
assert not metafunc.fixturenames
|
||||
repr(metafunc._calls)
|
||||
|
|
|
@ -8,6 +8,8 @@ from _pytest.mark import (
|
|||
EMPTY_PARAMETERSET_OPTION,
|
||||
)
|
||||
|
||||
ignore_markinfo = pytest.mark.filterwarnings('ignore:MarkInfo objects:_pytest.deprecated.RemovedInPytest4Warning')
|
||||
|
||||
|
||||
class TestMark(object):
|
||||
def test_markinfo_repr(self):
|
||||
|
@ -51,6 +53,7 @@ class TestMark(object):
|
|||
mark.hello(f)
|
||||
assert f.hello
|
||||
|
||||
@ignore_markinfo
|
||||
def test_pytest_mark_keywords(self):
|
||||
mark = Mark()
|
||||
|
||||
|
@ -62,6 +65,7 @@ class TestMark(object):
|
|||
assert f.world.kwargs['x'] == 3
|
||||
assert f.world.kwargs['y'] == 4
|
||||
|
||||
@ignore_markinfo
|
||||
def test_apply_multiple_and_merge(self):
|
||||
mark = Mark()
|
||||
|
||||
|
@ -78,6 +82,7 @@ class TestMark(object):
|
|||
assert f.world.kwargs['y'] == 1
|
||||
assert len(f.world.args) == 0
|
||||
|
||||
@ignore_markinfo
|
||||
def test_pytest_mark_positional(self):
|
||||
mark = Mark()
|
||||
|
||||
|
@ -88,6 +93,7 @@ class TestMark(object):
|
|||
assert f.world.args[0] == "hello"
|
||||
mark.world("world")(f)
|
||||
|
||||
@ignore_markinfo
|
||||
def test_pytest_mark_positional_func_and_keyword(self):
|
||||
mark = Mark()
|
||||
|
||||
|
@ -103,6 +109,7 @@ class TestMark(object):
|
|||
assert g.world.args[0] is f
|
||||
assert g.world.kwargs["omega"] == "hello"
|
||||
|
||||
@ignore_markinfo
|
||||
def test_pytest_mark_reuse(self):
|
||||
mark = Mark()
|
||||
|
||||
|
@ -484,6 +491,7 @@ class TestFunctional(object):
|
|||
assert 'hello' in keywords
|
||||
assert 'world' in keywords
|
||||
|
||||
@ignore_markinfo
|
||||
def test_merging_markers(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
import pytest
|
||||
|
@ -621,6 +629,7 @@ class TestFunctional(object):
|
|||
"keyword: *hello*"
|
||||
])
|
||||
|
||||
@ignore_markinfo
|
||||
def test_merging_markers_two_functions(self, testdir):
|
||||
p = testdir.makepyfile("""
|
||||
import pytest
|
||||
|
|
Loading…
Reference in New Issue