Skip to content

Allow mypy to verify if passed object suits to the type hint of an abstract base class #14537

@Dvergatal

Description

@Dvergatal

Feature

Verification of inheritance with an abstract base classes, meaning that if a variable in method is of type hint of an abstract base class derived from another abstract base class from which inherits also passed parameter to that function, a proper verification shall be done.

Pitch

In case of overloaded functions with type hint e.g. validate_enum_list(key: str, value: str, allowed_values: Iterable[str]) and validate_enum_list(key: str, value: Iterable[str], allowed_values: Iterable[Iterable[str]]) it is not possible without additional implementation of own abstract base class MyIterable to differentiate str from Iterable[str].

I have seen #11001 but it is still open without any clear resolution. It also mentions python/typing#256 and #5090

Use Cases

from typing import Any, Iterable, TypeVar, List, Container
from multimethod import multimethod
from types import GenericAlias

T = TypeVar("T")
class MyIterable(Iterable[T]):
    @classmethod
    def __subclasshook__(cls, subclass: type) -> bool:
        return not issubclass(subclass, str)

    def __class_getitem__(cls, key: Any) -> GenericAlias:
        return GenericAlias(cls, key)

@multimethod
def validate_enum_list(key: str, value: str, allowed_values: MyIterable[str]) -> None:
    print("key: str, value: str, allowed_values: MyIterable[str]")
    print(type(value))
    print(type(allowed_values))

@validate_enum_list.register
def _(key: str, value: MyIterable[str], allowed_values: MyIterable[MyIterable[str]]) -> None:
    print("key: str, value: MyIterable[str], allowed_values: MyIterable[MyIterable[str]]")
    print(type(value))
    print(type(allowed_values))

    value = sorted(value)  # this causes mypy error
    allowed_values = sorted([sorted(item) for item in allowed_values])  # this causes mypy error

validate_enum_list("test1", "test1", ["test1"])
validate_enum_list("test2", ["test2"], [["test1"]])
#validate_enum_list("test1", "test1", [["test1"]])  # uncommenting this will cause runtime exception which is GOOD, but no mypy error which is also WRONG

def get_enum_str(key: str, value: str, allowed_values: MyIterable[str]) -> None:
    validate_enum_list(key, value, allowed_values)
    print("get_enum_str")

def get_enum_str_list(key: str, value: MyIterable[str], allowed_values: MyIterable[MyIterable[str]]) -> None:
    validate_enum_list(key, value, allowed_values)

get_enum_str("test1", "test1", ["test1"])
get_enum_str_list("test2", ["test2"], [["test2"]])
get_enum_str_list("test2", "test2", [["test2"]])  # this causes mypy error

As commented in the code, line validate_enum_list("test1", "test1", [["test1"]]) does not return an error from mypy, but the same issue is with singledispatch decorator which I have already found is a bug.

P.S. I have found some additional informations regardless class_getitem() which is supposed to handle type hinting in such cases, but It is also mentioned that:

Custom implementations of __class_getitem__() on classes defined outside of the standard library may not be understood by third-party type-checkers such as mypy

So for now I'm confused as to whether it should be a feature request or a bug...

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions