A decorator implementing the descriptor protocol is incorrectly regarded read-only
Nessuno ha ancora preso questa issue.
- Lingua principale
- Python
- Stelle
- 20.6k
- Fork
- 3.3k
- Metriche di merge delle PR
- Metriche PR in attesa
Descrizione
Bug Report
A class-based decorator that implements the data descriptor protocol is incorrectly regarded as read-only, and does not match against itself in a Protocol. This bug was discovered when trying to implement protocols that match against SQLAlchemy's declared_attr decorator.
To Reproduce
Pattern in typical use:
from sqlalchemy.orm import Mapped, declared_attr
class MyModel:
@declared_attr
@classmethod
def foo(cls) -> Mapped[int]: ...
reveal_type(foo) # declared_attr[int]
reveal_type(foo.__set__) # exists, so this is a data descriptor
reveal_type(foo.__get__) # Typed as `-> int | InstrumentedAttribute[int]`, unlike `property.__get__`
class MyProtocol:
foo: declared_attr[int]
o: MyProtocol = MyModel() # Error: MyProtocol.foo expected settable variable, got read-only attribute
Here is an isolated code sample without external dependencies. This bug does not appear when the method decorator is replaced with a function call after method definition, and appears to be a side-effect of how Mypy processes decorators.
https://mypy-play.net/?gist=5eb1e9262cd880a77fd3b9fb5bb7dca0
Marking the attribute as read-only in the Protocol using @property works when the attribute is accessed via the instance, but not when accessed via the class (as o.__class__.foo), because it gets typed as property.fget (Mypy) or as an error (Pyright), instead of the expected declared_attr.__get__ return type.
This problem exists in all versions of Mypy available at mypy-play, including the latest release 1.8.0. Pyright 1.1.338 does not have this problem.
Expected Behavior
A decorated method that is turned into a descriptor should not be regarded as read-only when matching against a protocol.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia con il sample isolato di mypy-play e con i percorsi di elaborazione dei decorator e di corrispondenza degli attributi di Protocol che esercita. Riproduci la diagnostica di sola lettura, quindi traccia il modo in cui vengono tipizzati i metodi descriptor del metodo decorato; il risultato è raggiunto quando un descriptor di dati corrisponde a Protocol come assegnabile e l’accesso alla classe conserva il tipo restituito atteso di get.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- python, sqlalchemy
- Ambito
- compilers, devtools
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Ferma
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100