Skip to content

Binding of Generic decorators on Union variables #11037

Open
@twoertwein

Description

@twoertwein

Bug Report

Mypy seems to bind the TypeVar of a Generic decorator incorrectly when a variable is annotated as a Union.

To Reproduce
This example is based on this untyped cython code.

from typing import Callable, Generic, Optional, TypeVar, Union, overload

F = TypeVar("F")
G = TypeVar("G")


class cache_readonly(Generic[F, G]):
    def __init__(self, func: Callable[[F], G]) -> None:
        self.func = func
        self.name = func.__name__
        self.__doc__ = getattr(func, "__doc__", None)

    @overload
    def __get__(self, obj: F, typ) -> G:
        ...

    @overload
    def __get__(self, obj: None, typ) -> "cache_readonly[F, G]":
        ...

    def __get__(self, obj: Optional[F], typ) -> Union[G, "cache_readonly[F, G]"]:
        if obj is None:
            # accessed on the class, not the instance
            return self

        # Get the cache or set a default one if needed
        cache = getattr(obj, "_cache", None)
        if cache is None:
            cache = obj._cache = {}  # type: ignore

        if self.name in cache:
            val = cache[self.name]
        else:
            val = self.func(obj)
            cache[self.name] = val
        return val

    def __set__(self, obj: F, value: G) -> None:
        raise AttributeError("Can't set attribute")


class TestA:
    @cache_readonly
    def x(self) -> str:
        return "A"


class TestB:
    @cache_readonly
    def x(self) -> str:
        return "B"


def test(obj: Union[TestA, TestB]) -> str:
    return obj.x

Expected Behavior
Mypy and pyright are happy with the code :)

Actual Behavior
mypy

test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestA"
test.py:55: error: Argument 1 to "__get__" of "cache_readonly" has incompatible type "Union[TestA, TestB]"; expected "TestB"

Pyright doesn't complain (except for the __doc__ line).

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: -
  • Mypy configuration options from mypy.ini (and other config files): -
  • Python version used: 3.9.6
  • Operating system and version: CentOS 3.10.0-693.5.2.el7.x86_64

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions