-
Notifications
You must be signed in to change notification settings - Fork 241
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
Discrepancy in behavior of Callable instance fields #1113
Comments
IIRC the mypy issue is because when you define a method it boils down to the same The problem is also with the conflation of class variables and instance variables in Python, where class C:
x = 0 could mean either an instance variable or a class variable. |
Yeah, the mypy behavior is unfortunate. I bet this has been like this for a long time, probably from time before variable type annotations were a thing. I can have a look at how disruptive it would be to change this in mypy. |
I think pyright's behavior is correct here. It matches the runtime behavior (i.e. generates errors only in the situations where the runtime does). from typing import Callable
def func1() -> int:
return 0
def func2(self: "X") -> int:
return 0
class X:
f: Callable[[], int]
g: Callable[["X"], int]
x = X()
x.f = func1 # mypy generates error on this line
x.g = func2 # mypy generates error on this line
x.f() # mypy generates error on this line
x.g() # pyright and Python runtime generate error on this line
I don't think that distinction matters in this case. Here are two examples, one that populates the class variable and a second that populates an instance variable. In both cases, they must be called without passing a "self" argument. This runs without error and type checks in both pyright and mypy. from typing import Callable
def func1() -> int:
return 0
class X:
f: Callable[[], int]
X.f = func1
X.f() This runs without error and type checks in pyright, but mypy generates errors. from typing import Callable
def func1() -> int:
return 0
class X:
f: Callable[[], int]
x = X()
x.f = func1 # mypy: error: Attribute function "f" with type "Callable[[], int]" does not accept self argument
x.f() # mypy: error: Attribute function "f" with type "Callable[[], int]" does not accept self argument |
Yes, this is a long standing mypy bug: python/mypy#708 We had a fix recently (python/mypy#10548) but it had to be reverted in python/mypy#11571 because it regressed:
|
There may be a way to adjust python/mypy#10548 in a way that it is less disruptive to mypy users. For example, mypy could perhaps treat explicit annotations differently from inferred types from an assignment. |
I thought this bug had been fixed, because it definitely annoyed me a bit, and … it sort of has? But only if you're using dataclasses! from typing import Callable
from dataclasses import dataclass
@dataclass
class X:
f: Callable[[], int]
g: Callable[["X"], int]
instance = X(lambda: 1, lambda self: 2)
reveal_type(instance.f())
reveal_type(instance.g(instance)) so is the bug here really just that some classes still aren't dataclasses for some weird reason? 😉 |
More seriously the dataclasses/attrs plugin behavior is exactly what I'd expect, since |
I agree that ideally it should work like that for all classes: require |
I believe that we can fix this without a huge migration for code that has been annotated using the existing semantics, but we may need some subtle adjustments to the rules around class/instance variables. I'll investigate this in more detail, hopefully in the next one or two weeks. |
Closing this because we're in agreement that it's a bug in mypy. Thanks for the insights! |
@JelleZijlstra - where's the mypy bug tracking this? python/mypy#708 is closed but the problem is still there on Python 3.11 and latest mypy. (see simplistix/sybil#78 (comment)) |
Not sure, there might not be one. |
(Expanding from python/typeshed#7520 (comment))
Consider this code:
Here is how current type checkers handle it:
Expected 1 more positional argument
)Function <callable> expects 1 arg(s), got 0 [wrong-arg-count]
)Missing required positional argument: '__arg0' (code: incompatible_call)
)main.py:8: error: Attribute function "f" with type "Callable[[], int]" does not accept self argument
).I feel like mypy is wrong here, because the behavior where
self
gets implicitly bound on instances is specific to functions, not all callables. But the type system sometimes conflates functions with callables, so I can see where mypy is coming from.In either case, the discrepancy is unfortunate because it means we can't write typeshed stubs that satisfy both type checkers. We should come to an agreement on the right behavior and document it.
@Akuli pointed out a workaround for mypy's behavior: using a callable protocol (python/typeshed#7520 (comment))
The text was updated successfully, but these errors were encountered: