|
8 | 8 |
|
9 | 9 |
|
10 | 10 | def alias(name):
|
| 11 | + # todo: introduce deprecationwarnings |
11 | 12 | return property(attrgetter(name), doc='alias for ' + name)
|
12 | 13 |
|
13 | 14 |
|
@@ -329,30 +330,39 @@ def __call__(self, *args, **kwargs):
|
329 | 330 | is_class = inspect.isclass(func)
|
330 | 331 | if len(args) == 1 and (istestfunc(func) or is_class):
|
331 | 332 | if is_class:
|
332 |
| - if hasattr(func, 'pytestmark'): |
333 |
| - mark_list = func.pytestmark |
334 |
| - if not isinstance(mark_list, list): |
335 |
| - mark_list = [mark_list] |
336 |
| - # always work on a copy to avoid updating pytestmark |
337 |
| - # from a superclass by accident |
338 |
| - mark_list = mark_list + [self] |
339 |
| - func.pytestmark = mark_list |
340 |
| - else: |
341 |
| - func.pytestmark = [self] |
| 333 | + apply_mark(func, self.mark) |
342 | 334 | else:
|
343 |
| - holder = getattr(func, self.name, None) |
344 |
| - if holder is None: |
345 |
| - holder = MarkInfo(self.mark) |
346 |
| - setattr(func, self.name, holder) |
347 |
| - else: |
348 |
| - holder.add_mark(self.mark) |
| 335 | + apply_legacy_mark(func, self.mark) |
349 | 336 | return func
|
350 | 337 |
|
351 | 338 | mark = Mark(self.name, args, kwargs)
|
352 | 339 | return self.__class__(self.mark.combined_with(mark))
|
353 | 340 |
|
354 | 341 |
|
| 342 | +def apply_mark(obj, mark): |
| 343 | + assert isinstance(mark, Mark), mark |
| 344 | + """applies a marker to an object, |
| 345 | + makrer transfers only update legacy markinfo objects |
| 346 | + """ |
| 347 | + mark_list = getattr(obj, 'pytestmark', []) |
| 348 | + |
| 349 | + if not isinstance(mark_list, list): |
| 350 | + mark_list = [mark_list] |
| 351 | + # always work on a copy to avoid updating pytestmark |
| 352 | + # from a superclass by accident |
| 353 | + mark_list = mark_list + [mark] |
| 354 | + obj.pytestmark = mark_list |
| 355 | + |
355 | 356 |
|
| 357 | +def apply_legacy_mark(func, mark): |
| 358 | + if not isinstance(mark, Mark): |
| 359 | + raise TypeError("got {mark!r} instead of a Mark".format(mark=mark)) |
| 360 | + holder = getattr(func, mark.name, None) |
| 361 | + if holder is None: |
| 362 | + holder = MarkInfo(mark) |
| 363 | + setattr(func, mark.name, holder) |
| 364 | + else: |
| 365 | + holder.add_mark(mark) |
356 | 366 |
|
357 | 367 |
|
358 | 368 | class Mark(namedtuple('Mark', 'name, args, kwargs')):
|
@@ -404,17 +414,17 @@ def _marked(func, mark):
|
404 | 414 |
|
405 | 415 |
|
406 | 416 | def transfer_markers(funcobj, cls, mod):
|
407 |
| - # XXX this should rather be code in the mark plugin or the mark |
408 |
| - # plugin should merge with the python plugin. |
409 |
| - for holder in (cls, mod): |
410 |
| - try: |
411 |
| - pytestmark = holder.pytestmark |
412 |
| - except AttributeError: |
413 |
| - continue |
414 |
| - if isinstance(pytestmark, list): |
415 |
| - for mark in pytestmark: |
416 |
| - if not _marked(funcobj, mark): |
417 |
| - mark(funcobj) |
418 |
| - else: |
419 |
| - if not _marked(funcobj, pytestmark): |
420 |
| - pytestmark(funcobj) |
| 417 | + """ |
| 418 | + transfer legacy markers to the function level marminfo objects |
| 419 | + this one is a major fsckup for mark breakages |
| 420 | + """ |
| 421 | + for obj in (cls, mod): |
| 422 | + mark_list = getattr(obj, 'pytestmark', []) |
| 423 | + |
| 424 | + if not isinstance(mark_list, list): |
| 425 | + mark_list = [mark_list] |
| 426 | + |
| 427 | + for mark in mark_list: |
| 428 | + mark = getattr(mark, 'mark', mark) # unpack MarkDecorator |
| 429 | + if not _marked(funcobj, mark): |
| 430 | + apply_legacy_mark(funcobj, mark) |
0 commit comments