Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
@with_signature(new_sig)
def depends_on(*steps, **kwargs):
"""
Decorates a test step object so as to automatically mark it as skipped (default) or failed if the dependency
has not succeeded.
:param steps: a list of test steps that this step depends on. They can be anything, but typically they are non-test
(not prefixed with 'test') functions.
:param fail_instead_of_skip: if set to True, the test will be marked as failed instead of skipped when the
dependencies have not succeeded.
:return:
"""
# python 2 compatibility: no keyword arguments can follow an *args.
fail_instead_of_skip = kwargs.pop('fail_instead_of_skip', _FAIL_INSTEAD_OF_SKIP_DEFAULT)
if len(kwargs) > 0:
raise ValueError("Invalid argument(s): " + str(kwargs.keys()))
@with_signature("%s(%s)" % (root_fixture_name, argnames))
def _root_fixture(**kwargs):
return tuple(kwargs[k] for k in argnames_lst)
@with_signature("%s(%s, request)" % (name, ', '.join(f_names_args)))
def _new_fixture(request, **all_fixtures):
if not is_used_request(request):
return NOT_USED
else:
alternative = request.param
if isinstance(alternative, UnionFixtureAlternative):
fixture_to_use = alternative.fixture_name
return all_fixtures[fixture_to_use]
else:
raise TypeError("Union Fixture %s received invalid parameter type: %s. Please report this issue."
"" % (name, alternative.__class__))
@with_signature("%s(%s)" % (root_fixture_name, argnames))
def _root_fixture(**_kwargs):
return tuple(_kwargs[k] for k in argnames_lst)
def one_fixture_per_step_decorate(fixture_fun):
""" Implementation of the @one_fixture_per_step decorator, for manual decoration"""
def _check_scope(request):
scope = get_scope(request)
if scope != 'function':
# session- or module-scope
raise Exception("The `@one_fixture_per_step` decorator is only useful for function-scope fixtures. `%s`"
" seems to have scope='%s'. Consider removing `@one_fixture_per_step` or changing "
"the scope to 'function'." % (fixture_fun, scope))
# We will expose a new signature with additional arguments
orig_sig = signature(fixture_fun)
func_needs_request = 'request' in orig_sig.parameters
if not func_needs_request:
new_sig = add_signature_parameters(orig_sig, first=Parameter('request', kind=Parameter.POSITIONAL_OR_KEYWORD))
else:
new_sig = orig_sig
if not isgeneratorfunction(fixture_fun):
@wraps(fixture_fun, new_sig=new_sig)
def _steps_aware_decorated_function(*args, **kwargs):
request = kwargs['request'] if func_needs_request else kwargs.pop('request')
_check_scope(request)
res = fixture_fun(*args, **kwargs)
return _OnePerStepFixtureProxy(res)
else:
@wraps(fixture_fun, new_sig=new_sig)
def _steps_aware_decorated_function(*args, **kwargs):
request = kwargs['request'] if func_needs_request else kwargs.pop('request')
_check_scope(request)
gen = fixture_fun(*args, **kwargs)
# note: the function automatically registers it in the module
# note 2: idstyle is set to None because we provide an explicit enough list of ids
big_param_fixture = _fixture_union(caller_module, fixture_union_name, fixtures_to_union, idstyle=None,
ids=fixtures_to_union_names_for_ids, hook=hook)
# --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)
for _first_idx, _n in enumerate(old_sig.parameters):
if _n in all_param_names:
break
# then remove all parameters that will be replaced by the new fixture
new_sig = remove_signature_parameters(old_sig, *all_param_names)
# 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))
# --Finally create the fixture function, a wrapper of user-provided fixture with the new signature
def replace_paramfixture_with_values(kwargs):
# 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(all_param_names):
kwargs[p] = encompassing_fixture[i]
else:
kwargs[all_param_names[0]] = encompassing_fixture
# return
return kwargs
if not isgeneratorfunction(test_func):
# Transform the steps into ids if needed
step_ids = [create_pytest_param_str_id(f) for f in steps]
# Create the container that will hold all execution monitors for this function
# TODO maybe have later a single 'monitor' instance at plugin level... like in pytest-benchmark
all_monitors = StepMonitorsContainer(test_func, step_ids)
# Create the function wrapper.
# We will expose a new signature with additional 'request' arguments if needed, and the test step
orig_sig = signature(test_func)
func_needs_request = 'request' in orig_sig.parameters
additional_params = (Parameter(test_step_argname, kind=Parameter.POSITIONAL_OR_KEYWORD), ) \
+ ((Parameter('request', kind=Parameter.POSITIONAL_OR_KEYWORD), )
if not func_needs_request else ())
# add request parameter last, as first may be 'self'
new_sig = add_signature_parameters(orig_sig, last=additional_params)
# -- first create the logic
@wraps(test_func, new_sig=new_sig)
def wrapped_test_function(*args, **kwargs):
step_name = kwargs.pop(test_step_argname)
request = kwargs['request'] if func_needs_request else kwargs.pop('request')
if request is None:
# we are manually called outside of pytest. let's execute all steps at nce
if step_name is None:
# print("@test_steps - decorated function '%s' is being called manually. The `%s` parameter is set "
# "to None so all steps will be executed in order" % (f, test_step_argname))
step_names = step_ids
else:
# print("@test_steps - decorated function '%s' is being called manually. The `%s` parameter is set "
# "to %s so only these steps will be executed in order. Note that the order should be feasible"
# "" % (f, test_step_argname, step_name))
raise ValueError("Internal error related to fixture parametrization- please report")
# (4) wrap the fixture function so as to remove the parameter names and add 'request' if needed
all_param_names = tuple(v for l in params_names_or_name_combinations for v in l)
# --create the new signature that we want to expose to pytest
old_sig = signature(fixture_func)
for p in all_param_names:
if p not in old_sig.parameters:
raise ValueError("parameter '%s' not found in fixture signature '%s%s'"
"" % (p, fixture_func.__name__, old_sig))
new_sig = remove_signature_parameters(old_sig, *all_param_names)
# add request if needed
func_needs_request = 'request' in old_sig.parameters
if not func_needs_request:
new_sig = add_signature_parameters(new_sig, first=Parameter('request', kind=Parameter.POSITIONAL_OR_KEYWORD))
# --common routine used below. Fills kwargs with the appropriate names and values from fixture_params
def _get_arguments(*args, **kwargs):
request = kwargs['request'] if func_needs_request else kwargs.pop('request')
# populate the parameters
if len(params_names_or_name_combinations) == 1:
_params = [request.param] # remove the simplification
else:
_params = request.param
for p_names, fixture_param_value in zip(params_names_or_name_combinations, _params):
if len(p_names) == 1:
# a single parameter for that generated fixture (@pytest.mark.parametrize with a single name)
kwargs[p_names[0]] = fixture_param_value
else:
# several parameters for that generated fixture (@pytest.mark.parametrize with several names)
Implementation of the @cross_steps_fixture decorator, for manual decoration
:param fixture_fun:
:param step_param_names: a singleton or iterable containing the names of the test step parameters used in the
tests. By default the list is `[GENERATOR_MODE_STEP_ARGNAME, TEST_STEP_ARGNAME_DEFAULT]` to cover both
generator-mode and legacy manual mode.
:return:
"""
ref_dct = dict()
# Create the function wrapper.
# We will expose a new signature with additional 'request' arguments if needed, and the test step
orig_sig = signature(fixture_fun)
func_needs_request = 'request' in orig_sig.parameters
if not func_needs_request:
new_sig = add_signature_parameters(orig_sig, first=Parameter('request', kind=Parameter.POSITIONAL_OR_KEYWORD))
else:
new_sig = orig_sig
def _init_and_check(request):
"""
Checks that the current request is not session but a specific node.
:param request:
:return:
"""
scope = get_scope(request)
if scope == 'function':
# function-scope: ok
id_without_steps = get_pytest_node_hash_id(request.node,
params_to_ignore=_get_step_param_names_or_default(
step_param_names))
return id_without_steps
raise ValueError("Internal error related to fixture parametrization- please report")
# (4) wrap the fixture function so as to remove the parameter names and add 'request' if needed
all_param_names = tuple(v for pnames in params_names_or_name_combinations for v in pnames)
# --create the new signature that we want to expose to pytest
old_sig = signature(fixture_func)
for p in all_param_names:
if p not in old_sig.parameters:
raise ValueError("parameter '%s' not found in fixture signature '%s%s'"
"" % (p, fixture_func.__name__, old_sig))
new_sig = remove_signature_parameters(old_sig, *all_param_names)
# add request if needed
func_needs_request = 'request' in old_sig.parameters
if not func_needs_request:
new_sig = add_signature_parameters(new_sig, first=Parameter('request', kind=Parameter.POSITIONAL_OR_KEYWORD))
# --common routine used below. Fills kwargs with the appropriate names and values from fixture_params
def _map_arguments(*_args, **_kwargs):
request = _kwargs['request'] if func_needs_request else _kwargs.pop('request')
# populate the parameters
if len(params_names_or_name_combinations) == 1:
_params = [request.param] # remove the simplification
else:
_params = request.param
for p_names, fixture_param_value in zip(params_names_or_name_combinations, _params):
if len(p_names) == 1:
# a single parameter for that generated fixture (@pytest.mark.parametrize with a single name)
_kwargs[p_names[0]] = get_lazy_args(fixture_param_value)
else:
# several parameters for that generated fixture (@pytest.mark.parametrize with several names)