I'm trying to make my first mypy plugin to add typechecking for this code
adt.py
from dataclasses import make_dataclass
def adt(datatype, *ctrs: str):
basecls = type(datatype, (), {})
klass = lambda x: x.split()[0]
fields = lambda x: x.split()[1:]
clss = (make_dataclass(klass(cls),
bases=(basecls,),
fields=fields(cls))
for cls in ctrs)
return (basecls, *clss)
Maybe, Just, None_ = adt("Maybe", "Just x", "None")
j = Just(1)
def foo(m: Maybe):
pass
I create a adt_plugin.py
file saved to disk and configured mypy.ini
to load it, it's being loaded (I can see some of the prints), but it seems that my plugin callback is not being called, what I'm missing?
My plugin code doesn't do nothing, it just fails by now
adt_plugin.py
from typing import *
from mypy.plugin import Plugin, DynamicClassDefContext
T = TypeVar('T')
CB = Optional[Callable[[T], None]]
class AdtPlugin(Plugin):
def get_dynamic_class_hook(self, fullname: str) -> 'CB[DynamicClassDefContext]':
print(fullname)
if fullname == "adt.adt":
print("foo")
print(decl_info_hook)
return decl_info_hook
return None
def plugin(version: str):
# ignore version argument if the plugin works with all mypy versions.
return AdtPlugin
def decl_info_hook(ctx : DynamicClassDefContext) -> None:
ctx.api.fail("Not able to calculate MRO for declarative base", ctx.call)
mypy.ini
(on the current folder)
[mypy]
plugins = /home/geckos/code/python/adt_plugin.py
When I run mypy adt.py
I see:
python mypy --no-incremental adt.py
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
builtins.object
adt.adt
foo
<function decl_info_hook at 0x7f55cabf9ab0>
adt.Just
builtins.type
adt.py:19: error: Variable "adt.Maybe" is not valid as a type
adt.py:19: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
Found 1 error in 1 file (checked 1 source file)
So there is foo
, so that AdtPlugin.get_dynamic_class_hook
is being called, and it's returning the decl_info_hook
too, the function name is right, we can see it in the print, but the function is not called at all, I put an error on it, I also tried raise Exception("foooo")
inside of it but nothings happens.
Any idea how to debug this?
Okay, I got the problem, mypy won't detect this x, y, ..., z = something()
as a dynamic class creation. The statement need to have the form a = f()
where a single value is assigned, otherwise it won't call the plugin hook.