Reputation: 393
While trying to update my code to be PEP-484 compliant (I'm using mypy
0.610) I've ran into the following report:
$ mypy mymodule --strict-optional --ignore-missing-imports --disallow-untyped-calls --python-version 3.6
myfile.py:154: error: Signature of "deliver" incompatible with supertype "MyClass"
MyClass:
from abc import abstractmethod
from typing import Any
class MyClass(object):
@abstractmethod
def deliver(self, *args: Any, **kwargs: Any) -> bool:
raise NotImplementedError
myfile.py:
class MyImplementation(MyClass):
[...]
def deliver(self, source_path: str,
dest_branches: list,
commit_msg: str = None,
exclude_files: list = None) -> bool:
[...]
return True
I'm definitely doing something wrong here, but I can't quite understand what
Any pointers would be much appreciated.
Upvotes: 23
Views: 20569
Reputation: 319
You can solve the question by using Callable[..., Any]
and type: ignore
such like bellow.
from typing import Callable
class MyClass(object):
deliver: Callable[..., bool]
@abstractmethod
def deliver(self, *args, **kwargs): # type: ignore
raise NotImplementedError
Upvotes: -3
Reputation: 2795
Maybe you should work it around this way:
Define abstract method without arguments:
class MyClass:
@abstractmethod
def deliver(self) -> bool:
raise NotImplementedError
In implementations get all your data from self
:
class MyImplementation(MyClass):
def __init__(
self,
source_path: str,
dest_branches: list,
commit_msg: str = None,
exclude_files: list = None
) -> None:
super().__init__()
self.source_path = source_path
self.dest_branches = dest_branches
self.commit_msg = commit_msg
self.exclude_files = exclude_files
def deliver(self) -> bool:
# some logic
if self.source_path and self.commit_msg:
return True
return False
This way you will have completely compatible method declarations and still can implement methods as you want.
Upvotes: -3
Reputation: 281842
@abstractmethod
def deliver(self, *args: Any, **kwargs: Any) -> bool:
raise NotImplementedError
This declaration doesn't mean subclasses can give deliver
any signature they want. Subclass deliver
methods must be ready to accept any arguments the superclass deliver
method would accept, so your subclass deliver
has to be ready to accept arbitrary positional or keyword arguments:
# omitting annotations
def deliver(self, *args, **kwargs):
...
Your subclass's deliver
does not have that signature.
If all subclasses are supposed to have the same deliver
signature you've written for MyImplementation
, then you should give MyClass.deliver
the same signature too. If your subclasses are going to have different deliver
signatures, maybe this method shouldn't really be in the superclass, or maybe you need to rethink your class hierarchy, or give them the same signature.
Upvotes: 23