python / python/mypy

Misbehavior of `expand_type` in pydantic mypy plugin

Offen
#16,087 0 Kommentare 2 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

topic-plugins
Vorherrschende Sprache
Python
Sterne
20.6k
Forks
3.3k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

In writing the pydantic mypy plugin, I have leaned heavily on the code from the dataclasses plugin. Recently, a couple issues have been reported with misbehavior that I was able to track down to being caused by a call to expand_type changing the type from Union[str, None] to just str.

In particular, the following code snippet is misbehaving while using the pydantic mypy plugin (reported in https://github.com/pydantic/pydantic/issues/7399):

import pydantic

class Model(pydantic.BaseModel):
    model_config = {'frozen': True}
    my_var: str | None = pydantic.Field(default=None)

class SubModel(Model):
    pass

reveal_type(SubModel.my_var)
#> note: Revealed type is "builtins.str"

(The revealed type should have been "Union[builtins.str, None]".)

If I change

class Model(pydantic.BaseModel):
    model_config = {'frozen': True}
    ...

to

import dataclasses
@dataclasses.dataclass(frozen=True)
class Model:
    ...

I do get the expected reveal_type result of "Union[builtins.str, None]".

After a bit of digging, I was able to trace this down to the code that freezes fields, and in particular, if I comment out this block, the issue goes away. Digging further, I found the issue was that, in this line, I would sometimes end up getting str as the "expanded type" for Union[str, None].

Of course, I also noticed the verbatim warning comment, which was taken from the dataclasses plugin here. It seems that the caveats:

however this plugin is called very late...

only apply to the dataclasses plugin, as I do not get the same (correct) behavior in the pydantic plugin. I was able to find a hacky work-around for this specific failure (included in this PR), where, if I passed in a Union and got out a non-Union from expand_type I defer analysis, and this did resolve one of the reported issues, but it feels to me like there are probably many other cases that that won't handle correctly, and I'm not sure what exactly I can/should do to handle this more correctly.

Any suggestions about how to ensure that the pydantic plugin behaves the same as the dataclasses plugin with regard to expand_type would be appreciated! (Or other suggestions about how to improve the plugin logic, of course.)

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit dem Reproducer im Issue und untersuche pydantic/mypy.py im Block zum Einfrieren von Feldern um die Zeilen 876-880 sowie den expand_type-Aufruf um Zeile 354. Vergleiche das Verhalten mit mypy/plugins/dataclasses.py und überprüfe anschließend, dass reveal_type für das geerbte optionale Feld weiterhin Union[builtins.str, None] ergibt, ohne das sonstige Verhalten des Plugins zum Einfrieren von Feldern zu beeinträchtigen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

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