-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
False-positive on TypeVar bound class return value #10817
Comments
I recently added support for this case in pyright. It took me a while to work out a good solution, so I'll share it here in case it might be of use for someone attempting to fix this in mypy. When a symbol whose type is defined by a type variable (such as in the example above, where I solved the problem in pyright by introducing the notion of a "conditional type". A conditional type is like a normal type except that it's conditioned on one or more type variables from which it derives. In the case of constrained type variables, a type is conditioned on a particular constraint of a type variable. The example above uses a bound type variable, so there is no specific constraint associated with this condition. Pyright reports conditional types with a def fn(t: QBT) -> QBT:
reveal_type(t) # Type of "t" is "QBT@fn"
if not isinstance(t, B):
raise NotImplementedError
reveal_type(t) # Type of "t" is "B*"
return t This same approach allows constrained type variables to be analyzed in a single pass, versus the multi-pass approach currently used in mypy. FloatOrStr = TypeVar("FloatOrStr", float, str)
def add(v1: FloatOrStr, v2: FloatOrStr) -> FloatOrStr:
reveal_type(v1) # Type of "v1" is "FloatOrStr@add"
reveal_type(v2) # Type of "v2" is "FloatOrStr@add"
v3 = v1 + v2
reveal_type(v3) # Type of "v3" is "float* | str*"
if isinstance(v3, float):
reveal_type(v3) # Type of "v3" is "float*"
return v3 + 1
else:
reveal_type(v3) # Type of "v3" is "str*"
return v3 + "1" |
May be relevant to this bug. In the following code, mypy seems to ignore the type guard and requests me to return an object that is both tuple and dict. from typing import TypeVar, Tuple, Dict
T = TypeVar('T', Tuple, Dict)
class TupleDict(tuple, dict):
pass
def func(feat: T) -> T:
if isinstance(feat, tuple):
# return tuple() # error: Incompatible return value type (got "Tuple[<nothing>, ...]", expected "Dict[Any, Any]")
# return {} # error: Incompatible return value type (got "Dict[<nothing>, <nothing>]", expected "Tuple[Any, ...]")
return TupleDict() # pass
if isinstance(feat, dict):
return {} mypy 0.960 (compiled: yes) |
@LutingWang were you ever able to work around your issue in any way? I'm trying to do the same thing where I essentially am saying 'lets make up this new type that can actually be one of these 5 classes'. If I return an instance of any of those classes, mypy is complaining. |
For now I'm using |
I've probably encountered same bug when using dataclasses. Reproduction:
For now I have no idea how to workaround this case, |
Bug Report
When using a bound TypeVar, returning a type revealed as a class (not the generic) sometimes results in a false positive.
To Reproduce
Minimal example available here: https://mypy-play.net/?mypy=latest&python=3.10&gist=a9419e2d2627a65ae181f16224680618
On python 3.10 and latest mypy. Though I originally reproduced it on python 3.8 and mypy 0.8.
Expected Behavior
I am not 100%, but I think this should be allowed. I checked in the gitter.im and @JelleZijlstra also thought it might be a bug.
Actual Behavior
Exception regarding return type. Happens with yields also.
Your Environment
mypy.ini
: DefaultsWorkaround:
On .8 this does not work. But:
The text was updated successfully, but these errors were encountered: