question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`__set_name__` not called on class construction for `wrapt.decorator`-wrapped descriptors

See original GitHub issue

wrapt version: 1.12.1


I was using wrapt.decorator in combination with descriptors. However, I found that __set_name__ was not called on the descriptor when it’s being decorated:

import wrapt


@wrapt.decorator
def decorator(wrapped, instance, args, kwargs):
    return wrapped(*args, **kwargs)


class descriptor_wrapper:
    def __init__(self, descriptor):
        self.__wrapped__ = descriptor

    def __set_name__(self, owner, name):
        print("__set_name__", self, owner, name)
        if hasattr(self.__wrapped__, "__set_name__"):
            self.__wrapped__.__set_name__(owner, name)

    def __get__(self, instance, owner=None):
        print("__get__", self, instance, owner)
        return self.__wrapped__.__get__(instance, owner)


class MyClass:
    @descriptor_wrapper
    def this_works(self):
        pass

    @decorator
    @descriptor_wrapper
    def this_doesnt_work(self):
        pass

The output is:

__set_name__ <__main__.descriptor_wrapper object at 0x7f66360bac40> <class '__main__.MyClass'> this_works

But it is expected that __set_name__ be called for both descriptors.

On the other hand, lookup on the decorated descriptor seems to work:

>>> hasattr(MyClass.__dict__["this_doesnt_work"], "__set_name__")
True
>>> MyClass.__dict__["this_doesnt_work"].__set_name__(MyClass, "this_doesnt_work")
__set_name__ <__main__.descriptor_wrapper object at 0x7f66360baa00> <class '__main__.MyClass'> this_doesnt_work

but it just doesn’t get called during class construction.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
GrahamDumpletoncommented, Aug 7, 2021

The __set_name__ support when using wrapt.decorator is included in 1.13.0.

BTW, if interested in playing with pickling further and want an easy way of overriding the builtin FunctionWrapper to add the pickle methods, in 1.13.0 you can do:

class MyBoundFunctionWrapper(wrapt.BoundFunctionWrapper):
    pass

class MyFunctionWrapper(wrapt.FunctionWrapper):
    __bound_function_wrapper__ = MyBoundFunctionWrapper

@wrapt.decorator(proxy=MyFunctionWrapper)
def wrapper(wrapped, instance, args, kwargs):
    return wrapped(args, kwargs)

Version 1.13.0 is available on PyPi at the moment as release candidates.

Anyway, going to close out this issue at this point.

0reactions
GrahamDumpletoncommented, Aug 5, 2021

Have made changes to add __set_name__() propagation to FunctionWrapper, but not ObjectProxy.

You can try develop branch if you want to verify it works for you.

pip install -U https://github.com/GrahamDumpleton/wrapt/archive/refs/heads/develop.zip
Read more comments on GitHub >

github_iconTop Results From Across the Web

adding descriptor with setattr doesn't call __set_name__ - ...
I'm using setattr to add a long list of descriptors to a class, and I have discovered that __set_name__ of the descriptor is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found