decorador python para exibir passados e padrão kwargs

Eu sou novo em python e decoradores e estou perplexo ao escrever um decorador que relata não apenas argumentos e kwargs passados, mas TAMBÉM os kwargs padrão inalterados.

É isso que eu tenho até agora.

def document_call(fn):
    def wrapper(*args, **kwargs):
        print 'function %s called with positional args %s and keyword args %s' % (fn.__name__, args, kwargs)
        return fn(*args, **kwargs)
    return wrapper

@document_call
def square(n, trial=True, output=False):
    # kwargs are a bit of nonsense to test function
    if not output:
        print 'no output'
    if trial:
        print n*n

square(6) # with this call syntax, the default kwargs are not reported
# function square called with positional args (6,) and keyword args {}
# no output
36

square(7,output=True) # only if a kwarg is changed from default is it reported
# function square called with positional args (7,) and keyword args {'output': True}
49

O 'problema' é que esse decorador relata os argumentos passados na chamada para o quadrado, mas não informa os kwargs padrão definidos na definição do quadrado. A única maneira de denunciar os kwargs é se eles forem alterados do padrão, ou seja, passados para a chamada quadrada.

Quaisquer recomendações sobre como eu recebo os kwargs na definição quadrada também são relatadas?

Edite depois de acompanhar as sugestões de inspeção, que me ajudaram na solução abaixo. Alterei a saída dos parâmetros posicionais para incluir seus nomes, porque pensei que facilitava a compreensão da saída.

import inspect
def document_call(fn):
    def wrapper(*args, **kwargs):            
            argspec = inspect.getargspec(fn)
            n_postnl_args = len(argspec.args) - len(argspec.defaults)
        # get kwargs passed positionally
        passed = {k:v for k,v in zip(argspec.args[n_postnl_args:], args[n_postnl_args:])}
        # update with kwargs
        passed.update({k:v for k,v in kwargs.iteritems()})            
        print 'function %s called with \n  positional args %s\n  passed kwargs %s\n  default kwargs %s' % (
                fn.__name__, {k:v for k,v in zip(argspec.args, args[:n_postnl_args])},
                passed,
                {k:v for k,v in zip(argspec.args[n_postnl_args:], argspec.defaults) if k not in passed})        
        return fn(*args, **kwargs)
return wrapper

Essa foi uma boa experiência de aprendizado. É legal ver três soluções diferentes e diferentes para o mesmo problema. Obrigado aos respondentes!

questionAnswers(3)

yourAnswerToTheQuestion