I'm trying to "teach" pylint to recognize member function, my scenario can be simplified to the following:
Main module: a.py
from plugins import plu
class FooClass(object):
def bar(self):
self.plu.foo("asdasd")
if __name__ == '__main__':
a = FooClass()
for plugin_name, plugin in plu.plugins.items():
setattr(a, plugin_name, plugin())
a.bar()
Plugins folder file plu.py:
plugins = {}
class Plugin(object):
def foo(self, arg):
print("bar %s" % arg)
plugins['plu'] = Plugin
The idea that plugins register themselves and some other method "introduces" them on the FooClass
object.
Output of the a.py is:
bar asdasd
(as expected)
Running pylint -E a.py
yields the following error:
pylint -E a.py
************* Module a
E: 5, 8: Instance of 'FooClass' has no 'plu' member (no-member)
I had tried to write the following pylint-plugin:
import astroid
from astroid import nodes
def transform_test_class(mod):
if mod.name != 'a':
return
foo_cls = mod.lookup('FooClass')[1]
plugin_cls_def = astroid.MANAGER.ast_from_module_name('plugins.plu')
foo_cls[0].locals['plu'] = plugin_cls_def.lookup('Plugin')[1]
def register(linter):
astroid.MANAGER.register_transform(nodes.Module, transform_test_class)
Output of running pylint --load-plugins=$(pwd)/pylint-plugin -E a.py
is:
************* Module a
E: 5, 8: No value for argument 'arg' in unbound method call (no-value-for-parameter)
From the error I suspect that somehow I introduce the property incorrectly, as pylint thinks that method foo
is unbounded, but it is indeed bounded. I need to find a way to tell pylint that foo_cls[0].locals['plu']
is actually an instance of class Plugin
and not the class itself. Any idea how this can be achieved?
You need to instantiate the plugin class when adding it to the locals of the FooClass. So replace this line foo_cls[0].locals['plu'] = plugin_cls_def.lookup('Plugin')[1]
with foo_cls[0].locals['plu'] = [cls.instantiate_class() for cls in plugin_cls_def.lookup('Plugin')[1]]