Skip to content

Fix default argument mutation #477

@Otto-AA

Description

@Otto-AA

With the changes in #469 mutations to default arguments will have no effect and thus always be reported (TODO: test this, add E2E test).

We probably could use decorators to handle this case:

def check(some_flag: bool = False) -> None:
    return some_flag

Could mutate to something like

P = ParamSpec('P')
R = TypeVar('R')

def __mutmut_dispatcher(func: Callable[P, R]) -> Callable[P, R]:
    @wraps(func)
    def trampoline(*args: P.args, **kwargs: P.kwargs) -> R:
        # check environment variable
        # and call correct function from the mutants dict
        func_to_call = mutants_dict[...]
        return func_to_call(*args, **kwargs)
    return trampoline

@__mutmut_dispatcher
def check(some_flag: bool = False) -> None:
    return some_flag

And depending on the os.environ['MUTANT_UNDER_TEST'] the @__mutmut_dispatcher would pass the args to the original function or the mutated method. The decorator could use *args, **kwargs as parameters and thus accept any args (with or without defaults).

I also like that with the decorator we would not need to do parsing of the args and handle all edge cases ourselve, but simply pass on *args, **kwargs.

For static typing, I think using ParamSpec should retain the original signature for static typing.
But I'm not sure how it works with runtime type hints. Maybe with a @functool.wraps decorator this is fine?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions