-
-
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
Type Narrowing failure in 0.981 #13800
Comments
Interesting, |
Looks like it's from python/typeshed#8465, cc @sobolevn |
Very strange 😨 |
Yeah, it's pretty strange, but it's true. Fixes itself on master if you add |
It does not feel right. It looks like it exposes some other bug. I will have a look. |
So, I am diving into it. First of all, I was able to reproduce this problem. from typing import TypeVar
T = TypeVar("T", dict, int)
def method(x: T) -> T:
if isinstance(x, dict):
return {}
else:
return 0 Also, At this point I am sure that this is a bug. Revealed typesLet's reveal types: from typing import TypeVar
T = TypeVar("T", dict, str)
def method(x: T) -> T:
if isinstance(x, dict):
reveal_type(x)
return {}
else:
reveal_type(x)
return 'a' Output:
Looks like What about types that do work? from typing import TypeVar
T = TypeVar("T", dict, int)
def method(x: T) -> T:
if isinstance(x, dict):
reveal_type(x)
return {}
else:
reveal_type(x)
return 1 Outputs:
So, let's find why the intersection of two instances is created in the first place 🤔
|
Possibly related: #13956 |
I am not sure if this is related but I wanted to add another data point on 0.991 @classmethod
def from_df(cls, df: pd.DataFrame | pd.Series) -> "Sites":
if isinstance(df, pd.Series):
return cls.from_sitemap(cast(SiteDict, df.to_dict()))
assert isinstance(df, pd.DataFrame) # for mypy type failure
df.rename({df.columns[0]: "name"}, axis=1, inplace=True) Error:
Without the Environment: Options: |
Are we sure the initial report reveals a bug or is this behaviour by design? If I am right, we can consider it only a bug if the order of the type variable constraints matters. Then Mypy should behave as follows: from typing import TypeVar
class A: ...
class B: v = 1
class C(A, B): ...
T1 = TypeVar("T1", A, B)
def f1(x: T1) -> T1:
if isinstance(x, A):
return A() # no error
return B()
T2 = TypeVar("T2", B, A)
def f2(x: T2) -> T2:
if isinstance(x, A):
return A() # error: Incompatible return value type (got "A", expected "B") [return-value]
return B()
f1(C()).v # error: "A" has no attribute "v" [attr-defined]
f2(C()).v Are there any promises that Mypy or other type checkers prioritise the first over the second type variable constraint when estimating return types in the context of multiple inheritance? If we agree that order matters (and if I do not miss other potential problems here), adjusting Mypy should be manageable with reasonable effort. |
It seems to be a known issue. I found the following test case (added by @Michael0x2a): [case testIsInstanceAdHocIntersectionGenericsWithValuesDirectReturn]
# flags: --warn-unreachable
from typing import TypeVar
class A:
attr: int
class B:
attr: int
class C:
attr: str
T1 = TypeVar('T1', A, B)
def f1(x: T1) -> T1:
if isinstance(x, A):
# The error message is confusing, but we indeed do run into problems if
# 'x' is a subclass of A and B
return A() # E: Incompatible return value type (got "A", expected "B")
else:
return B()
T2 = TypeVar('T2', B, C)
def f2(x: T2) -> T2:
if isinstance(x, B):
# In contrast, it's impossible for a subclass of "B" and "C" to
# exist, so this is fine
return B()
else:
return C()
[builtins fixtures/isinstance.pyi] |
… `isinstance`, constrained type variables and multiple inheritance (fixes python#13800). The idea is to make a union of the current expanded return type and the previously expanded return types if the latter are among the bases of intersections generated by `isinstance` checks.
I'm seeing an Incompatible return value type error in 0.981 that wasn't present in previous versions of mypy.
To Reproduce
Expected Behavior
Actual Behavior
Your Environment
mypy version 0.981
python version 3.9.13
The text was updated successfully, but these errors were encountered: