# AUTOGENERATED! DO NOT EDIT! File to edit: nbs/05_logargs.ipynb (unless otherwise specified).

__all__ = ['log_args']

# Cell
from .imports import *
from .foundation import *
from .meta import *
from functools import wraps
import inspect

# Cell
def log_args(f=None, *, to_return=False, but=None, but_as=None):
    "Decorator to log function args in 'to.init_args'"
    if f is None: return partial(log_args, to_return=to_return, but=but, but_as=but_as)

    if inspect.isclass(f):
        f.__init__ = log_args(f.__init__, to_return=to_return, but=but, but_as=but_as)
        return f

    but_as_args = L(getattr(b, '_log_args_but', None) for b in L(but_as)).concat()
    but = (L(but.split(',') if but else None) + but_as_args + L('self')).unique()
    but_not_found = L(b for b in L(but_as) if not hasattr(b, '_log_args_but'))
    if but_not_found: print(f'Did not find but_as with {f.__qualname__} in {[b.__qualname__ for b in but_not_found]}')
    setattr(f, '_log_args_but', but)

    @wraps(f)  # maintain original signature
    def _f(*args, **kwargs):
        f_insp,args_insp = f,args
        xtra_kwargs = {}
        # some functions don't have correct signature (e.g. functions with @delegates such as Datasets.__init__)
        if '__init__' in f.__qualname__:
            # from https://stackoverflow.com/a/25959545/3474490
            # args[0].__class__ would not consider inheritance
            cls = getattr(inspect.getmodule(f), f.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
            f_insp, args_insp = cls, args[1:]
        try: func_args = inspect.signature(f_insp).bind(*args_insp, **kwargs)
        except Exception as e:
            try:
                # sometimes it happens because the signature does not reference some kwargs
                sigp = dict(inspect.signature(f_insp).parameters)
                key_no_sig = set(kwargs.keys())-set(sigp.keys())
                #if key_no_sig: print(f'Warning: @log_args found unexpected args in {f.__qualname__}: {key_no_sig}')
                xtra_kwargs={k:kwargs.pop(k) for k in key_no_sig}
                func_args = inspect.signature(f_insp).bind(*args_insp, **kwargs)
            except:
                #print(f'@log_args had an issue on {f.__qualname__} -> {e}')
                return f(*args, **kwargs)
        func_args.apply_defaults()
        log_dict = {**func_args.arguments, **{f'{k} (not in signature)':v for k,v in xtra_kwargs.items()}}
        log = {f'{f.__qualname__}.{k}':v for k,v in log_dict.items() if k not in but}
        inst = f(*args, **kwargs) if to_return else args[0]
        init_args = getattr(inst, 'init_args', {})
        init_args.update(log)
        setattr(inst, 'init_args', init_args)
        return inst if to_return else f(*args, **kwargs)
    return _f