use consistent inner repressentation for marks
This commit is contained in:
parent
98ac1dd34b
commit
10094a3f09
|
@ -356,7 +356,7 @@ class Node(object):
|
||||||
"""
|
"""
|
||||||
from _pytest.mark import MarkDecorator
|
from _pytest.mark import MarkDecorator
|
||||||
if isinstance(marker, py.builtin._basestring):
|
if isinstance(marker, py.builtin._basestring):
|
||||||
marker = MarkDecorator(marker)
|
marker = getattr(pytest.mark, marker)
|
||||||
elif not isinstance(marker, MarkDecorator):
|
elif not isinstance(marker, MarkDecorator):
|
||||||
raise ValueError("is not a string or pytest.mark.* Marker")
|
raise ValueError("is not a string or pytest.mark.* Marker")
|
||||||
self.keywords[marker.name] = marker
|
self.keywords[marker.name] = marker
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
""" generic mechanism for marking and selecting python functions. """
|
""" generic mechanism for marking and selecting python functions. """
|
||||||
import inspect
|
import inspect
|
||||||
|
from collections import namedtuple
|
||||||
|
from operator import attrgetter
|
||||||
|
from itertools import imap
|
||||||
|
|
||||||
|
def alias(name):
|
||||||
|
return property(attrgetter(name), doc='alias for ' + name)
|
||||||
|
|
||||||
|
|
||||||
class MarkerError(Exception):
|
class MarkerError(Exception):
|
||||||
|
@ -182,7 +188,7 @@ class MarkGenerator:
|
||||||
raise AttributeError("Marker name must NOT start with underscore")
|
raise AttributeError("Marker name must NOT start with underscore")
|
||||||
if hasattr(self, '_config'):
|
if hasattr(self, '_config'):
|
||||||
self._check(name)
|
self._check(name)
|
||||||
return MarkDecorator(name)
|
return MarkDecorator(Mark(name, (), {}))
|
||||||
|
|
||||||
def _check(self, name):
|
def _check(self, name):
|
||||||
try:
|
try:
|
||||||
|
@ -235,19 +241,20 @@ class MarkDecorator:
|
||||||
additional keyword or positional arguments.
|
additional keyword or positional arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, name, args=None, kwargs=None):
|
def __init__(self, mark):
|
||||||
self.name = name
|
assert isinstance(mark, Mark), repr(mark)
|
||||||
self.args = args or ()
|
self.mark = mark
|
||||||
self.kwargs = kwargs or {}
|
|
||||||
|
name = alias('mark.name')
|
||||||
|
args = alias('mark.args')
|
||||||
|
kwargs = alias('mark.kwargs')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def markname(self):
|
def markname(self):
|
||||||
return self.name # for backward-compat (2.4.1 had this attr)
|
return self.name # for backward-compat (2.4.1 had this attr)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
d = self.__dict__.copy()
|
return "<MarkDecorator %r>" % self.mark
|
||||||
name = d.pop('name')
|
|
||||||
return "<MarkDecorator %r %r>" % (name, d)
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
""" if passed a single callable argument: decorate it with mark info.
|
""" if passed a single callable argument: decorate it with mark info.
|
||||||
|
@ -270,17 +277,14 @@ class MarkDecorator:
|
||||||
else:
|
else:
|
||||||
holder = getattr(func, self.name, None)
|
holder = getattr(func, self.name, None)
|
||||||
if holder is None:
|
if holder is None:
|
||||||
holder = MarkInfo(
|
holder = MarkInfo(self.mark)
|
||||||
self.name, self.args, self.kwargs
|
|
||||||
)
|
|
||||||
setattr(func, self.name, holder)
|
setattr(func, self.name, holder)
|
||||||
else:
|
else:
|
||||||
holder.add(self.args, self.kwargs)
|
holder.add_mark(self.mark)
|
||||||
return func
|
return func
|
||||||
kw = self.kwargs.copy()
|
|
||||||
kw.update(kwargs)
|
mark = Mark(self.name, args, kwargs)
|
||||||
args = self.args + args
|
return self.__class__(self.mark.combined_with(mark))
|
||||||
return self.__class__(self.name, args=args, kwargs=kw)
|
|
||||||
|
|
||||||
|
|
||||||
def extract_argvalue(maybe_marked_args):
|
def extract_argvalue(maybe_marked_args):
|
||||||
|
@ -291,36 +295,41 @@ def extract_argvalue(maybe_marked_args):
|
||||||
newmarks = {}
|
newmarks = {}
|
||||||
argval = maybe_marked_args
|
argval = maybe_marked_args
|
||||||
while isinstance(argval, MarkDecorator):
|
while isinstance(argval, MarkDecorator):
|
||||||
newmark = MarkDecorator(argval.markname,
|
newmark = MarkDecorator(Mark(
|
||||||
argval.args[:-1], argval.kwargs)
|
argval.markname, argval.args[:-1], argval.kwargs))
|
||||||
newmarks[newmark.markname] = newmark
|
newmarks[newmark.name] = newmark
|
||||||
argval = argval.args[-1]
|
argval = argval.args[-1]
|
||||||
return argval, newmarks
|
return argval, newmarks
|
||||||
|
|
||||||
|
|
||||||
class MarkInfo:
|
class Mark(namedtuple('Mark', 'name, args, kwargs')):
|
||||||
|
|
||||||
|
def combined_with(self, other):
|
||||||
|
assert self.name == other.name
|
||||||
|
return Mark(
|
||||||
|
self.name, self.args + other.args,
|
||||||
|
dict(self.kwargs, **other.kwargs))
|
||||||
|
|
||||||
|
|
||||||
|
class MarkInfo(object):
|
||||||
""" Marking object created by :class:`MarkDecorator` instances. """
|
""" Marking object created by :class:`MarkDecorator` instances. """
|
||||||
def __init__(self, name, args, kwargs):
|
def __init__(self, mark):
|
||||||
#: name of attribute
|
assert isinstance(mark, Mark), repr(mark)
|
||||||
self.name = name
|
self.combined = mark
|
||||||
#: positional argument list, empty if none specified
|
self._marks = [mark]
|
||||||
self.args = args
|
|
||||||
#: keyword argument dictionary, empty if nothing specified
|
name = alias('combined.name')
|
||||||
self.kwargs = kwargs.copy()
|
args = alias('combined.args')
|
||||||
self._arglist = [(args, kwargs.copy())]
|
kwargs = alias('combined.kwargs')
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<MarkInfo %r args=%r kwargs=%r>" % (
|
return "<MarkInfo {0!r}>".format(self.combined)
|
||||||
self.name, self.args, self.kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
def add(self, args, kwargs):
|
def add_mark(self, mark):
|
||||||
""" add a MarkInfo with the given args and kwargs. """
|
""" add a MarkInfo with the given args and kwargs. """
|
||||||
self._arglist.append((args, kwargs))
|
self._marks.append(mark)
|
||||||
self.args += args
|
self.combined = self.combined.combined_with(mark)
|
||||||
self.kwargs.update(kwargs)
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
""" yield MarkInfo objects each relating to a marking-call. """
|
""" yield MarkInfo objects each relating to a marking-call. """
|
||||||
for args, kwargs in self._arglist:
|
return imap(MarkInfo, self._marks)
|
||||||
yield MarkInfo(self.name, args, kwargs)
|
|
||||||
|
|
|
@ -121,11 +121,9 @@ class MarkEvaluator:
|
||||||
# "holder" might be a MarkInfo or a MarkDecorator; only
|
# "holder" might be a MarkInfo or a MarkDecorator; only
|
||||||
# MarkInfo keeps track of all parameters it received in an
|
# MarkInfo keeps track of all parameters it received in an
|
||||||
# _arglist attribute
|
# _arglist attribute
|
||||||
if hasattr(self.holder, '_arglist'):
|
marks = getattr(self.holder, '_marks', None) \
|
||||||
arglist = self.holder._arglist
|
or [self.holder.mark]
|
||||||
else:
|
for _, args, kwargs in marks:
|
||||||
arglist = [(self.holder.args, self.holder.kwargs)]
|
|
||||||
for args, kwargs in arglist:
|
|
||||||
if 'condition' in kwargs:
|
if 'condition' in kwargs:
|
||||||
args = (kwargs['condition'],)
|
args = (kwargs['condition'],)
|
||||||
for expr in args:
|
for expr in args:
|
||||||
|
|
|
@ -5,8 +5,8 @@ from _pytest.mark import MarkGenerator as Mark
|
||||||
|
|
||||||
class TestMark:
|
class TestMark:
|
||||||
def test_markinfo_repr(self):
|
def test_markinfo_repr(self):
|
||||||
from _pytest.mark import MarkInfo
|
from _pytest.mark import MarkInfo, Mark
|
||||||
m = MarkInfo("hello", (1,2), {})
|
m = MarkInfo(Mark("hello", (1,2), {}))
|
||||||
repr(m)
|
repr(m)
|
||||||
|
|
||||||
def test_pytest_exists_in_namespace_all(self):
|
def test_pytest_exists_in_namespace_all(self):
|
||||||
|
|
Loading…
Reference in New Issue