@@ -501,47 +501,94 @@ def datasets_decorator(test_func):
501501 # First list all cases according to user preferences
502502 _cases = get_all_cases (cases , module , test_func , has_tag , filter )
503503
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 )
507506
508507 # 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 )
510509
511510 return parametrizer (test_func )
512511
513512 return datasets_decorator
514513
515514
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+
516538# Compatibility for the way we put marks on single parameters in the list passed to @pytest.mark.parametrize
517539# see https://docs.pytest.org/en/3.3.0/skipping.html?highlight=mark%20parametrize#skip-xfail-with-parametrize
518540
519541try :
542+ # check if pytest.param exists
520543 _ = 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 ))
524544except 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
525547 def get_marked_parameter_for_case (c , marks ):
526548 if len (marks ) > 1 :
527549 raise ValueError ("Multiple marks on parameters not supported for old versions of pytest" )
528550 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 )
532564
533565
534566def transform_marks_into_decorators (marks ):
535567 """
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+
537571 :param marks:
538572 :return:
539573 """
540574 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 ))
545592 return marks_mod
546593
547594
@@ -555,9 +602,6 @@ def get_all_cases(cases=None, # type: Union[Callable[[Any], Any],
555602 """
556603 Lists all desired cases from the user inputs. This function may be convenient for debugging purposes.
557604
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-
561605 :param cases: a single case or a hardcoded list of cases to use. Only one of `cases` and `module` should be set.
562606 :param module: a module or a hardcoded list of modules to use. You may use `THIS_MODULE` to indicate that the
563607 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],
592636 m = sys .modules [this_module_object .__module__ ] if module is THIS_MODULE else module
593637 _cases = extract_cases_from_module (m , has_tag = has_tag , filter = filter )
594638
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-
598639 return _cases
599640
600641
0 commit comments