cubicweb/pylintext.py
author Philippe Pepiot <ph@itsalwaysdns.eu>
Tue, 31 Mar 2020 19:15:03 +0200
changeset 12957 0c973204033a
parent 11220 ffef75b7a26e
permissions -rw-r--r--
[server] prevent returning closed cursor to the database pool In since c8c6ad8 init_repository use repo.internal_cnx() instead of repo.system_source.get_connection() so it use the pool and we should not close cursors from the pool before returning it back. Otherwise we may have "connection already closed" error. This bug only trigger when connection-pool-size = 1. Since we are moving to use a dynamic pooler we need to get this fixed. This does not occur with sqlite since the connection wrapper instantiate new cursor everytime, but this occur with other databases.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     1
"""Pylint plugin to analyse cubicweb cubes
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     2
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     3
Done:
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     4
* turn functions decorated by @objectify_predicate into classes
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     5
* add yams base types to yams.buildobjs module
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     6
* add data() function to uiprops module's namespace
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
     7
* avoid 'abstract method not implemented' for `cell_call`, `entity_call`, `render_body`
11220
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
     8
* avoid invalid-name on schema relation class names
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     9
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    10
TODO:
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    11
* avoid invalid class name for predicates and predicates
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    12
* W:188, 0: Method '__lt__' is abstract in class 'Entity' but is not overridden (abstract-method)
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    13
* generate entity attributes from the schema?
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    14
"""
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    15
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    16
from astroid import MANAGER, InferenceError, nodes, ClassDef, FunctionDef
9311
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    17
from astroid.builder import AstroidBuilder
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    18
11218
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    19
from pylint.checkers.utils import unimplemented_abstract_methods, class_is_abstract
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    20
11217
1f686f55ef3d [pylint] upgrade pylintext plugin
Laura Médioni <laura.medioni@logilab.fr>
parents: 11057
diff changeset
    21
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    22
def turn_function_to_class(node):
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    23
    """turn a Function node into a Class node (in-place)"""
11217
1f686f55ef3d [pylint] upgrade pylintext plugin
Laura Médioni <laura.medioni@logilab.fr>
parents: 11057
diff changeset
    24
    node.__class__ = ClassDef
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    25
    node.bases = ()
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    26
    # mark class as a new style class
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    27
    node._newstyle = True
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    28
    # remove return nodes so that we don't get warned about 'return outside
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    29
    # function' by pylint
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    30
    for rnode in node.nodes_of_class(nodes.Return):
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    31
        rnode.parent.body.remove(rnode)
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    32
    # add __init__ method to avoid no-init
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    33
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    34
    # that seems to be enough :)
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    35
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    36
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    37
def cubicweb_transform(module):
8190
2a3c1b787688 [vreg] move base registry implementation to logilab.common. Closes #1916014
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8061
diff changeset
    38
    # handle objectify_predicate decorator (and its former name until bw compat
2a3c1b787688 [vreg] move base registry implementation to logilab.common. Closes #1916014
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8061
diff changeset
    39
    # is kept). Only look at module level functions, should be enough.
10663
54b8a1f249fb [py3k] dict.itervalues → dict.values
Rémi Cardona <remi.cardona@logilab.fr>
parents: 9311
diff changeset
    40
    for assnodes in module.locals.values():
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    41
        for node in assnodes:
11217
1f686f55ef3d [pylint] upgrade pylintext plugin
Laura Médioni <laura.medioni@logilab.fr>
parents: 11057
diff changeset
    42
            if isinstance(node, FunctionDef) and node.decorators:
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    43
                for decorator in node.decorators.nodes:
9311
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    44
                    try:
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    45
                        for infered in decorator.infer():
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    46
                            if infered.name in ('objectify_predicate', 'objectify_selector'):
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    47
                                turn_function_to_class(node)
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    48
                                break
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    49
                        else:
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    50
                            continue
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    51
                        break
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    52
                    except InferenceError:
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    53
                        continue
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    54
    # add yams base types into 'yams.buildobjs', astng doesn't grasp globals()
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    55
    # magic in there
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    56
    if module.name == 'yams.buildobjs':
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    57
        from yams import BASE_TYPES
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    58
        for etype in BASE_TYPES:
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    59
            module.locals[etype] = [ClassDef(etype, None)]
8061
88ca47ceb9f2 [pylint] enhance plugin: define 'data' function in uiprops module
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7941
diff changeset
    60
    # add data() to uiprops module
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    61
    elif module.name.split('.')[-1] == 'uiprops':
9311
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
    62
        fake = AstroidBuilder(MANAGER).string_build('''
8061
88ca47ceb9f2 [pylint] enhance plugin: define 'data' function in uiprops module
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7941
diff changeset
    63
def data(string):
88ca47ceb9f2 [pylint] enhance plugin: define 'data' function in uiprops module
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7941
diff changeset
    64
  return u''
88ca47ceb9f2 [pylint] enhance plugin: define 'data' function in uiprops module
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7941
diff changeset
    65
''')
88ca47ceb9f2 [pylint] enhance plugin: define 'data' function in uiprops module
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 7941
diff changeset
    66
        module.locals['data'] = fake.locals['data']
11220
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    67
    # handle lower case with underscores for relation names in schema.py
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    68
    if not module.qname().endswith('.schema'):
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    69
        return
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    70
    schema_locals = module.locals
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    71
    for assnodes in schema_locals.values():
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    72
        for node in assnodes:
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    73
            if not isinstance(node, ClassDef):
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    74
                continue
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    75
            # XXX can we infer ancestor classes? it would be better to know for sure that
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    76
            # one of the mother classes is yams.buildobjs.RelationDefinition for instance
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    77
            for base in node.basenames:
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    78
                if base in ('RelationDefinition', 'ComputedRelation', 'RelationType'):
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    79
                    new_name = node.name.replace('_', '').capitalize()
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    80
                    schema_locals[new_name] = schema_locals[node.name]
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    81
                    del schema_locals[node.name]
ffef75b7a26e [pylint] Avoid invalid-name on schema relation class names
Laura Médioni <laura.medioni@logilab.fr>
parents: 11219
diff changeset
    82
                    node.name = new_name
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    83
11217
1f686f55ef3d [pylint] upgrade pylintext plugin
Laura Médioni <laura.medioni@logilab.fr>
parents: 11057
diff changeset
    84
11218
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    85
def cubicweb_abstractmethods_transform(classdef):
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    86
    if class_is_abstract(classdef):
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    87
        return
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    88
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    89
    def is_abstract(method):
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    90
        return method.is_abstract(pass_is_abstract=False)
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    91
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    92
    methods = sorted(
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    93
        unimplemented_abstract_methods(classdef, is_abstract).items(),
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    94
        key=lambda item: item[0],
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    95
    )
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
    96
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    97
    dummy_method = AstroidBuilder(MANAGER).string_build('''
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    98
def dummy_method(self):
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
    99
   """"""
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
   100
''')
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
   101
11218
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   102
    for name, method in methods:
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   103
        owner = method.parent.frame()
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   104
        if owner is classdef:
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   105
            continue
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   106
        if name not in classdef.locals:
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
   107
            if name in ('cell_call', 'entity_call', 'render_body'):
11218
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   108
                classdef.set_local(name, dummy_method)
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   109
3fea2f3b25c1 [pylint] remove abstract-method warning
Laura Médioni <laura.medioni@logilab.fr>
parents: 11217
diff changeset
   110
7941
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   111
def register(linter):
018b5deca73e pylint extension
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   112
    """called when loaded by pylint --load-plugins, nothing to do here"""
9311
8833ead6f3e4 update pylint extension to astroid API
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 8696
diff changeset
   113
    MANAGER.register_transform(nodes.Module, cubicweb_transform)
11219
0796b6191cea [pylint] more work on the pylint support
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 11218
diff changeset
   114
    MANAGER.register_transform(ClassDef, cubicweb_abstractmethods_transform)