如何让pylint通过astroid识别变量

How to make pylint recognize variable via astroid

我正在尝试"teach" pylint 来识别成员函数,我的场景可以简化为以下:

主模块: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()

插件文件夹文件plu.py:

plugins = {}
class Plugin(object):
   def foo(self, arg):
       print("bar %s" % arg)

plugins['plu'] = Plugin

插件在 FooClass 对象上注册自己和一些其他方法 "introduces" 的想法。

a.py 的输出是:

bar asdasd

(符合预期)

运行 pylint -E a.py 产生以下错误:

pylint  -E a.py 
************* Module a
E:  5, 8: Instance of 'FooClass' has no 'plu' member (no-member)

我曾尝试编写以下 pylint 插件:

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)

运行pylint --load-plugins=$(pwd)/pylint-plugin -E a.py的输出是:

************* Module a
E:  5, 8: No value for argument 'arg' in unbound method call (no-value-for-parameter)

从错误中我怀疑我以某种方式错误地引入了 属性,因为 pylint 认为方法 foo 是无界的,但它确实是有界的。我需要找到一种方法来告诉 pylint foo_cls[0].locals['plu'] 实际上是 class Plugin 的一个实例,而不是 class 本身。知道如何实现吗?

您需要在将插件添加到 FooClass 的局部变量时实例化插件 class。所以将这一行 foo_cls[0].locals['plu'] = plugin_cls_def.lookup('Plugin')[1] 替换为 foo_cls[0].locals['plu'] = [cls.instantiate_class() for cls in plugin_cls_def.lookup('Plugin')[1]]