You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
1.11 regression: "generic" mapping failing with confusing error message #17566
I've boiled down a minimal example -- this pattern is used by pyupgrade (and reorder-python-imports) to register ast functions and has been working with mypy since version 0.710 -- but was broken with the last update sadly
To Reproduce
this is a simplified version of pyupgrade/_data.py -- FUNCS acts as a mapping from ast types to their callback functions
Bisects to #17311 , looks like some weird partial type situation where mypy gets a partial type from the FUNCS[tp].append but the type var scope there is different than the scope in ASTCallbackMapping.__getitem__.
Definitely should at least have a better error message, a possible workaround is FUNCS = cast(ASTCallbackMapping, collections.defaultdict(list))
making the Protocol generic isn't right either because then visit can't be typed properly -- the actual __getitem__ is what's generic, not the class itself
Sorry if I'm missing something, but isn't this error expected?
The protocol defines a "mapping from given type AST_T to a list of AST_T handlers corresponding to it". defaultdict does not guarantee that - there is no item-level type mapping. There's no way to specify the type of FUNCS that you want explicitly: defaultdict and dict are generic classes, their __getitem__ methods aren't generic.
Now mypy refuses to visit(store) as in your post, and also fails to infer store type wide enough.
There's nothing in static types of your original snippet preventing FUNCS[ast.And] = [handle_or], actually, and "it's only done by that function" is impossible to explain to mypy.
Activity
hauntsaninja commentedon Jul 23, 2024
Bisects to #17311 , looks like some weird partial type situation where mypy gets a partial type from the
FUNCS[tp].appendbut the type var scope there is different than the scope inASTCallbackMapping.__getitem__.Definitely should at least have a better error message, a possible workaround is
FUNCS = cast(ASTCallbackMapping, collections.defaultdict(list))erictraut commentedon Jul 23, 2024
Another workaround is to make
AST_Ta class-scoped type variable in the protocol definition:asottile commentedon Jul 28, 2024
making the Protocol generic isn't right either because then
visitcan't be typed properly -- the actual__getitem__is what's generic, not the class itselfhack around python/mypy#17566
hack around python/mypy#17566
sterliakov commentedon Jan 15, 2025
Sorry if I'm missing something, but isn't this error expected?
The protocol defines a "mapping from given type AST_T to a list of AST_T handlers corresponding to it".
defaultdictdoes not guarantee that - there is no item-level type mapping. There's no way to specify the type ofFUNCSthat you want explicitly:defaultdictanddictare generic classes, their__getitem__methods aren't generic.The problem:
Now
mypyrefuses tovisit(store)as in your post, and also fails to inferstoretype wide enough.There's nothing in static types of your original snippet preventing
FUNCS[ast.And] = [handle_or], actually, and "it's only done by that function" is impossible to explain tomypy.Note that you can't do
because
AST_Tis unbound there.