python / python/mypy

Protocol invariance not tracked if subclassed

Aperta
#18,724 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

bug
Lingua principale
Python
Stelle
20.6k
Fork
3.3k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Bug Report

Taking the Protocol with @property example from the docs: https://mypy.readthedocs.io/en/stable/protocols.html#invariance-of-protocol-attributes
The example shows that attributes must be read-only for subclass covariance to be inferred. This makes sense.

However, if a child class explicitly subclasses the Protocol then mypy doesn't report the error. This results in unsound code. This seems like a bug in typechecker behavior (and also docs which are confusing.)

To Reproduce

class Box(Protocol):
    content: object

def takes_box(box: Box) -> None:
    box.content = object()

@dataclasses.dataclass(slots=False)
class BadBox(Box):  # XXX: inheritence wrongly hides the error
    content: int

takes_box(BadBox(42))  # XXX should fail but doesn't!!

Full example here: https://mypy-play.net/?mypy=latest&python=3.11&gist=4d7e99ee4f933393234041a219e3f952

Expected Behavior

mypy to report that BadBox.content doesn't match Box, either in the declaration of content: int or in the function call to takes_box.

Actual Behavior

Mypy reports no errors, but at runtime, BadBox.content is no longer an int.

Notes

  1. if Box.content: str, then a liskov error is reported for BadBox.content: int, but in the above example, because int is a subclass of object no error seems to be reported.

  2. Perhaps ReadOnly will help here? https://peps.python.org/pep-0767/ I tried using Final but it's not allowed in Protocols unfortunately.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con il reproducer dell’invarianza di Protocol nell’issue e confronta il caso della sottoclasse esplicita con l’esempio documentato di @property, usando l’esempio collegato di mypy-play per verificare il comportamento. Il lavoro è completato quando mypy segnala l’attributo mutabile incompatibile o rifiuta la chiamata a takes_box, con copertura per il caso object-to-int.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
compilers
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Specificata chiaramente
Idoneità per principianti
42/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.