Description
When type checking the following example.py
:
from typing import Type
from typing import TypeVar
_Base = TypeVar('_Base', bound='Base')
class Meta(type):
def method_to_access_a_special_instance(cls: Type[_Base]) -> _Base:
# In the real code, this returns some special instance of cls instead of `None`.
return None # type: ignore
@property
def property_to_access_a_special_instance(cls: Type[_Base]) -> Base:
# In the real code, this returns some special instance of cls instead of `None`.
return None # type: ignore
class Base(metaclass=Meta):
pass
class Sub(Base):
pass
a = Base()
a = Base.method_to_access_a_special_instance() # Line 29
b = Sub()
b = Base.method_to_access_a_special_instance() # Line 32
b = Sub.method_to_access_a_special_instance() # Line 33
a = Base.property_to_access_a_special_instance # Line 35
b = Sub.property_to_access_a_special_instance # Line 36
Then mypy
produces the following errors:
example.py:32: error: Incompatible types in assignment (expression has type "Base", variable has type "Sub")
example.py:35: error: Invalid method type
example.py:36: error: Incompatible types in assignment (expression has type "Base", variable has type "Sub")
example.py:36: error: Invalid method type
Expected results:
-
Lines 29 and 33 are accepted by
mypy
, as they should. -
Line 32 is properly rejected because
b
has the typeSub
and we assign aBase
to it.
Unexpected results (bugs?):
-
Lines 35 and 36 are rejected with the message
Invalid method type
. This seems strange, as the only difference between them and the valid lines 29 and 33 is that the code is using a property instead of a method. -
Line 36 also triggers an additional rejection claiming that the property returns a different type
Base
than the expected typeSub
. Again this is strange sincemypy
correctly deduces the return type of the method, but gets confused and deduces a different type when using a property.
Workaround:
For now, I am using the method syntax, since the property syntax is rejected by mypy
. However, this causes ugliness in the code. For example, I need to write something like MyClass.special_instance()[x]
, when I would much rather write MyClass.special_instance[x]
instead.