Dataclass doesn't match a protocol if a field is Callable (expected settable variable, got read-only attribute)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 20.6k
- Forks
- 3.3k
- PR merge metrics
- PR metrics pending
Description
Bug Report
A dataclass containing a Callable field doesn't match the protocol. On the other hand if the field is defined using a callback protocol (another protocol with __call__) or the class is not a dataclass, no error is reported.
test.py:26: error: Incompatible types in assignment (expression has type "FooDC", variable has type "FooProto") [assignment]
test.py:26: note: Protocol member FooProto.f expected settable variable, got read-only attribute
The mypy's subtypes.py:get_member_flags() function contains:
if v.is_property:
return {IS_VAR}
which doesn't take the v.is_settable_property into account while it is set for Callables in plugins/dataclasses.py:_propertize_callables().
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=5c77ed1a30b03cba5cf0ba8e710a4214
import typing
import collections.abc
import dataclasses
CAC = collections.abc.Callable[..., None]
class FooProto(typing.Protocol):
f: CAC
class Foo:
f: CAC
def __init__(self, f: CAC):
self.f = f
@dataclasses.dataclass(frozen=False)
class FooDC:
f: CAC
foo: FooProto = Foo(lambda: None)
# only foo_dc fails:
# test.py:23: error: Incompatible types in assignment (expression has type "FooDC", variable has type "FooProto") [assignment]
# test.py:23: note: Protocol member FooProto.f expected settable variable, got read-only attribute
foo_dc: FooProto = FooDC(lambda: None)
class CallbackProto(typing.Protocol):
def __call__(self, *args, **kwargs) -> None: ...
class FooProtoCallback(typing.Protocol):
f: CallbackProto
class FooCallback:
f: CallbackProto
def __init__(self, f: CAC):
self.f = f
@dataclasses.dataclass(frozen=False)
class FooDCCallback:
f: CallbackProto
foo_callback: FooProtoCallback = FooCallback(lambda: None)
foo_dc_callback: FooProtoCallback = FooDCCallback(lambda: None)
Expected Behavior
I expect a dataclass with a Callable to match the protocol.
Actual Behavior
The dataclass doesn't match the protocol.
Your Environment
- Mypy version used: 1.13.0
- Mypy command-line flags: none
- Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.11.2
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 in subtypes.py at get_member_flags() and compare its handling of v.is_property with the v.is_settable_property state set by plugins/dataclasses.py:_propertize_callables(). Use the issue's reproduction with mypy 1.13.0 to verify the behavior, then confirm that the dataclass with a Callable field matches the protocol without the reported assignment error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100