For example:
T = TypeVar("T", bound="CustomDict")
class CustomDict(dict):
def __init__(self) -> None:
super().__init__()
class dict_operator:
def __init__(self, method: Callable[..., Any]) -> None:
self.method = method
def __get__(self, instance: T, owner: Type[T]) -> Callable[..., Any]:
def wrapper(key: Any, *args: Any, **kwargs: Any) -> Any:
results = self.method(instance, key, *args, **kwargs)
print("Did something after __getitem__ or __setitem__")
return results
return wrapper
@dict_operator
def __getitem__(self, key: Any) -> Any:
return super().__getitem__(key)
@dict_operator
def __setitem__(self, key: Any, value: Any) -> None:
super().__setitem__(key, value)
Mypy: Signature of "__getitem__" incompatible with supertype "dict"Mypyoverride Signature of "__getitem__" incompatible with supertype "Mapping"Mypyoverride (variable) Any: Any
I take it the decorator has altered the overriden methods' signatures but I don't know how to account for this.
The issue isn't the type annotations on __getitem__
and __setitem__
. For better or for worse, mypy (currently) doesn't recognise that a __get__
which returns a Callable
is, for the majority of cases, a safe override in lieu of a real Callable
. The fastest fix is to add a __call__
to your dict_operator
class body (mypy Playground 1):
class CustomDict(dict):
...
class dict_operator:
def __init__(self, method: Callable[..., Any]) -> None: ...
def __get__(self, instance: T, owner: Type[T]) -> Callable[..., Any]:
# This needs to be the same as the return type of `__get__`
__call__: Callable[..., Any]
@dict_operator
def __getitem__(self, key: Any) -> Any: ... # OK
@dict_operator
def __setitem__(self, key: Any, value: Any) -> None: ... # OK
I don't know if you only did this for demonstration purposes, but IMO, you have too much imprecise typing here; Callable[..., Any]
in particular is not a very useful type annotation. I don't know what Python version you're using, but if you're able to use typing_extensions
instead, you can have access to the latest typing constructs for better static checking. See mypy Playground 2 for a possible way to implement stricter typing.