Binding of Generic decorators on Union variables
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the report with the test.py example using mypy 0.910 and compare its diagnostics with the expected behavior and pyright result. Done means the Union[TestA, TestB] access no longer produces the incompatible get argument errors while preserving the shown decorator behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100