2017-10-18 6 views
0

J'ai une classe qui implémente une vérification typographique via des variables de classe. Ensuite, lorsque la classe est instanciée, les variables définies deviennent les arguments requis pour la classe, avec les types requis. Le motif ressemble à ceci:Définir plusieurs types déduits basés sur des arguments pour le plugin pylint

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 n'apprécie pas cela. Il voit arg1 et arg2 comme instances de ArgumentObj. Donc, je veux écrire un plugin qui lit les types passés, et traite ces objets comme des instances de ces types à l'intérieur de mon MagicBaseClass. Donc, j'ai été capable de comprendre comment trouver les bons nœuds pour la transformation de classe, et je peux accéder à toutes les données dont j'ai besoin, mais je ne sais pas trop quoi en faire. . Le kicker est le multiple types autorisés. Je ne trouve aucun exemple pour gérer cela, et les documents que je peux trouver sont fondamentalement inutiles.

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) 

Répondre

0

Il existe Name objets. Ce sont essentiellement les chaînes dans votre fichier avant tout est fait pour eux. Pour obtenir ce qu'ils seront, vous devez les .infer(). Cela transforme quelque chose comme le mot dans le fichier "basetring" en un objet de classe astroïde basestring (bien, en fait, il renvoie un générateur ... mais larges traits ici). Puis, étant donné ces objets de classe astroïde, vous devez "instancier" la classe en un objet instance-iso astroïde. Enfin, (la partie importante), node.locals.items() est un dictionnaire de {name: list of instance-ish objects}. La mise à jour de ce dictionnaire vous permet de définir les types déduits.

donc mon code à large coups de se tourner au-dessus dans ce:

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)