Dataclass doesn't match a protocol if a field is Callable (expected settable variable, got read-only attribute)

Offen
#18,179 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Anfängerfreundlichkeit
55/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Veraltet
Tech-Stack
python
Bereich
devtools

Rechercherichtung

Beginne in subtypes.py bei get_member_flags() und vergleiche die Behandlung von v.is_property mit dem von plugins/dataclasses.py:_propertize_callables() gesetzten Zustand v.is_settable_property. Verwende die Reproduktion des Issues mit mypy 1.13.0, um das Verhalten zu überprüfen, und bestätige anschließend, dass die Dataclass mit einem Callable-Feld ohne den gemeldeten Zuweisungsfehler zum Protokoll passt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

bug

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
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
Ø Merge
1 T. 18 Std.
Gemergte PRs (30 T.)
54

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus python/mypy

Alle Issues in python/mypy

Ähnliche Issues

Weitere Issues zu Python

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.