Re: a little more explicative error message?

Discussion in 'Python' started by Terry Reedy, Jul 16, 2013.

  1. Terry Reedy

    Terry Reedy Guest

    On 7/16/2013 1:44 AM, Vito De Tullio wrote:
    > Hi
    > I was writing a decorator and lost half an hour for a stupid bug in my code,
    > but honestly the error the python interpreter returned to me doesn't
    > helped...
    > $ python3
    > Python 3.3.0 (default, Feb 24 2013, 09:34:27)
    > [GCC 4.7.2] on linux
    > Type "help", "copyright", "credits" or "license" for more information.
    >>>> from functools import wraps
    >>>> def dec(fun):

    > ... @wraps
    > ... def ret(*args, **kwargs):
    > ... return fun(*args, **kwargs)

    At this point, when dec(fun) is called, the interpreter *successfully*
    executes ret = wraps(ret), which works, but is wrong, because wraps
    should be called with the wrapped function fun as its argument, not the
    wrapper function ret. The interpreter should instead execute
    ret = partial(update_wrapper, wrapped = fun, ...)(ret)
    which will update ret to look like fun.

    > ... return ret
    > ...
    >>>> @dec

    > ... def fun(): pass

    At this point, the interpreter *successfully* executes fun = dec(fun) =
    (wraps(ret))(fun), which causes ret = wraps(ret) before returning ret.
    Notice that when dec returns, the wraps code is over and done with.
    Instead the interpreter should execute
    fun = (partial(update_wrapper, wrapped = fun, ...)(ret))(fun)

    > ...
    >>>> fun()

    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > TypeError: update_wrapper() missing 1 required positional argument:
    > 'wrapper'

    Because fun has not been properly wrapped because you left out a call.

    > Soo... at a first glance, no tricks... can you tell where is the error? :D

    Not exactly, but it must have something to do with wraps, so the first
    thing I would do is to look at the wraps doc if I had not before. It
    only takes a couple of minutes.

    >>> from functools import wraps
    >>> help(wraps)

    Help on function wraps in module functools:

    wraps(wrapped, assigned=('__module__', '__name__', '__qualname__',
    '__doc__', '__annotations__'), updated=('__dict__',))
    Decorator factory to apply update_wrapper() to a wrapper function

    Returns a decorator that invokes update_wrapper() with the decorated
    function as the wrapper argument and the arguments to wraps() as
    the remaining arguments. ...

    This is pretty clear that wraps is not a decorator but a function that
    returns decorator, which means that is must be called with an argument
    in the @del statement.

    To really understand what is intended to happen so I could write the
    commentary above, I looked at the code to see
    def wraps(wrapped, ...):
    return partial(update_wrapper, wrapped=wrapped,
    assigned=assigned, updated=updated)

    > As I said, the error is totally mine, I just forgot to pass the function as
    > parameter to wraps. But... what is "update_wrapper()"? and "wrapper"? There
    > is no useful traceback or something... just... this.
    > Ok, the documentation clearly says:
    > This is a convenience function to simplify applying partial() to
    > update_wrapper().
    > So, again, shame on me... I just read carefully the doc *after* 20 minutes
    > trying everything else... still... I think should be useful if wraps()
    > intercept this error saying something more explicit about the missing fun
    > parameter...

    How is a function that has already been called and has returned without
    apparent error supposed to catch a later error caused by its return not
    being correct, due to its input not being correct?

    Your request is like asking a function f(x) to catch ZeroDivisionError
    if it return a 0 and that 0 is later used as a divisor after f returns,
    as in 1/f(x).

    When you call wraps with a callable, there is no way for it to know that
    the callable in intended to the be the wrapper instead of the wrappee,
    unless it were clairvoyant ;-).

    Terry Jan Reedy
    Terry Reedy, Jul 16, 2013
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michael
    Matt Hammond
    Jun 26, 2006
  2. ThaDoctor
    Alan Woodland
    Sep 28, 2007
  3. Robert Klemme

    With a Ruby Yell: more, more more!

    Robert Klemme, Sep 28, 2005, in forum: Ruby
    Jeff Wood
    Sep 29, 2005
  4. Daniel
    Bart van Ingen Schenau
    Jul 9, 2013
  5. Vito De Tullio

    a little more explicative error message?

    Vito De Tullio, Jul 16, 2013, in forum: Python
    Vito De Tullio
    Jul 16, 2013

Share This Page