根据 pylint 插件的参数设置多个推断类型
Set multiple inferred types based on arguments for pylint plugin
我有一个 class 通过 class 变量实现一些类型检查。
然后,当 class 被实例化时,定义的变量成为 class 所需的参数,具有所需的类型。该模式看起来像这样:
class MyClass(MagicBaseClass):
arg1 = ArgumentObj(allowedTypes=(basestring, ))
arg2 = ArgumentObj(allowedTypes=(list, tuple))
def myMethod(self):
print type(self.arg1) # a basestring
print type(self.arg2) # a list
mc = MyClass(arg1='test', arg2=())
mc.myMethod()
Pylint 不喜欢这样。它将 arg1
和 arg2
视为 ArgumentObj
的实例。所以我想写一个插件来读取传递的类型,并将这些对象视为我 MagicBaseClass
.
中那些类型的实例
所以,我已经能够弄清楚如何为 class 转换挖掘到正确的节点,并且我可以访问我需要的所有数据,但我真的不知道怎么办。关键是多种允许的类型。我现在找不到任何例子来处理这个问题,我能找到的文档基本上没用。
from astroid import MANAGER
from astroid import nodes, node_classes
def transform_myClass(node):
for key, value in node.locals.items():
val = value[0]
try:
s = val.statement().value
if s.func.name != 'ArgumentObj':
continue
except AttributeError:
continue
for child in s.get_children():
if not isinstance(child, node_classes.Keyword):
continue
if child.arg == 'allowedTypes':
typeNames = child.value
#### And here is where I have no idea what to do next ####
MANAGER.register_transform(nodes.ClassDef, transform_myClass)
有 Name
个对象。这些基本上是您的文件中的字符串 在 对它们进行任何操作之前。要获得它们可能的样子,您必须 .infer()
它们。这会将文件 "basestring" 中的单词变成一个小行星 class-ish 对象 basestring
(好吧,实际上它 returns 是一个生成器......但这里是粗略的)。
然后,给定这些 astroid class-ish 对象,你必须 "instantiate" class 到 astroid instance-ish 对象。
最后(重要的部分),node.locals.items()
是{name: list of instance-ish objects}
的字典。更新该字典可让您设置推断类型。
所以我上面的粗略代码会变成这样:
from astroid import MANAGER
from astroid import nodes, node_classes
def transform_myClass(node):
updater = {}
for key, value in node.locals.items():
val = value[0]
try:
s = val.statement().value
if s.func.name != 'ArgumentObj':
continue
except AttributeError:
continue
# Collect all the inferred types in this list
typeList = []
for child in s.get_children():
if not isinstance(child, node_classes.Keyword):
continue
# What I needed to do was here:
# Infer the child classes, and return the instantiated class
if child.arg == 'allowedTypes':
for tc in child.value.get_children():
for cls in tc.infer():
typeList.append(cls.instantiate_class())
updater[key] = typeList
# Finally, I needed to update the locals
# which sets the inferred types of the class members
node.locals.update(updater)
MANAGER.register_transform(nodes.ClassDef, transform_myClass)
我有一个 class 通过 class 变量实现一些类型检查。 然后,当 class 被实例化时,定义的变量成为 class 所需的参数,具有所需的类型。该模式看起来像这样:
class MyClass(MagicBaseClass):
arg1 = ArgumentObj(allowedTypes=(basestring, ))
arg2 = ArgumentObj(allowedTypes=(list, tuple))
def myMethod(self):
print type(self.arg1) # a basestring
print type(self.arg2) # a list
mc = MyClass(arg1='test', arg2=())
mc.myMethod()
Pylint 不喜欢这样。它将 arg1
和 arg2
视为 ArgumentObj
的实例。所以我想写一个插件来读取传递的类型,并将这些对象视为我 MagicBaseClass
.
所以,我已经能够弄清楚如何为 class 转换挖掘到正确的节点,并且我可以访问我需要的所有数据,但我真的不知道怎么办。关键是多种允许的类型。我现在找不到任何例子来处理这个问题,我能找到的文档基本上没用。
from astroid import MANAGER
from astroid import nodes, node_classes
def transform_myClass(node):
for key, value in node.locals.items():
val = value[0]
try:
s = val.statement().value
if s.func.name != 'ArgumentObj':
continue
except AttributeError:
continue
for child in s.get_children():
if not isinstance(child, node_classes.Keyword):
continue
if child.arg == 'allowedTypes':
typeNames = child.value
#### And here is where I have no idea what to do next ####
MANAGER.register_transform(nodes.ClassDef, transform_myClass)
有 Name
个对象。这些基本上是您的文件中的字符串 在 对它们进行任何操作之前。要获得它们可能的样子,您必须 .infer()
它们。这会将文件 "basestring" 中的单词变成一个小行星 class-ish 对象 basestring
(好吧,实际上它 returns 是一个生成器......但这里是粗略的)。
然后,给定这些 astroid class-ish 对象,你必须 "instantiate" class 到 astroid instance-ish 对象。
最后(重要的部分),node.locals.items()
是{name: list of instance-ish objects}
的字典。更新该字典可让您设置推断类型。
所以我上面的粗略代码会变成这样:
from astroid import MANAGER
from astroid import nodes, node_classes
def transform_myClass(node):
updater = {}
for key, value in node.locals.items():
val = value[0]
try:
s = val.statement().value
if s.func.name != 'ArgumentObj':
continue
except AttributeError:
continue
# Collect all the inferred types in this list
typeList = []
for child in s.get_children():
if not isinstance(child, node_classes.Keyword):
continue
# What I needed to do was here:
# Infer the child classes, and return the instantiated class
if child.arg == 'allowedTypes':
for tc in child.value.get_children():
for cls in tc.infer():
typeList.append(cls.instantiate_class())
updater[key] = typeList
# Finally, I needed to update the locals
# which sets the inferred types of the class members
node.locals.update(updater)
MANAGER.register_transform(nodes.ClassDef, transform_myClass)