from typing import Callable
from inspect import signature, Parameter

import wrapt


def set_defaults(config):
    def decorate(fn: Callable):
        parameters = signature(fn).parameters
        common_keys = parameters.keys() & config.keys()
        for key in common_keys:
            assert parameters[key].kind == Parameter.KEYWORD_ONLY

        @wrapt.decorator
        def _wrap(wrapped, instance, args, kwargs):
            # easier for pdb... only need to step over one line
            new_kwargs = {key: config[key] for key in common_keys}
            new_kwargs.update(kwargs)
            return wrapped(*args, **new_kwargs)

        wrap = _wrap(fn)
        wrap.__unwrapped__ = fn
        wrap.config = config
        return wrap
    return decorate


__all__ = ['set_defaults']
