|
7 | 7 | from distutils.version import LooseVersion |
8 | 8 | from inspect import getmembers, isgeneratorfunction, getmodule |
9 | 9 |
|
| 10 | +from makefun import with_signature, add_signature_parameters, remove_signature_parameters |
| 11 | + |
| 12 | +try: # python 3.3+ |
| 13 | + from inspect import signature, Parameter |
| 14 | +except ImportError: |
| 15 | + from funcsigs import signature, Parameter |
| 16 | + |
10 | 17 | from pytest_cases.common import yield_fixture, get_pytest_parametrize_marks |
11 | | -from pytest_cases.decorator_hack import my_decorate |
12 | 18 |
|
13 | 19 | try: # type hints, python 3+ |
14 | 20 | from typing import Callable, Union, Optional, Any, Tuple, List, Dict, Iterable |
@@ -379,50 +385,52 @@ def _param_fixture(request): |
379 | 385 | old_parameter_names = tuple(v for l in params_map.values() for v in l) |
380 | 386 |
|
381 | 387 | # common routine used below. Fills kwargs with the appropriate names and values from fixture_params |
382 | | - def _get_arguments(fixture_params, args_and_kwargs): |
383 | | - # unpack the underlying function's args/kwargs |
384 | | - args = args_and_kwargs.pop('args') |
385 | | - kwargs = args_and_kwargs.pop('kwargs') |
386 | | - if len(args_and_kwargs) > 0: |
387 | | - raise ValueError("Internal error - please file an issue in the github project page") |
388 | | - |
389 | | - # fill the kwargs with additional arguments by using mapping |
| 388 | + def _get_arguments(*args, **kwargs): |
| 389 | + # kwargs contains the generated fixture names so we have to remove them. |
| 390 | + # For each generated fixture, there are one or several parameters to inject in kwargs |
390 | 391 | i = 0 |
391 | 392 | for new_p_name in new_parameter_names: |
| 393 | + fixture_param_value = kwargs.pop(new_p_name) |
392 | 394 | if len(params_map[new_p_name]) == 1: |
393 | | - kwargs[params_map[new_p_name][0]] = fixture_params[i] |
| 395 | + # a single parameter for that generated ficture (@pytest.mark.parametrize with a single name) |
| 396 | + kwargs[params_map[new_p_name][0]] = fixture_param_value |
394 | 397 | i += 1 |
395 | 398 | else: |
396 | | - # unpack several |
397 | | - for old_p_name, old_p_value in zip(params_map[new_p_name], fixture_params[i]): |
| 399 | + # several parameters for that generated fixture (@pytest.mark.parametrize with several names) |
| 400 | + # unpack all of them and inject them in the kwargs |
| 401 | + for old_p_name, old_p_value in zip(params_map[new_p_name], fixture_param_value): |
398 | 402 | kwargs[old_p_name] = old_p_value |
399 | 403 | i += 1 |
400 | 404 |
|
401 | 405 | return args, kwargs |
402 | 406 |
|
| 407 | + # create the new signature that we want to expose to pytest |
| 408 | + old_sig = signature(fixture_func) |
| 409 | + new_sig = remove_signature_parameters(old_sig, *old_parameter_names) |
| 410 | + # add them in reversed order so as to match the same test order than in pytest. |
| 411 | + new_sig = add_signature_parameters(new_sig, first=(Parameter(n, kind=Parameter.POSITIONAL_OR_KEYWORD) |
| 412 | + for n in reversed(new_parameter_names))) |
| 413 | + |
| 414 | + # Finally create the fixture function, a wrapper of user-provided fixture with the new signature |
403 | 415 | if not isgeneratorfunction(fixture_func): |
404 | 416 | # normal function with return statement |
405 | | - def wrapper(f, *fixture_params, **args_and_kwargs): |
406 | | - args, kwargs = _get_arguments(fixture_params, args_and_kwargs) |
| 417 | + @with_signature(new_sig) |
| 418 | + def wrapped_fixture_func(*args, **kwargs): |
| 419 | + args, kwargs = _get_arguments(*args, **kwargs) |
407 | 420 | return fixture_func(*args, **kwargs) |
408 | 421 |
|
409 | | - wrapped_fixture_func = my_decorate(fixture_func, wrapper, |
410 | | - additional_args=new_parameter_names, removed_args=old_parameter_names) |
411 | | - |
412 | 422 | # transform the created wrapper into a fixture |
413 | 423 | fixture_decorator = pytest.fixture(scope=scope, params=params, autouse=autouse, ids=ids, **kwargs) |
414 | 424 | return fixture_decorator(wrapped_fixture_func) |
415 | 425 |
|
416 | 426 | else: |
417 | 427 | # generator function (with a yield statement) |
418 | | - def wrapper(f, *fixture_params, **args_and_kwargs): |
419 | | - args, kwargs = _get_arguments(fixture_params, args_and_kwargs) |
| 428 | + @with_signature(new_sig) |
| 429 | + def wrapped_fixture_func(*args, **kwargs): |
| 430 | + args, kwargs = _get_arguments(*args, **kwargs) |
420 | 431 | for res in fixture_func(*args, **kwargs): |
421 | 432 | yield res |
422 | 433 |
|
423 | | - wrapped_fixture_func = my_decorate(fixture_func, wrapper, |
424 | | - additional_args=new_parameter_names, removed_args=old_parameter_names) |
425 | | - |
426 | 434 | # transform the created wrapper into a fixture |
427 | 435 | fixture_decorator = yield_fixture(scope=scope, params=params, autouse=autouse, ids=ids, **kwargs) |
428 | 436 | return fixture_decorator(wrapped_fixture_func) |
|
0 commit comments