introduce a own storage for markers
This commit is contained in:
parent
2962c7367c
commit
360d608da4
|
@ -365,3 +365,28 @@ class NodeKeywords(MappingMixin):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<NodeKeywords for node %s>" % (self.node, )
|
return "<NodeKeywords for node %s>" % (self.node, )
|
||||||
|
|
||||||
|
|
||||||
|
@attr.s(cmp=False, hash=False)
|
||||||
|
class NodeMarkers(object):
|
||||||
|
node = attr.ib(repr=False)
|
||||||
|
own_markers = attr.ib(default=attr.Factory(list))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_node(cls, node):
|
||||||
|
return cls(node=node)
|
||||||
|
|
||||||
|
def update(self, add_markers):
|
||||||
|
"""update the own markers
|
||||||
|
"""
|
||||||
|
self.own_markers.extend(add_markers)
|
||||||
|
|
||||||
|
def find(self, name):
|
||||||
|
"""
|
||||||
|
find markers in own nodes or parent nodes
|
||||||
|
needs a better place
|
||||||
|
"""
|
||||||
|
for node in reversed(self.node.listchain()):
|
||||||
|
for mark in node._markers.own_markers:
|
||||||
|
if mark.name == name:
|
||||||
|
yield mark
|
||||||
|
|
|
@ -4,11 +4,12 @@ import os
|
||||||
import six
|
import six
|
||||||
import py
|
import py
|
||||||
import attr
|
import attr
|
||||||
|
from more_itertools import first
|
||||||
|
|
||||||
import _pytest
|
import _pytest
|
||||||
import _pytest._code
|
import _pytest._code
|
||||||
|
|
||||||
from _pytest.mark.structures import NodeKeywords
|
from _pytest.mark.structures import NodeKeywords, NodeMarkers
|
||||||
|
|
||||||
SEP = "/"
|
SEP = "/"
|
||||||
|
|
||||||
|
@ -89,6 +90,7 @@ class Node(object):
|
||||||
|
|
||||||
#: keywords/markers collected from all scopes
|
#: keywords/markers collected from all scopes
|
||||||
self.keywords = NodeKeywords(self)
|
self.keywords = NodeKeywords(self)
|
||||||
|
self._markers = NodeMarkers.from_node(self)
|
||||||
|
|
||||||
#: allow adding of extra keywords to use for matching
|
#: allow adding of extra keywords to use for matching
|
||||||
self.extra_keyword_matches = set()
|
self.extra_keyword_matches = set()
|
||||||
|
@ -178,15 +180,16 @@ class Node(object):
|
||||||
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
|
||||||
|
self._markers.update([marker])
|
||||||
|
|
||||||
|
def find_markers(self, name):
|
||||||
|
"""find all marks with the given name on the node and its parents"""
|
||||||
|
return self._markers.find(name)
|
||||||
|
|
||||||
def get_marker(self, name):
|
def get_marker(self, name):
|
||||||
""" get a marker object from this node or None if
|
""" get a marker object from this node or None if
|
||||||
the node doesn't have a marker with that name. """
|
the node doesn't have a marker with that name. """
|
||||||
val = self.keywords.get(name, None)
|
return first(self.find_markers(name), None)
|
||||||
if val is not None:
|
|
||||||
from _pytest.mark import MarkInfo, MarkDecorator
|
|
||||||
if isinstance(val, (MarkDecorator, MarkInfo)):
|
|
||||||
return val
|
|
||||||
|
|
||||||
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."""
|
||||||
|
|
|
@ -28,7 +28,7 @@ from _pytest.compat import (
|
||||||
safe_str, getlocation, enum,
|
safe_str, getlocation, enum,
|
||||||
)
|
)
|
||||||
from _pytest.outcomes import fail
|
from _pytest.outcomes import fail
|
||||||
from _pytest.mark.structures import transfer_markers
|
from _pytest.mark.structures import transfer_markers, get_unpacked_marks
|
||||||
|
|
||||||
|
|
||||||
# relative paths that we use to filter traceback entries from appearing to the user;
|
# relative paths that we use to filter traceback entries from appearing to the user;
|
||||||
|
@ -212,11 +212,17 @@ class PyobjContext(object):
|
||||||
|
|
||||||
|
|
||||||
class PyobjMixin(PyobjContext):
|
class PyobjMixin(PyobjContext):
|
||||||
|
|
||||||
|
def __init__(self, *k, **kw):
|
||||||
|
super(PyobjMixin, self).__init__(*k, **kw)
|
||||||
|
|
||||||
def obj():
|
def obj():
|
||||||
def fget(self):
|
def fget(self):
|
||||||
obj = getattr(self, '_obj', None)
|
obj = getattr(self, '_obj', None)
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self._obj = obj = self._getobj()
|
self._obj = obj = self._getobj()
|
||||||
|
# XXX evil hacn
|
||||||
|
self._markers.update(get_unpacked_marks(self.obj))
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def fset(self, value):
|
def fset(self, value):
|
||||||
|
@ -1114,6 +1120,7 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
|
||||||
self.obj = callobj
|
self.obj = callobj
|
||||||
|
|
||||||
self.keywords.update(self.obj.__dict__)
|
self.keywords.update(self.obj.__dict__)
|
||||||
|
self._markers.update(get_unpacked_marks(self.obj))
|
||||||
if callspec:
|
if callspec:
|
||||||
self.callspec = callspec
|
self.callspec = callspec
|
||||||
# this is total hostile and a mess
|
# this is total hostile and a mess
|
||||||
|
@ -1123,6 +1130,7 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
|
||||||
# feel free to cry, this was broken for years before
|
# feel free to cry, this was broken for years before
|
||||||
# and keywords cant fix it per design
|
# and keywords cant fix it per design
|
||||||
self.keywords[mark.name] = mark
|
self.keywords[mark.name] = mark
|
||||||
|
self._markers.update(callspec.marks)
|
||||||
if keywords:
|
if keywords:
|
||||||
self.keywords.update(keywords)
|
self.keywords.update(keywords)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue