Plugin development: Use of `get_dynamic_class_hook` causes deserialization of types to fail from `.mypy_cache`
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
Hello folks. I'm working on a plugin that uses get_dynamic_class_hook to construct type constructors (TypeInfo) and class definitions (ClassDef) that don't exist in a module. I add these definitions to a MypyFile. Finally, I add this MypyFile to the modules dictionary provided by the SemanticAnalyzerPluginInterface API to convince mypy of my "fake" module.
This works wonderfully until a second run of my plugin when the .mypy_cache has been constructed. Before semantic analysis, mypy seems to be trying to read my fake module, because in the cache names in real modules have a target that refers to the fake module. For instance,
{
".class": "MypyFile",
"_fullname": "RealModule",
...
"names": {
".class": "SymbolTable",
...
"SomeType": {
".class": "SymbolTableNode",
"kind": "Gdef",
"node": {
".class": "TypeAlias",
...
"fullname": "RealModule.SomeType",
...
"target": "FakeModule.SomeType"
}
},
...
The stacktrace is below. mypy fails to resolve FakeModule.SomeType because FakeModule doesn't exist in its modules dictionary. I don't think my use of get_dynamic_class_hook is unusual, so I think there's a hole in my understanding of this hook.
...
-> process_graph(graph, manager)
/usr/lib/python3.9/site-packages/mypy/build.py(3333)process_graph()
-> process_fresh_modules(graph, prev_scc, manager)
/usr/lib/python3.9/site-packages/mypy/build.py(3414)process_fresh_modules()
-> graph[id].fix_cross_refs()
/usr/lib/python3.9/site-packages/mypy/build.py(2110)fix_cross_refs()
-> fixup_module(self.tree, self.manager.modules, self.options.use_fine_grained_cache)
/usr/lib/python3.9/site-packages/mypy/fixup.py(52)fixup_module()
-> node_fixer.visit_symbol_table(tree.names, tree.fullname)
/usr/lib/python3.9/site-packages/mypy/fixup.py(156)visit_symbol_table()
-> self.visit_type_info(value.node)
/usr/lib/python3.9/site-packages/mypy/fixup.py(115)visit_type_info()
-> self.current_info = save_info
/usr/lib/python3.9/site-packages/mypy/fixup.py(158)visit_symbol_table()
-> value.node.accept(self)
/usr/lib/python3.9/site-packages/mypy/nodes.py(1037)accept()
-> return visitor.visit_var(self)
/usr/lib/python3.9/site-packages/mypy/fixup.py(211)visit_var()
-> v.type.accept(self.type_fixer)
/usr/lib/python3.9/site-packages/mypy/types.py(1444)accept()
-> return visitor.visit_instance(self)
/usr/lib/python3.9/site-packages/mypy/fixup.py(230)visit_instance()
-> inst.type = lookup_fully_qualified_typeinfo(
/usr/lib/python3.9/site-packages/mypy/fixup.py(367)lookup_fully_qualified_typeinfo()
-> stnode = lookup_fully_qualified(name, modules, raise_on_missing=not allow_missing)
/usr/lib/python3.9/site-packages/mypy/lookup.py(31)lookup_fully_qualified()
-> assert "." in head, f"Cannot find module for {name}"
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 l’API get_dynamic_class_hook e il percorso di deserializzazione della cache in build.py, quindi segui fix_cross_refs attraverso fixup.py e lookup.py usando lo stack trace riportato. Riproduci la seconda esecuzione con .mypy_cache e un modulo fittizio e verifica che i tipi creati dai plugin possano essere deserializzati senza una ricerca del modulo non risolta.
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
- Da chiarire
- Idoneità per principianti
- 35/100