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

Abierto
#18,179 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
55/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Estancado
Stack tecnológico
python
Área
devtools

Línea de trabajo

Comienza en subtypes.py, en get_member_flags(), y compara el tratamiento de v.is_property con el estado v.is_settable_property establecido por plugins/dataclasses.py:_propertize_callables(). Usa la reproducción del issue con mypy 1.13.0 para verificar el comportamiento y, después, confirma que el dataclass con un campo Callable coincide con el protocolo sin el error de asignación indicado.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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
Lenguaje dominante
Python
Estrellas
20.6k
Forks
3.3k
Merge medio
1 d 18 h
PR fusionados (30 d)
54

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de python/mypy

Todos los issues de python/mypy

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.