Skip to content

Mypy forbids converting a method to a property in some cases #3913

Closed
@orenbenkiki

Description

@orenbenkiki

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 type Sub and we assign a Base 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 type Sub. Again this is strange since mypy 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions