78 lines
2.5 KiB
ReStructuredText
78 lines
2.5 KiB
ReStructuredText
Known Issues
|
|
============
|
|
|
|
The following known issues exist.
|
|
|
|
@classmethod.\_\_get\_\_()
|
|
--------------------------
|
|
|
|
The Python ``@classmethod`` decorator assumes in the implementation of its
|
|
``__get__()`` method that the wrapped function is always a normal function.
|
|
It doesn't entertain the idea that the wrapped function could actually be a
|
|
descriptor, the result of a nested decorator. This is an issue because it
|
|
means that the complete descriptor binding protocol is not performed on
|
|
anything which is wrapped by the ``@classmethod`` decorator.
|
|
|
|
The consequence of this is that when ``@classmethod`` is used to wrap a
|
|
decorator implemented using ``@wrapt.decorator``, that ``__get__()`` isn't
|
|
called on the latter. The result is that it is not possible in the latter
|
|
to properly identify the decorator as being bound to a class method and
|
|
it will instead be identified as being associated with a normal function,
|
|
with the class type being passed as the first argument.
|
|
|
|
The behaviour of the Python ``@classmethod`` is arguably wrong and a fix to
|
|
Python for this issue is being pursued (http://bugs.python.org/issue19072).
|
|
The only solution is the recommendation that decorators implemented using
|
|
``@wrapt.decorator`` always be placed outside of ``@classmethod`` and never
|
|
inside.
|
|
|
|
Using decorated class with super()
|
|
----------------------------------
|
|
|
|
In the implementation of a decorated class, if needing to use a reference
|
|
to the class type with super, it is necessary to access the original
|
|
wrapped class and use it instead of the decorated class.
|
|
|
|
::
|
|
|
|
@mydecorator
|
|
class Derived(Base):
|
|
|
|
def __init__(self):
|
|
super(Derived.__wrapped__, self).__init__()
|
|
|
|
If using Python 3, one can simply use ``super()`` with no arguments and
|
|
everything will work fine.
|
|
|
|
::
|
|
|
|
@mydecorator
|
|
class Derived(Base):
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
|
|
Deriving from decorated class
|
|
-----------------------------
|
|
|
|
If deriving from a decorated class, it is necessary to access the original
|
|
wrapped class and use it as the base class.
|
|
|
|
::
|
|
|
|
@mydecorator
|
|
class Base(object):
|
|
pass
|
|
|
|
class Derived(Base.__wrapped__):
|
|
pass
|
|
|
|
In doing this, the functionality of any decorator on the base class is not
|
|
inherited. If creation of a derived class needs to also be mediated via the
|
|
decorator, the decorator would need to be applied to the derived class also.
|
|
|
|
In this case of trying to decorate a base class in a class hierarchy, it
|
|
may turn out to be more appropriate to use a meta class instead of trying
|
|
to decorate the base class.
|