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, ...):
    '<docstring>'
    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
    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
    Replies:
    4
    Views:
    399
    Matt Hammond
    Jun 26, 2006
  2. ThaDoctor
    Replies:
    3
    Views:
    372
    Alan Woodland
    Sep 28, 2007
  3. Robert Klemme

    With a Ruby Yell: more, more more!

    Robert Klemme, Sep 28, 2005, in forum: Ruby
    Replies:
    5
    Views:
    204
    Jeff Wood
    Sep 29, 2005
  4. Daniel
    Replies:
    1
    Views:
    201
    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
    Replies:
    0
    Views:
    84
    Vito De Tullio
    Jul 16, 2013
Loading...

Share This Page