Open glyph opened 1 year ago
I think for pep681 it's really important to keep pyright in the loop because the reference implementation is that of pyright: https://peps.python.org/pep-0681/#reference-implementation
for the above test case pyright only reports:
/home/classic/dev/sqlalchemy/test3.py /home/classic/dev/sqlalchemy/test3.py:21:18 - warning: Instance methods should take a "self" parameter (reportSelfClsParameterName)
for general pep-681 behavior you might want to raise it at https://github.com/python/peps/issues
It's not that dataclasses discern between "Callable" and "FunctionType", it's just that anything that quacks like a descriptor triggers the behavior described here.
Note the __get__
is only called a couple times, with instance=None
, meaning that it's not useful to e.g. bind a method to an instance. Maybe what you're hoping to do isn't even possible?
It looks to me like accidental behavior that got documented, given how it's a mere side-effect of how the default is represented (as a class variable's value), and how changing from Python syntax = d
to = field(default=d)
eliminates this behavior:
class Descriptor:
def __get__(self, instance, owner):
return 42
d = Descriptor()
@dataclass
class C:
- desc: Descriptor = d
+ desc: Descriptor = field(default=d)
c = C()
-assert c.desc == 42
+assert isinstance(c.desc, Descriptor)
Right now the plugin does not checks for field's type vs. default's type — it kinda happens on it own (due to typeshed annotations), thought it might be doable.
But is it even worthwhile to replicate given how odd and accidental this feature seems?
Bug Report
If you declare an attribute on a dataclass to be
Callable
, Mypy assumes that its__get__
will not be called, even on a default attribute. But this is only true if the default is aFunctionType
, not some other type of callable.Similarly, the inverse is true: an abstract type (such as a callable
Protocol
) will tell mypy that__get__
will be called, even though if the concrete default value is aFunctionType
, it won't be.Specifically, the following program contains 2 type errors, but MyPy does not think so:
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.11&gist=1ac4e7c090774489207dfbc737de2d61
Expected Behavior
I would expect runtime and type-time behavior to be consistent here. Specifically I just don't expect
__get__
to be called on things with aCallable
type.Actual Behavior
Mypy succeeds, rather than reporting the type errors.
Your Environment
mypy.ini
(and other config files): none