3
3
4
4
import inspect
5
5
import warnings
6
+ import attr
6
7
from collections import namedtuple
7
8
from operator import attrgetter
8
9
from six .moves import map
@@ -160,22 +161,26 @@ def pytest_collection_modifyitems(items, config):
160
161
items [:] = remaining
161
162
162
163
163
- class MarkMapping :
164
+ @attr .s
165
+ class MarkMapping (object ):
164
166
"""Provides a local mapping for markers where item access
165
167
resolves to True if the marker is present. """
166
168
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 ()
169
174
for key , value in keywords .items ():
170
175
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 )
173
178
174
179
def __getitem__ (self , name ):
175
- return name in self ._mymarks
180
+ return name in self .own_mark_names
176
181
177
182
178
- class KeywordMapping :
183
+ class KeywordMapping ( object ) :
179
184
"""Provides a local mapping for keywords.
180
185
Given a list of names, map any substring of one of these names to True.
181
186
"""
@@ -192,7 +197,7 @@ def __getitem__(self, subname):
192
197
193
198
def matchmark (colitem , markexpr ):
194
199
"""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 ))
196
201
197
202
198
203
def matchkeyword (colitem , keywordexpr ):
@@ -280,7 +285,21 @@ def istestfunc(func):
280
285
getattr (func , "__name__" , "<lambda>" ) != "<lambda>"
281
286
282
287
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 ):
284
303
""" A decorator for test functions and test classes. When applied
285
304
it will create :class:`MarkInfo` objects which may be
286
305
:ref:`retrieved by hooks as item keywords <excontrolskip>`.
@@ -314,9 +333,7 @@ def test_function():
314
333
315
334
"""
316
335
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 ))
320
337
321
338
name = alias ('mark.name' )
322
339
args = alias ('mark.args' )
@@ -396,15 +413,6 @@ def store_legacy_markinfo(func, mark):
396
413
holder .add_mark (mark )
397
414
398
415
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
-
408
416
class MarkInfo (object ):
409
417
""" Marking object created by :class:`MarkDecorator` instances. """
410
418
0 commit comments