33
44import inspect
55import warnings
6+ import attr
67from collections import namedtuple
78from operator import attrgetter
89from six .moves import map
@@ -160,22 +161,26 @@ def pytest_collection_modifyitems(items, config):
160161 items [:] = remaining
161162
162163
163- class MarkMapping :
164+ @attr .s
165+ class MarkMapping (object ):
164166 """Provides a local mapping for markers where item access
165167 resolves to True if the marker is present. """
166168
167- def __init__ (self , keywords ):
168- mymarks = set ()
169+ own_mark_names = attr .ib ()
170+
171+ @classmethod
172+ def from_keywords (cls , keywords ):
173+ mark_names = set ()
169174 for key , value in keywords .items ():
170175 if isinstance (value , MarkInfo ) or isinstance (value , MarkDecorator ):
171- mymarks .add (key )
172- self . _mymarks = mymarks
176+ mark_names .add (key )
177+ return cls ( mark_names )
173178
174179 def __getitem__ (self , name ):
175- return name in self ._mymarks
180+ return name in self .own_mark_names
176181
177182
178- class KeywordMapping :
183+ class KeywordMapping ( object ) :
179184 """Provides a local mapping for keywords.
180185 Given a list of names, map any substring of one of these names to True.
181186 """
@@ -192,7 +197,7 @@ def __getitem__(self, subname):
192197
193198def matchmark (colitem , markexpr ):
194199 """Tries to match on any marker names, attached to the given colitem."""
195- return eval (markexpr , {}, MarkMapping (colitem .keywords ))
200+ return eval (markexpr , {}, MarkMapping . from_keywords (colitem .keywords ))
196201
197202
198203def matchkeyword (colitem , keywordexpr ):
@@ -280,7 +285,21 @@ def istestfunc(func):
280285 getattr (func , "__name__" , "<lambda>" ) != "<lambda>"
281286
282287
283- class MarkDecorator :
288+ @attr .s (frozen = True )
289+ class Mark (object ):
290+ name = attr .ib ()
291+ args = attr .ib ()
292+ kwargs = attr .ib ()
293+
294+ def combined_with (self , other ):
295+ assert self .name == other .name
296+ return Mark (
297+ self .name , self .args + other .args ,
298+ dict (self .kwargs , ** other .kwargs ))
299+
300+
301+ @attr .s
302+ class MarkDecorator (object ):
284303 """ A decorator for test functions and test classes. When applied
285304 it will create :class:`MarkInfo` objects which may be
286305 :ref:`retrieved by hooks as item keywords <excontrolskip>`.
@@ -314,9 +333,7 @@ def test_function():
314333
315334 """
316335
317- def __init__ (self , mark ):
318- assert isinstance (mark , Mark ), repr (mark )
319- self .mark = mark
336+ mark = attr .ib (validator = attr .validators .instance_of (Mark ))
320337
321338 name = alias ('mark.name' )
322339 args = alias ('mark.args' )
@@ -396,15 +413,6 @@ def store_legacy_markinfo(func, mark):
396413 holder .add_mark (mark )
397414
398415
399- class Mark (namedtuple ('Mark' , 'name, args, kwargs' )):
400-
401- def combined_with (self , other ):
402- assert self .name == other .name
403- return Mark (
404- self .name , self .args + other .args ,
405- dict (self .kwargs , ** other .kwargs ))
406-
407-
408416class MarkInfo (object ):
409417 """ Marking object created by :class:`MarkDecorator` instances. """
410418
0 commit comments