pytest_cases/fixture_parametrize_plus.py
def parametrize_plus_decorate(test_func):
            """
            A decorator that wraps the test function so that instead of receiving the parameter names, it receives the
            new fixture. All other decorations are unchanged.

            :param test_func:
            :return:
            """
            test_func_name = test_func.__name__

            # Are there explicit ids provided ?
            try:
                if len(ids) != len(argvalues):
                    raise ValueError("Explicit list of `ids` provided has a different length (%s) than the number of "
                                     "parameter sets (%s)" % (len(ids), len(argvalues)))
                explicit_ids_to_use = []
            except TypeError:
                explicit_ids_to_use = None

            # first check if the test function has the parameters as arguments
            old_sig = signature(test_func)
            for p in argnames:
                if p not in old_sig.parameters:
                    raise ValueError("parameter '%s' not found in test function signature '%s%s'"
                                     "" % (p, test_func_name, old_sig))

            # The name for the final "union" fixture
            # style_template = "%s_param__%s"
            main_fixture_style_template = "%s_%s"
            fixture_union_name = main_fixture_style_template % (test_func_name, param_names_str)
            fixture_union_name = check_name_available(caller_module, fixture_union_name, if_name_exists=CHANGE,
                                                      caller=parametrize_plus)

            # Retrieve (if ref) or create (for normal argvalues) the fixtures that we will union
            fixture_alternatives = []
            prev_i = -1
            for i, j_list in fixture_indices:  # noqa
                # A/ Is there any non-empty group of 'normal' parameters before the fixture_ref at <i> ? If so, handle.
                if i > prev_i + 1:
                    # create a new "param" fixture parametrized with all of that consecutive group.
                    # Important note: we could either wish to create one fixture for parameter value or to create
                    #  one for each consecutive group as shown below. This should not lead to different results but perf
                    #  might differ. Maybe add a parameter in the signature so that users can test it ?
                    #  this would make the ids more readable by removing the "P2toP3"-like ids
                    p_fix_name, p_fix_alt = _create_params_alt(test_func_name=test_func_name, hook=hook,
                                                               union_name=fixture_union_name, from_i=prev_i + 1, to_i=i)
                    fixture_alternatives.append((p_fix_name, p_fix_alt))
                    if explicit_ids_to_use is not None:
                        if isinstance(p_fix_alt, SingleParamAlternative):
                            explicit_ids_to_use.append(ids[prev_i + 1])
                        else:
                            # the ids provided by the user are propagated to the params of this fix, so we need an id
                            explicit_ids_to_use.append(ParamIdMakers.explicit(p_fix_alt))

                # B/ Now handle the fixture ref at position <i>
                if j_list is None:
                    # argvalues[i] contains a single argvalue that is a fixture_ref : add the referenced fixture
                    f_fix_name, f_fix_alt = _create_fixture_ref_alt(union_name=fixture_union_name, i=i)
                    fixture_alternatives.append((f_fix_name, f_fix_alt))
                    if explicit_ids_to_use is not None:
                        explicit_ids_to_use.append(ids[i])

                else:
                    # argvalues[i] is a tuple, some of them being fixture_ref. create a fixture refering to all of them
                    prod_fix_name, prod_fix_alt = _create_fixture_ref_product(union_name=fixture_union_name, i=i,
                                                                              fixture_ref_positions=j_list,
                                                                              test_func_name=test_func_name, hook=hook)
                    fixture_alternatives.append((prod_fix_name, prod_fix_alt))
                    if explicit_ids_to_use is not None:
                        explicit_ids_to_use.append(ids[i])

                prev_i = i

            # C/ handle last consecutive group of normal parameters, if any
            i = len(argvalues)  # noqa
            if i > prev_i + 1:
                p_fix_name, p_fix_alt = _create_params_alt(test_func_name=test_func_name, union_name=fixture_union_name,
                                                           from_i=prev_i + 1, to_i=i, hook=hook)
                fixture_alternatives.append((p_fix_name, p_fix_alt))
                if explicit_ids_to_use is not None:
                    if isinstance(p_fix_alt, SingleParamAlternative):
                        explicit_ids_to_use.append(ids[prev_i + 1])
                    else:
                        # the ids provided by the user are propagated to the params of this fix, so we need an id
                        explicit_ids_to_use.append(ParamIdMakers.explicit(p_fix_alt))

            # TO DO if fixtures_to_union has length 1, simplify ? >> No, we leave such "optimization" to the end user

            # consolidate the list of alternatives
            fix_alternatives = tuple(a[1] for a in fixture_alternatives)

            # and the list of their names. Duplicates should be removed here
            fix_alt_names = []
            for a, alt in fixture_alternatives:
                if a not in fix_alt_names:
                    fix_alt_names.append(a)
                else:
                    # this should only happen when the alternative is directly a fixture reference
                    assert isinstance(alt, FixtureParamAlternative), \
                        "Created fixture names are not unique, please report"

            # Finally create a "main" fixture with a unique name for this test function
            if debug:
                print("Creating final union fixture %r with alternatives %r" % (fixture_union_name, fix_alternatives))

            # note: the function automatically registers it in the module
            _make_fixture_union(caller_module, name=fixture_union_name, hook=hook, caller=parametrize_plus,
                                fix_alternatives=fix_alternatives, unique_fix_alt_names=fix_alt_names,
                                ids=explicit_ids_to_use or ids or ParamIdMakers.get(idstyle))

            # --create the new test function's signature that we want to expose to pytest
            # it is the same than existing, except that we want to replace all parameters with the new fixture
            # first check where we should insert the new parameters (where is the first param we remove)
            _first_idx = -1
            for _first_idx, _n in enumerate(old_sig.parameters):
                if _n in argnames:
                    break
            # then remove all parameters that will be replaced by the new fixture
            new_sig = remove_signature_parameters(old_sig, *argnames)
            # finally insert the new fixture in that position. Indeed we can not insert first or last, because
            # 'self' arg (case of test class methods) should stay first and exec order should be preserved when possible
            new_sig = add_signature_parameters(new_sig, custom_idx=_first_idx,
                                               custom=Parameter(fixture_union_name,
                                                                kind=Parameter.POSITIONAL_OR_KEYWORD))

            if debug:
                print("Creating final test function wrapper with signature %s%s" % (test_func_name, new_sig))

            # --Finally create the fixture function, a wrapper of user-provided fixture with the new signature
            def replace_paramfixture_with_values(kwargs):  # noqa
                # remove the created fixture value
                encompassing_fixture = kwargs.pop(fixture_union_name)
                # and add instead the parameter values
                if nb_params > 1:
                    for i, p in enumerate(argnames):  # noqa
                        kwargs[p] = encompassing_fixture[i]
                else:
                    kwargs[argnames[0]] = encompassing_fixture
                # return
                return kwargs

            if not isgeneratorfunction(test_func):
                # normal test function with return statement
                @wraps(test_func, new_sig=new_sig)
                def wrapped_test_func(*args, **kwargs):  # noqa
                    if kwargs.get(fixture_union_name, None) is NOT_USED:
                        # TODO why this ? it is probably useless: this fixture
                        #  is private and will never end up in another union
                        return NOT_USED
                    else:
                        replace_paramfixture_with_values(kwargs)
                        return test_func(*args, **kwargs)

            else:
                # generator test function (with one or several yield statements)
                @wraps(test_func, new_sig=new_sig)
                def wrapped_test_func(*args, **kwargs):  # noqa
                    if kwargs.get(fixture_union_name, None) is NOT_USED:
                        # TODO why this ? it is probably useless: this fixture
                        #  is private and will never end up in another union
                        yield NOT_USED
                    else:
                        replace_paramfixture_with_values(kwargs)
                        for res in test_func(*args, **kwargs):
                            yield res

            # move all pytest marks from the test function to the wrapper
            # not needed because the __dict__ is automatically copied when we use @wraps
            #   move_all_pytest_marks(test_func, wrapped_test_func)

            # With this hack we will be ordered correctly by pytest https://github.com/pytest-dev/pytest/issues/4429
            wrapped_test_func.place_as = test_func

            # return the new test function
            return wrapped_test_func

            A decorator that wraps the test function so that instead of receiving the parameter names, it receives the
            new fixture. All other decorations are unchanged.

            :param test_func:
            :return:
            
A decorator that wraps the test function so that instead of receiving the parameter names, it receives the
new fixture. All other decorations are unchanged.
A decorator that wraps the test function so that instead of receiving the parameter names it receives the new fixture . All other decorations are unchanged .
def parametrize_plus_decorate(test_func):
            test_func_name = test_func.__name__
            try:
                if len(ids) != len(argvalues):
                    raise ValueError("Explicit list of `ids` provided has a different length (%s) than the number of "
                                     "parameter sets (%s)" % (len(ids), len(argvalues)))
                explicit_ids_to_use = []
            except TypeError:
                explicit_ids_to_use = None
            old_sig = signature(test_func)
            for p in argnames:
                if p not in old_sig.parameters:
                    raise ValueError("parameter '%s' not found in test function signature '%s%s'"
                                     "" % (p, test_func_name, old_sig))
            main_fixture_style_template = "%s_%s"
            fixture_union_name = main_fixture_style_template % (test_func_name, param_names_str)
            fixture_union_name = check_name_available(caller_module, fixture_union_name, if_name_exists=CHANGE,
                                                      caller=parametrize_plus)
            fixture_alternatives = []
            prev_i = -1
            for i, j_list in fixture_indices:  
                if i > prev_i + 1:
                    p_fix_name, p_fix_alt = _create_params_alt(test_func_name=test_func_name, hook=hook,
                                                               union_name=fixture_union_name, from_i=prev_i + 1, to_i=i)
                    fixture_alternatives.append((p_fix_name, p_fix_alt))
                    if explicit_ids_to_use is not None:
                        if isinstance(p_fix_alt, SingleParamAlternative):
                            explicit_ids_to_use.append(ids[prev_i + 1])
                        else:
                            explicit_ids_to_use.append(ParamIdMakers.explicit(p_fix_alt))
                if j_list is None:
                    f_fix_name, f_fix_alt = _create_fixture_ref_alt(union_name=fixture_union_name, i=i)
                    fixture_alternatives.append((f_fix_name, f_fix_alt))
                    if explicit_ids_to_use is not None:
                        explicit_ids_to_use.append(ids[i])
                else:
                    prod_fix_name, prod_fix_alt = _create_fixture_ref_product(union_name=fixture_union_name, i=i,
                                                                              fixture_ref_positions=j_list,
                                                                              test_func_name=test_func_name, hook=hook)
                    fixture_alternatives.append((prod_fix_name, prod_fix_alt))
                    if explicit_ids_to_use is not None:
                        explicit_ids_to_use.append(ids[i])
                prev_i = i
            i = len(argvalues)  
            if i > prev_i + 1:
                p_fix_name, p_fix_alt = _create_params_alt(test_func_name=test_func_name, union_name=fixture_union_name,
                                                           from_i=prev_i + 1, to_i=i, hook=hook)
                fixture_alternatives.append((p_fix_name, p_fix_alt))
                if explicit_ids_to_use is not None:
                    if isinstance(p_fix_alt, SingleParamAlternative):
                        explicit_ids_to_use.append(ids[prev_i + 1])
                    else:
                        explicit_ids_to_use.append(ParamIdMakers.explicit(p_fix_alt))
            fix_alternatives = tuple(a[1] for a in fixture_alternatives)
            fix_alt_names = []
            for a, alt in fixture_alternatives:
                if a not in fix_alt_names:
                    fix_alt_names.append(a)
                else:
                    assert isinstance(alt, FixtureParamAlternative), \
                        "Created fixture names are not unique, please report"
            if debug:
                print("Creating final union fixture %r with alternatives %r" % (fixture_union_name, fix_alternatives))
            _make_fixture_union(caller_module, name=fixture_union_name, hook=hook, caller=parametrize_plus,
                                fix_alternatives=fix_alternatives, unique_fix_alt_names=fix_alt_names,
                                ids=explicit_ids_to_use or ids or ParamIdMakers.get(idstyle))
            _first_idx = -1
            for _first_idx, _n in enumerate(old_sig.parameters):
                if _n in argnames:
                    break
            new_sig = remove_signature_parameters(old_sig, *argnames)
            new_sig = add_signature_parameters(new_sig, custom_idx=_first_idx,
                                               custom=Parameter(fixture_union_name,
                                                                kind=Parameter.POSITIONAL_OR_KEYWORD))
            if debug:
                print("Creating final test function wrapper with signature %s%s" % (test_func_name, new_sig))
            def replace_paramfixture_with_values(kwargs):  
                encompassing_fixture = kwargs.pop(fixture_union_name)
                if nb_params > 1:
                    for i, p in enumerate(argnames):  
                        kwargs[p] = encompassing_fixture[i]
                else:
                    kwargs[argnames[0]] = encompassing_fixture
                return kwargs
            if not isgeneratorfunction(test_func):
                @wraps(test_func, new_sig=new_sig)
                def wrapped_test_func(*args, **kwargs):  
                    if kwargs.get(fixture_union_name, None) is NOT_USED:
                        return NOT_USED
                    else:
                        replace_paramfixture_with_values(kwargs)
                        return test_func(*args, **kwargs)
            else:
                @wraps(test_func, new_sig=new_sig)
                def wrapped_test_func(*args, **kwargs):  
                    if kwargs.get(fixture_union_name, None) is NOT_USED:
                        yield NOT_USED
                    else:
                        replace_paramfixture_with_values(kwargs)
                        for res in test_func(*args, **kwargs):
                            yield res
            wrapped_test_func.place_as = test_func
             the new test function
            return wrapped_test_func
def parametrize_plus_decorate ( test_func ) : test_func_name = test_func . __name__ try : if len ( ids ) != len ( argvalues ) : raise ValueError ( "Explicit list of `ids` provided has a different length (%s) than the number of " "parameter sets (%s)" % ( len ( ids ) , len ( argvalues ) ) ) explicit_ids_to_use = [ ] except TypeError : explicit_ids_to_use = None old_sig = signature ( test_func ) for p in argnames : if p not in old_sig . parameters : raise ValueError ( "parameter '%s' not found in test function signature '%s%s'" "" % ( p , test_func_name , old_sig ) ) main_fixture_style_template = "%s_%s" fixture_union_name = main_fixture_style_template % ( test_func_name , param_names_str ) fixture_union_name = check_name_available ( caller_module , fixture_union_name , if_name_exists = CHANGE , caller = parametrize_plus ) fixture_alternatives = [ ] prev_i = - 1 for i , j_list in fixture_indices : if i > prev_i + 1 : p_fix_name , p_fix_alt = _create_params_alt ( test_func_name = test_func_name , hook = hook , union_name = fixture_union_name , from_i = prev_i + 1 , to_i = i ) fixture_alternatives . append ( ( p_fix_name , p_fix_alt ) ) if explicit_ids_to_use is not None : if isinstance ( p_fix_alt , SingleParamAlternative ) : explicit_ids_to_use . append ( ids [ prev_i + 1 ] ) else : explicit_ids_to_use . append ( ParamIdMakers . explicit ( p_fix_alt ) ) if j_list is None : f_fix_name , f_fix_alt = _create_fixture_ref_alt ( union_name = fixture_union_name , i = i ) fixture_alternatives . append ( ( f_fix_name , f_fix_alt ) ) if explicit_ids_to_use is not None : explicit_ids_to_use . append ( ids [ i ] ) else : prod_fix_name , prod_fix_alt = _create_fixture_ref_product ( union_name = fixture_union_name , i = i , fixture_ref_positions = j_list , test_func_name = test_func_name , hook = hook ) fixture_alternatives . append ( ( prod_fix_name , prod_fix_alt ) ) if explicit_ids_to_use is not None : explicit_ids_to_use . append ( ids [ i ] ) prev_i = i i = len ( argvalues ) if i > prev_i + 1 : p_fix_name , p_fix_alt = _create_params_alt ( test_func_name = test_func_name , union_name = fixture_union_name , from_i = prev_i + 1 , to_i = i , hook = hook ) fixture_alternatives . append ( ( p_fix_name , p_fix_alt ) ) if explicit_ids_to_use is not None : if isinstance ( p_fix_alt , SingleParamAlternative ) : explicit_ids_to_use . append ( ids [ prev_i + 1 ] ) else : explicit_ids_to_use . append ( ParamIdMakers . explicit ( p_fix_alt ) ) fix_alternatives = tuple ( a [ 1 ] for a in fixture_alternatives ) fix_alt_names = [ ] for a , alt in fixture_alternatives : if a not in fix_alt_names : fix_alt_names . append ( a ) else : assert isinstance ( alt , FixtureParamAlternative ) , "Created fixture names are not unique, please report" if debug : print ( "Creating final union fixture %r with alternatives %r" % ( fixture_union_name , fix_alternatives ) ) _make_fixture_union ( caller_module , name = fixture_union_name , hook = hook , caller = parametrize_plus , fix_alternatives = fix_alternatives , unique_fix_alt_names = fix_alt_names , ids = explicit_ids_to_use or ids or ParamIdMakers . get ( idstyle ) ) _first_idx = - 1 for _first_idx , _n in enumerate ( old_sig . parameters ) : if _n in argnames : break new_sig = remove_signature_parameters ( old_sig , * argnames ) new_sig = add_signature_parameters ( new_sig , custom_idx = _first_idx , custom = Parameter ( fixture_union_name , kind = Parameter . POSITIONAL_OR_KEYWORD ) ) if debug : print ( "Creating final test function wrapper with signature %s%s" % ( test_func_name , new_sig ) ) def replace_paramfixture_with_values ( kwargs ) : encompassing_fixture = kwargs . pop ( fixture_union_name ) if nb_params > 1 : for i , p in enumerate ( argnames ) : kwargs [ p ] = encompassing_fixture [ i ] else : kwargs [ argnames [ 0 ] ] = encompassing_fixture return kwargs if not isgeneratorfunction ( test_func ) : @ wraps ( test_func , new_sig = new_sig ) def wrapped_test_func ( * args , ** kwargs ) : if kwargs . get ( fixture_union_name , None ) is NOT_USED : return NOT_USED else : replace_paramfixture_with_values ( kwargs ) return test_func ( * args , ** kwargs ) else : @ wraps ( test_func , new_sig = new_sig ) def wrapped_test_func ( * args , ** kwargs ) : if kwargs . get ( fixture_union_name , None ) is NOT_USED : yield NOT_USED else : replace_paramfixture_with_values ( kwargs ) for res in test_func ( * args , ** kwargs ) : yield res wrapped_test_func . place_as = test_func return wrapped_test_func
A decorator that wraps the test function so that instead of receiving the parameter names, it receives the
new fixture.
A decorator that wraps the test function so that instead of receiving the parameter names it receives the new fixture .
"""
            A decorator that wraps the test function so that instead of receiving the parameter names, it receives the
            new fixture. All other decorations are unchanged.

            :param test_func:
            :return:
            """ # Are there explicit ids provided ? # first check if the test function has the parameters as arguments # The name for the final "union" fixture # style_template = "%s_param__%s" # Retrieve (if ref) or create (for normal argvalues) the fixtures that we will union # noqa # A/ Is there any non-empty group of 'normal' parameters before the fixture_ref at <i> ? If so, handle. # create a new "param" fixture parametrized with all of that consecutive group. # Important note: we could either wish to create one fixture for parameter value or to create #  one for each consecutive group as shown below. This should not lead to different results but perf #  might differ. Maybe add a parameter in the signature so that users can test it ? #  this would make the ids more readable by removing the "P2toP3"-like ids # the ids provided by the user are propagated to the params of this fix, so we need an id # B/ Now handle the fixture ref at position <i> # argvalues[i] contains a single argvalue that is a fixture_ref : add the referenced fixture # argvalues[i] is a tuple, some of them being fixture_ref. create a fixture refering to all of them # C/ handle last consecutive group of normal parameters, if any # noqa # the ids provided by the user are propagated to the params of this fix, so we need an id # TO DO if fixtures_to_union has length 1, simplify ? >> No, we leave such "optimization" to the end user # consolidate the list of alternatives # and the list of their names. Duplicates should be removed here # this should only happen when the alternative is directly a fixture reference # Finally create a "main" fixture with a unique name for this test function # note: the function automatically registers it in the module # --create the new test function's signature that we want to expose to pytest # it is the same than existing, except that we want to replace all parameters with the new fixture # first check where we should insert the new parameters (where is the first param we remove) # then remove all parameters that will be replaced by the new fixture # finally insert the new fixture in that position. Indeed we can not insert first or last, because # 'self' arg (case of test class methods) should stay first and exec order should be preserved when possible # --Finally create the fixture function, a wrapper of user-provided fixture with the new signature # noqa # remove the created fixture value # and add instead the parameter values # noqa # return # normal test function with return statement # noqa # TODO why this ? it is probably useless: this fixture #  is private and will never end up in another union # generator test function (with one or several yield statements) # noqa # TODO why this ? it is probably useless: this fixture #  is private and will never end up in another union # move all pytest marks from the test function to the wrapper # not needed because the __dict__ is automatically copied when we use @wraps #   move_all_pytest_marks(test_func, wrapped_test_func) # With this hack we will be ordered correctly by pytest https://github.com/pytest-dev/pytest/issues/4429 # return the new test function
None
test_func
None