introduce a own storage for markers

This commit is contained in:
Ronny Pfannschmidt 2018-03-16 11:02:34 +01:00
parent 2962c7367c
commit 360d608da4
3 changed files with 43 additions and 7 deletions

View File

@ -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

View File

@ -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."""

View File

@ -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)