@@ -501,47 +501,94 @@ def datasets_decorator(test_func):
501
501
# First list all cases according to user preferences
502
502
_cases = get_all_cases (cases , module , test_func , has_tag , filter )
503
503
504
- # old: use id getter function : cases_ids = str
505
- # new: hardcode the case ids, safer (?) in case this is mixed with another fixture
506
- cases_ids = [str (c ) for c in _cases ]
504
+ # Then transform into required arguments for pytest (applying the pytest marks if needed)
505
+ marked_cases , cases_ids = get_pytest_parametrize_args (_cases )
507
506
508
507
# Finally create the pytest decorator and apply it
509
- parametrizer = pytest .mark .parametrize (case_data_argname , _cases , ids = cases_ids )
508
+ parametrizer = pytest .mark .parametrize (case_data_argname , marked_cases , ids = cases_ids )
510
509
511
510
return parametrizer (test_func )
512
511
513
512
return datasets_decorator
514
513
515
514
515
+ def get_pytest_parametrize_args (cases ):
516
+ """
517
+ Transforms a list of cases into a tuple containing the arguments to use in `@pytest.mark.parametrize`
518
+ the tuple is (marked_cases, ids) where
519
+
520
+ - marked_cases is a list containing either the case or a pytest-marked case (using the pytest marks that were
521
+ present on the case function)
522
+ - ids is a list containing the case ids to use as test ids.
523
+
524
+ :param cases:
525
+ :return: (marked_cases, ids)
526
+ """
527
+ # hardcode the case ids, as simply passing 'ids=str' would not work when cases are marked cases
528
+ case_ids = [str (c ) for c in cases ]
529
+
530
+ # create the pytest parameter values with the appropriate pytest marks
531
+ marked_cases = [c if len (c .get_marks ()) == 0 else get_marked_parameter_for_case (c , marks = c .get_marks ())
532
+ for c in cases ]
533
+
534
+ return marked_cases , case_ids
535
+
536
+
537
+
516
538
# Compatibility for the way we put marks on single parameters in the list passed to @pytest.mark.parametrize
517
539
# see https://docs.pytest.org/en/3.3.0/skipping.html?highlight=mark%20parametrize#skip-xfail-with-parametrize
518
540
519
541
try :
542
+ # check if pytest.param exists
520
543
_ = pytest .param
521
- def get_marked_parameter_for_case (c , marks ):
522
- marks_mod = transform_marks_into_decorators (marks )
523
- return pytest .param (c , marks = marks_mod , id = str (c ))
524
544
except AttributeError :
545
+ # if not this is how it was done
546
+ # see e.g. https://docs.pytest.org/en/2.9.2/skipping.html?highlight=mark%20parameter#skip-xfail-with-parametrize
525
547
def get_marked_parameter_for_case (c , marks ):
526
548
if len (marks ) > 1 :
527
549
raise ValueError ("Multiple marks on parameters not supported for old versions of pytest" )
528
550
else :
529
- markinfo = marks [0 ]
530
- markinfodecorator = getattr (pytest .mark , markinfo .name )
531
- return markinfodecorator (* markinfo .args )(c )
551
+ # get a decorator for each of the markinfo
552
+ marks_mod = transform_marks_into_decorators (marks )
553
+
554
+ # decorate
555
+ return marks_mod [0 ](c )
556
+ else :
557
+ # Otherise pytest.param exists, it is easier
558
+ def get_marked_parameter_for_case (c , marks ):
559
+ # get a decorator for each of the markinfo
560
+ marks_mod = transform_marks_into_decorators (marks )
561
+
562
+ # decorate
563
+ return pytest .param (c , marks = marks_mod )
532
564
533
565
534
566
def transform_marks_into_decorators (marks ):
535
567
"""
536
- Transforms the provided marks (MarkInfo) into MarkDecorator
568
+ Transforms the provided marks (MarkInfo) obtained from marked cases, into MarkDecorator so that they can
569
+ be re-applied to generated pytest parameters in the global @pytest.mark.parametrize.
570
+
537
571
:param marks:
538
572
:return:
539
573
"""
540
574
marks_mod = []
541
- for m in marks :
542
- md = pytest .mark .MarkDecorator ()
543
- md .mark = m
544
- marks_mod .append (md )
575
+ try :
576
+ for m in marks :
577
+ md = pytest .mark .MarkDecorator ()
578
+ if LooseVersion (pytest .__version__ ) >= LooseVersion ('3.0.0' ):
579
+ md .mark = m
580
+ else :
581
+ md .name = m .name
582
+ # md.markname = m.name
583
+ md .args = m .args
584
+ md .kwargs = m .kwargs
585
+
586
+ # markinfodecorator = getattr(pytest.mark, markinfo.name)
587
+ # markinfodecorator(*markinfo.args)
588
+
589
+ marks_mod .append (md )
590
+ except Exception as e :
591
+ warn ("Caught exception while trying to mark case: [%s] %s" % (type (e ), e ))
545
592
return marks_mod
546
593
547
594
@@ -555,9 +602,6 @@ def get_all_cases(cases=None, # type: Union[Callable[[Any], Any],
555
602
"""
556
603
Lists all desired cases from the user inputs. This function may be convenient for debugging purposes.
557
604
558
- Note: at the end of execution this function modifies the list of cases so that the pytest marks are applied
559
- correctly for usage of the result as the parameter in a `@pytest.mark.parametrize`.
560
-
561
605
:param cases: a single case or a hardcoded list of cases to use. Only one of `cases` and `module` should be set.
562
606
:param module: a module or a hardcoded list of modules to use. You may use `THIS_MODULE` to indicate that the
563
607
module is the current one. Only one of `cases` and `module` should be set.
@@ -592,9 +636,6 @@ def get_all_cases(cases=None, # type: Union[Callable[[Any], Any],
592
636
m = sys .modules [this_module_object .__module__ ] if module is THIS_MODULE else module
593
637
_cases = extract_cases_from_module (m , has_tag = has_tag , filter = filter )
594
638
595
- # create the pytest parameters to handle pytest marks
596
- _cases = [c if len (c .get_marks ()) == 0 else get_marked_parameter_for_case (c , marks = c .get_marks ()) for c in _cases ]
597
-
598
639
return _cases
599
640
600
641
0 commit comments