cubicweb/pylintext.py
changeset 11219 0796b6191cea
parent 11218 3fea2f3b25c1
child 11220 ffef75b7a26e
equal deleted inserted replaced
11218:3fea2f3b25c1 11219:0796b6191cea
     1 """Pylint plugin for cubicweb"""
     1 """Pylint plugin to analyse cubicweb cubes
     2 
     2 
     3 from astroid import MANAGER, InferenceError, nodes, scoped_nodes, ClassDef, FunctionDef
     3 Done:
       
     4 * turn functions decorated by @objectify_predicate into classes
       
     5 * add yams base types to yams.buildobjs module
       
     6 * add data() function to uiprops module's namespace
       
     7 * avoid 'abstract method not implemented' for `cell_call`, `entity_call`, `render_body`
       
     8 
       
     9 TODO:
       
    10 * avoid invalid class name for predicates and predicates
       
    11 * W:188, 0: Method '__lt__' is abstract in class 'Entity' but is not overridden (abstract-method)
       
    12 * generate entity attributes from the schema?
       
    13 """
       
    14 
       
    15 from astroid import MANAGER, InferenceError, nodes, ClassDef, FunctionDef
     4 from astroid.builder import AstroidBuilder
    16 from astroid.builder import AstroidBuilder
       
    17 
     5 from pylint.checkers.utils import unimplemented_abstract_methods, class_is_abstract
    18 from pylint.checkers.utils import unimplemented_abstract_methods, class_is_abstract
     6 
    19 
     7 
    20 
     8 def turn_function_to_class(node):
    21 def turn_function_to_class(node):
     9     """turn a Function node into a Class node (in-place)"""
    22     """turn a Function node into a Class node (in-place)"""
    10     node.__class__ = ClassDef
    23     node.__class__ = ClassDef
    11     node.bases = ()
    24     node.bases = ()
       
    25     # mark class as a new style class
       
    26     node._newstyle = True
    12     # remove return nodes so that we don't get warned about 'return outside
    27     # remove return nodes so that we don't get warned about 'return outside
    13     # function' by pylint
    28     # function' by pylint
    14     for rnode in node.nodes_of_class(nodes.Return):
    29     for rnode in node.nodes_of_class(nodes.Return):
    15         rnode.parent.body.remove(rnode)
    30         rnode.parent.body.remove(rnode)
       
    31     # add __init__ method to avoid no-init
       
    32 
    16     # that seems to be enough :)
    33     # that seems to be enough :)
    17 
    34 
    18 
    35 
    19 def cubicweb_transform(module):
    36 def cubicweb_transform(module):
    20     # handle objectify_predicate decorator (and its former name until bw compat
    37     # handle objectify_predicate decorator (and its former name until bw compat
    36     # add yams base types into 'yams.buildobjs', astng doesn't grasp globals()
    53     # add yams base types into 'yams.buildobjs', astng doesn't grasp globals()
    37     # magic in there
    54     # magic in there
    38     if module.name == 'yams.buildobjs':
    55     if module.name == 'yams.buildobjs':
    39         from yams import BASE_TYPES
    56         from yams import BASE_TYPES
    40         for etype in BASE_TYPES:
    57         for etype in BASE_TYPES:
    41             module.locals[etype] = [scoped_nodes.Class(etype, None)]
    58             module.locals[etype] = [ClassDef(etype, None)]
    42     # add data() to uiprops module
    59     # add data() to uiprops module
    43     if module.name.split('.')[-1] == 'uiprops':
    60     elif module.name.split('.')[-1] == 'uiprops':
    44         fake = AstroidBuilder(MANAGER).string_build('''
    61         fake = AstroidBuilder(MANAGER).string_build('''
    45 def data(string):
    62 def data(string):
    46   return u''
    63   return u''
    47 ''')
    64 ''')
    48         module.locals['data'] = fake.locals['data']
    65         module.locals['data'] = fake.locals['data']
    58     methods = sorted(
    75     methods = sorted(
    59         unimplemented_abstract_methods(classdef, is_abstract).items(),
    76         unimplemented_abstract_methods(classdef, is_abstract).items(),
    60         key=lambda item: item[0],
    77         key=lambda item: item[0],
    61     )
    78     )
    62 
    79 
    63     def dummy_method():
    80     dummy_method = AstroidBuilder(MANAGER).string_build('''
    64         """"""
    81 def dummy_method(self):
       
    82    """"""
       
    83 ''')
       
    84 
    65     for name, method in methods:
    85     for name, method in methods:
    66         owner = method.parent.frame()
    86         owner = method.parent.frame()
    67         if owner is classdef:
    87         if owner is classdef:
    68             continue
    88             continue
    69         if name not in classdef.locals:
    89         if name not in classdef.locals:
    70             if name in ('entity_call', 'render_body'):
    90             if name in ('cell_call', 'entity_call', 'render_body'):
    71                 classdef.set_local(name, dummy_method)
    91                 classdef.set_local(name, dummy_method)
    72 
    92 
    73 
    93 
    74 def register(linter):
    94 def register(linter):
    75     """called when loaded by pylint --load-plugins, nothing to do here"""
    95     """called when loaded by pylint --load-plugins, nothing to do here"""
    76     MANAGER.register_transform(nodes.Module, cubicweb_transform)
    96     MANAGER.register_transform(nodes.Module, cubicweb_transform)
    77     MANAGER.register_transform(nodes.ClassDef, cubicweb_abstractmethods_transform)
    97     MANAGER.register_transform(ClassDef, cubicweb_abstractmethods_transform)