import inspect


def get_keyword_args(function, try_mro_from_class=None):
    """Inspect function signature and return keyword args with their default values.

    Parameters
    ----------
    function : callable
        The function to interrogate.
    try_mro_from_class : any Class or None
        Try and trace the method resolution order (MRO) of the ``function_to_inspect`` by inferring a method stack from
        the supplied class.
        The signature of the function is checked in every MRO up the stack so long as there exists as
        ``**kwargs`` in the method call. This is setting will yield expected results in every case, for instance, if
        the method does not call `super()`, or the Super class has a different function name.
        In the case of conflicting keywords, the lower MRO function is preferred.

    Returns
    -------
    kwargs : dict
        A dictionary ``{'keyword argument': 'default value'}``. The arguments of the
        function that do not have a default value will not be included.

    """

    def extract_kwargs(input_argspec):
        defaults = input_argspec.defaults
        if defaults is None:
            defaults = []
        n_defaults = len(defaults)
        n_args = len(input_argspec.args)
        # Cycle through the kwargs only
        cycle_kwargs = input_argspec.args[n_args - n_defaults:]
        cycle_kwargs = {arg: value for arg, value in zip(cycle_kwargs, defaults)}
        # Handle the kwonlyargs for calls with `def F(a,b *args, x=True, **kwargs)
        if input_argspec.kwonlydefaults is not None:
            cycle_kwargs = {**cycle_kwargs, **input_argspec.kwonlydefaults}
        return cycle_kwargs

    agspec = inspect.getfullargspec(function)
    kwargs = extract_kwargs(agspec)
    if try_mro_from_class is not None and agspec.varkw is not None:
        try:
            mro = inspect.getmro(try_mro_from_class)
        except AttributeError:
            # No MRO
            mro = [try_mro_from_class]
        for cls in mro[1:]:
            try:
                parent_function = getattr(cls, function.__name__)
            except AttributeError:
                # Class does not have a method name
                pass
            else:
                inner_argspec = inspect.getfullargspec(parent_function)
                kwargs = {**extract_kwargs(inner_argspec), **kwargs}
    return kwargs