Description
Note: if you are reporting a wrong signature of a function or a class in
the standard library, then the typeshed tracker is better suited
for this report: https://github.com/python/typeshed/issues
Please provide more information to help us understand the issue:
- Are you reporting a bug, or opening a feature request?
Bug.
- Please insert below the code you are checking with mypy,
or a mock-up repro if the source is private. We would appreciate
if you try to simplify your case to a minimal repro.
See below.
- What is the actual behavior/output?
See below.
- What is the behavior/output you expect?
Error as shown n output should not be reported.
- What are the versions of mypy and Python you are using?
mypy 0.711, python 3.7.3
- What are the mypy flags you are using? (For example --strict-optional)
None.
It doesn't seem to be possible to create an explicit descriptor class that behaves
the same way as @Property does with respect to methods of sub-types declaring more constrained return types.
In the example below, we have classes "Obj" > "Foo", and "AA" > "BB".
All methods of Obj return AA. Foo overrides all methods of Obj, but all of those methods
return "BB". Note that all methods of Foo are still consistent with the definitions in
Obj.
The method func1 has no decorators and is accepted without complaints, and its types are correctly recognized.
Method func3 is decorated with "@Property". Here too, mypy handles this case without error.
Method func2 is decorated with "@prop", which is a custom property descriptor.
The revealed types for func2 are consistent with func3 -- hence the typing for the "prop" class appears to be consistent with what "@Property" does. However, mypy flags an error that
Foo.func2 is not consistent with the super type definition Obj.func2. (As a related issue, I haven't been able to come up with a better typing scheme for "prop" without using "type:ignore", which still gives the same type results.)
In this example below, I'd expect mypy to report no errors on either func2 or func3, or to report errors for both. As it stands, it appears that it's not possible to create a typing scheme for a descriptor that fully mirrors mypy's special handling for "@Property".
from typing import Generic, TypeVar,Type, Callable,Any, Union, overload,Optional
OwnerType = TypeVar("OwnerType", bound=object)
T = TypeVar('T', covariant=True)
CallableType = TypeVar("CallableType", bound=Callable)
class prop(Generic[T]):
def __init__(self, func: Callable[[Any], T]):
self.func = func
def __get__(self, obj: Any, owner: Type[Any]) -> T:
if obj is None:
return self # type: ignore
return self.func(obj)
class AA:
def foo(self) -> int:
return 1
class BB(AA):
def bar(self) -> int:
return 1
class Obj:
def func1(self) -> AA:
return AA()
@prop
def func2(self) -> AA:
return AA()
@property
def func3(self) -> AA:
return AA()
class Foo(Obj):
def func1(self) -> BB:
return BB()
@prop
def func2(self) -> BB:
return BB()
@property
def func3(self) -> BB:
return BB()
x = Obj()
y = Foo()
reveal_type(Obj.func1)
reveal_type(Obj.func2)
reveal_type(Obj.func3)
reveal_type(Foo.func1)
reveal_type(Foo.func2)
reveal_type(Foo.func3)
reveal_type(x.func1)
reveal_type(x.func2)
reveal_type(x.func3)
reveal_type(y.func1)
reveal_type(y.func2)
reveal_type(y.func3)
Mypy output:
/tmp/xx.py:40: error: Signature of "func2" incompatible with supertype "Obj"
/tmp/xx.py:49: note: Revealed type is 'def (self: xx.Obj) -> xx.AA'
/tmp/xx.py:50: note: Revealed type is 'xx.AA*'
/tmp/xx.py:51: note: Revealed type is 'def (self: xx.Obj) -> xx.AA'
/tmp/xx.py:52: note: Revealed type is 'def (self: xx.Foo) -> xx.BB'
/tmp/xx.py:53: note: Revealed type is 'xx.BB*'
/tmp/xx.py:54: note: Revealed type is 'def (self: xx.Foo) -> xx.BB'
/tmp/xx.py:55: note: Revealed type is 'def () -> xx.AA'
/tmp/xx.py:56: note: Revealed type is 'xx.AA*'
/tmp/xx.py:57: note: Revealed type is 'xx.AA'
/tmp/xx.py:58: note: Revealed type is 'def () -> xx.BB'
/tmp/xx.py:59: note: Revealed type is 'xx.BB*'
/tmp/xx.py:60: note: Revealed type is 'xx.BB'