Unable to overload __new__ method with TypeVar input
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Bug Report
Unable to overload new method with generic input
To Reproduce
How can I type hint my __new__ implementation using a generic input?
So I have a class that can store str or decimal.Decimal instances, and it subclasses the input str or decimal.Decimal class.
This code works in mypy and python:
from __future__ import annotations
import typing
import typing_extensions
import decimal
import random
T = typing.TypeVar('T', str, decimal.Decimal)
class StrOrDecimal(typing.Generic[T]):
@typing.overload
def __new__(cls, arg: decimal.Decimal) -> StrOrDecimalTyped.Decimal.StrOrDecimal[decimal.Decimal]:
...
@typing.overload
def __new__(cls, arg: str) -> StrOrDecimalTyped.Str.StrOrDecimal[str]:
...
# def __new__(cls, arg: typing.Union[str, decimal.Decimal]): does not work
def __new__(cls, arg): # works
if isinstance(arg, decimal.Decimal):
return super(cls, StrOrDecimalTyped.Decimal.StrOrDecimal).__new__(StrOrDecimalTyped.Decimal.StrOrDecimal, arg)
if isinstance(arg, str):
return super(cls, StrOrDecimalTyped.Str.StrOrDecimal).__new__(StrOrDecimalTyped.Str.StrOrDecimal, arg)
raise ValueError('Invalid value')
_StrOrDecimal = StrOrDecimal
# needed for mypy
class StrOrDecimalTyped:
class Str:
class StrOrDecimal(_StrOrDecimal[T], str):
pass
class Decimal:
class StrOrDecimal(_StrOrDecimal[T], decimal.Decimal):
pass
a_val = 'a'
a = StrOrDecimal(a_val)
print(a)
b_val = decimal.Decimal('1.2')
b = StrOrDecimal(b_val)
print(b)
choices: typing.List[typing.Union[str, decimal.Decimal]] = [a_val, b_val]
c_val = random.choice(choices)
c = StrOrDecimal(c_val)
try:
reveal_type(a)
reveal_type(b)
reveal_type(c)
except NameError:
typing_extensions.reveal_type(a)
typing_extensions.reveal_type(b)
typing_extensions.reveal_type(c)
But if I use either of these signatures:
def __new__(cls, arg: typing.Union[str, decimal.Decimal]):
def __new__(cls, arg: T):
I get this error:
generic.py:19: error: Argument 1 to "__new__" of "StrOrDecimal" has incompatible type "Type[generic.StrOrDecimalTyped.Decimal.StrOrDecimal[Any]]"; expected "Type[generic.StrOrDecimal[T]]"
How can I fix it?
Expected Behavior
I expect to be able to use T as the input type
Actual Behavior
Mypy throws the above error
Your Environment
- Mypy version used:
- Mypy command-line flags:
- Mypy configuration options from
mypy.ini(and other config files): - Python version used:
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
Start by running the provided reproduction in generic.py and inspect the reported error at line 19, focusing on how mypy checks the new signature with TypeVar and overloads. Compare the overload, Union, and TypeVar variants; done means a supported generic input form type-checks without the incompatible-argument error while retaining the expected revealed types.
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
- Needs clarification
- Newbie friendliness
- 32/100