Search code examples
pythonpython-3.xpython-decorators

singledispatchmethod and class method decorators in python 3.8


I am trying to use one of the new capabilities of python 3.8 (currently using 3.8.3). Following the documentation I tried the example provided in the docs:

from functools import singledispatchmethod
class Negator:
    @singledispatchmethod
    @classmethod
    def neg(cls, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    @classmethod
    def _(cls, arg: int):
        return -arg

    @neg.register
    @classmethod
    def _(cls, arg: bool):
        return not arg

Negator.neg(1)

This, however, yields the following error:

...
TypeError: Invalid first argument to `register()`: <classmethod object at 0x7fb9d31b2460>. Use either `@register(some_class)` or plain `@register` on an annotated function.

How can I create a generic class method? Is there something I am missing in my example?

Update:

I have read Aashish A's answer and it seems lik an on-going issue. I have managed to solve my problem the following way.

from functools import singledispatchmethod
class Negator:
    @singledispatchmethod
    @staticmethod
    def neg(arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(arg: int):
        return -arg

    @neg.register
    def _(arg: bool):
        return not arg

print(Negator.neg(False))
print(Negator.neg(-1))

This seems to work in version 3.8.1 and 3.8.3, however it seems it shouldn't as I am not using the staticmethod decorator on neither the undescore functions. This DOES work with classmethods, even tho the issue seems to indicate the opposite.

Keep in mind if you are using an IDE that the linter won't be happy with this approach, throwing a lot of errors.


Solution

  • This seems to be a bug in the functools library documented in this issue.