This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: @classmethod doesn't set __wrapped__ the same way as functool's update_wrapper
Type: behavior Stage:
Components: Extension Modules Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Thomas701
Priority: normal Keywords:

Created on 2021-08-20 12:07 by Thomas701, last changed 2022-04-11 14:59 by admin.

Messages (1)
msg399965 - (view) Author: Thomas (Thomas701) Date: 2021-08-20 12:07
@classmethod defines a __wrapped__ attribute that always points to the inner most function in a decorator chain while functool's update_wrapper has been fixed to set the wrapper.__wrapped__ attribute after updating the wrapper.__dict__ (see https://bugs.python.org/issue17482) so .__wrapped__ points to the next decorator in the chain.
This results in inconsistency of the value of the.__wrapped__ attribute.

Consider this code:

from functools import update_wrapper


class foo_deco:
    def __init__(self, func):
        self._func = func
        update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        return self._func(*args, **kwargs)


class bar_deco:
    def __init__(self, func):
        self._func = func
        update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        return self._func(*args, **kwargs)


class Foo:
    @classmethod
    @foo_deco
    def bar_cm(self):
        pass

    @bar_deco
    @foo_deco
    def bar_bar(self):
        pass


print(Foo.bar_cm.__wrapped__)
# <function Foo.bar_cm at 0x7fb0254433a0>
print(Foo.bar_bar.__wrapped__)
# <__main__.foo_deco object at 0x7fb025445fd0>

# The foo_deco object is available on bar_cm this way though
print(Foo.__dict__['bar_cm'].__func__)
# <__main__.foo_deco object at 0x7fb025445fa0>

It would be more consistent if the fix that was applied to update_wrapper was ported to classmethod's construction (or classmethod could invoke update_wrapper directly, maybe). It's also worth noting that @staticmethod behaves the same and @property doesn't define a .__wrapped__ attribute. For @property, I don't know if this is by design or if it was just never ported, but I believe it would be a great addition just to be able to go down a decorator chain without having to special-case the code.
History
Date User Action Args
2022-04-11 14:59:49adminsetgithub: 89124
2021-08-20 12:07:01Thomas701create