1

I am trying to add typehints to some methods I want to overide from a library (in my case djangos save() method).

For this, I would like to use **kwargs in my implementation, because I am not concered about most of the arguments.

I have a minimal example here:

from typing import Any


class Abstract(object):
    def save(self, arg_1: bool = True, arg_2: bool = False, arg_3: bool = True) -> None:
        raise NotImplementedError

class Implementation(Abstract):
    def save(self, arg_1: bool = True, **kwargs: Any) -> None:
        # do something with arg_1
        super().save(arg_1=arg_1, **kwargs)

Running mypy 0.942 here gives me:

error: Signature of "save" incompatible with supertype "Abstract"
note:      Superclass:
note:          def save(self, arg_1: bool = ..., arg_2: bool = ..., arg_3: bool = ...) -> None
note:      Subclass:
note:          def save(self, arg_1: bool = ..., **kwargs: Any) -> None

Do I really need to add all the arguments from the library to my implementation?

I mean technically, the Subclass still supports arg_2 and arg_3 through the **kwargs. So I am not getting why it should be incompatible.

Similar question (but a bit different): Python 3.6: Signature of {method} incompatible with super type {Class}

flix
  • 1,821
  • 18
  • 23

1 Answers1

2

Developping on @joel 's comments.

The Abstract.save method accepts 3 parameters, that can be both positional/keyword arguments. In other words, you could call save(False, False, False) or save(arg_1=False, arg2=False, arg3=False).

Meanwhile, the Implementation.save method only one positional/keyword argument, plus any number of keyword-only arguments.

This means that the Implementation.save method is not just more generic than Abstract.save: you can not call save(False, False, False) on the implementation one.

To solve this, you could do something like the following, which allows flexibility while maintaining type compatibility:

class Implementation(Abstract):
    def save(self, arg_1: bool = True, *args: Any, **kwargs: Any) -> None:
        # do something with arg_1
        super().save(arg_1, *args, **kwargs)
rogdham
  • 193
  • 8
  • Hello @rogdham, Yes, that's it. Adding the `*args` makes mypy not complain anymore. Thanks. However, I think your explanation contains a mistake. I think it should be " you can not call `save(False, False, False)` on the implementation one.". If you agree, please correct your answer. Then I will accept it as the right one. – flix Aug 24 '22 at 06:23