classification
Title: No way to create an abstract classmethod
Type: enhancement Stage: patch review
Components: Library (Lib) Versions: Python 3.2
process
Status: closed Resolution: accepted
Dependencies: Superseder:
Assigned To: Nosy List: benjamin.peterson, daniel.urban, della, eric.araujo, gvanrossum, pitrou, terry.reedy
Priority: normal Keywords: patch

Created on 2009-04-28 14:24 by della, last changed 2010-08-17 00:53 by benjamin.peterson. This issue is now closed.

Files
File name Uploaded Description Edit
issue5867.diff daniel.urban, 2010-08-13 19:35 Patch (py3k branch)
issue5867a.diff daniel.urban, 2010-08-13 20:26 New patch (+ tests) (py3k branch)
abstractclassstaticmethod.diff daniel.urban, 2010-08-14 07:27 Patch adding the abc.abstractclassmethod and abc.abstractstatismethod decorators
abstractclassstaticmethod+doc.diff daniel.urban, 2010-08-16 07:14 New patch (+doc)
Messages (13)
msg86744 - (view) Author: Matteo Dell'Amico (della) Date: 2009-04-28 14:24
Is there a way to define an abstract classmethod? The two obvious ways
don't seem to work properly.

Python 3.0.1+ (r301:69556, Apr 15 2009, 17:25:52) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import abc
>>> class C(metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     @classmethod
...     def f(cls): print(42)
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in C
  File "/usr/lib/python3.0/abc.py", line 24, in abstractmethod
    funcobj.__isabstractmethod__ = True
AttributeError: 'classmethod' object has no attribute '__isabstractmethod__'
>>> class C(metaclass=abc.ABCMeta):
...     @classmethod
...     @abc.abstractmethod
...     def f(cls): print(42)
... 
>>> class D(C): pass
... 
>>> D.f()
42
msg86922 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2009-05-01 22:09
Please ask questions like this first on python-list or the c.l.p or
gmane mirrors.
msg113790 - (view) Author: Daniel Urban (daniel.urban) * Date: 2010-08-13 15:57
@abstractmethod
@classmethod
def ...
doesn't work because classmethod objects doesn't have a __dict__, so setting arbitrary attributes don't work, and abstractmethod tries to set the __isabstractmethod__ atribute to True.


The other order:
@classmethod
@abstractmethod
def ...
doesn't work, because the abstractmethod decorator sets the function's __isabstractmethod__ attribute to True, but when ABCMeta.__new__ checks the object in the namespace of the class, it won't find it, because the classmethod object won't have an __isabstractmethod__ attribute.

The situation is the same with staticmethod.

One possible solution would be adding a descriptor to classmethod (and staticmethod), with the name "__isabstractmethod__", which on __get__ would check its underlying callable for this attribute, and on __set__ would set this attribute on that callable. I think this way both order should work.
msg113820 - (view) Author: Daniel Urban (daniel.urban) * Date: 2010-08-13 19:35
Here is a patch, which adds a descriptor to classmethod and staticmethod.
Pseudocode:

__get__(self, inst, owner):
    if getattr(inst.callable, '__isabstractmethod__', False):
        return True
    return False

__set__(self, inst, value):
    inst.callable.__isabstractmethod__ = bool(value)
msg113822 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-08-13 19:53
The patch doesn't check that instantiating these methods work at all.
msg113826 - (view) Author: Daniel Urban (daniel.urban) * Date: 2010-08-13 20:26
If I understand correctly, some tests are needed for the instantiation of classes with abstract static/classmethods. I added them in issue5867a.diff.
msg113833 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-08-13 21:20
Thank you. I'm not an ABC expert but it looks ok. Guido, what do you think?
msg113838 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2010-08-13 21:42
As you figured out it is not yet supported.

I object to making changes to the classmethod implementation.

I expect the best thing to do is to add a new

@abc.abstractclassmethod

decorator defined in pure Python (maybe the definition of abstractproperty provides a hint on how to do this).

You may want to define @abc.abstractstaticmethod as well.
msg113877 - (view) Author: Daniel Urban (daniel.urban) * Date: 2010-08-14 07:27
I'm attaching a new patch adding the abc.abstractclassmethod and abc.abstractstaticmethod decorators.
msg113973 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2010-08-15 16:17
The patch looks fine code-wise, but it also needs a doc addition in Doc/library/abc.rst.
msg114038 - (view) Author: Daniel Urban (daniel.urban) * Date: 2010-08-16 07:14
I'm attaching a new patch containing also some documentation for the two new decorators. The doc is rather terse, and english is not my first language, so please let me know if some corrections are needed.
msg114088 - (view) Author: √Čric Araujo (eric.araujo) * (Python committer) Date: 2010-08-17 00:03
Looks good.
msg114091 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2010-08-17 00:53
Applied in r84124. Thanks for the patch.
History
Date User Action Args
2010-08-17 00:53:12benjamin.petersonsetstatus: open -> closed
resolution: accepted
messages: + msg114091
2010-08-17 00:03:07eric.araujosetnosy: + eric.araujo
messages: + msg114088
2010-08-16 07:14:44daniel.urbansetfiles: + abstractclassstaticmethod+doc.diff

messages: + msg114038
2010-08-15 16:17:35pitrousetmessages: + msg113973
2010-08-14 07:27:55daniel.urbansetfiles: + abstractclassstaticmethod.diff

messages: + msg113877
2010-08-13 21:42:41gvanrossumsetmessages: + msg113838
2010-08-13 21:20:38pitrousetnosy: + gvanrossum
messages: + msg113833
2010-08-13 20:26:00daniel.urbansetfiles: + issue5867a.diff

messages: + msg113826
2010-08-13 19:53:38pitrousetversions: + Python 3.2, - Python 3.1
nosy: + pitrou, benjamin.peterson

messages: + msg113822

stage: patch review
2010-08-13 19:35:13daniel.urbansetfiles: + issue5867.diff
keywords: + patch
messages: + msg113820
2010-08-13 15:57:47daniel.urbansetmessages: + msg113790
2010-08-12 18:44:49daniel.urbansetnosy: + daniel.urban
2009-05-01 22:09:58terry.reedysetnosy: + terry.reedy
messages: + msg86922
2009-04-28 18:28:52benjamin.petersonsetpriority: normal
type: behavior -> enhancement
versions: + Python 3.1, - Python 3.0
2009-04-28 14:24:11dellacreate