summaryrefslogtreecommitdiffstats
path: root/testsuite/ext/pylint_compat.py
blob: 5300df8e6d6318cc065c300b585afc97242498b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
from pylint.__pkginfo__ import version as pylint_version

try:
    from logilab.astng.__pkginfo__ import version as astng_version
except ImportError:
    from astroid.__pkginfo__ import version as astng_version


def register(linter):
    if pylint_version < '0.24.0':
        import pylint.utils
        orig_check_message_id = pylint.utils.MessagesHandlerMixIn.check_message_id
        def check_message_id(self, msgid):
            # translate the new message ids back into the old ones
            replacements = {'12': '65', '13': '99'}
            new = msgid[1:3]
            if new in replacements:
                msgid = msgid[0] + replacements[new] + msgid[3:]
            return orig_check_message_id(self, msgid)
        pylint.utils.MessagesHandlerMixIn.check_message_id = check_message_id

        def ignore(meth, msgid, *args, **kwargs):
            # ignore non-existent message ids in disable/enable comments
            ignore = ['W1401', 'R0924']
            if msgid in ignore:
                return
            return meth(msgid, *args, **kwargs)
        linter._options_methods['disable'] = lambda *args, **kwargs: ignore(linter.disable, *args, **kwargs)
        linter._options_methods['enable'] = lambda *args, **kwargs: ignore(linter.enable, *args, **kwargs)

    if pylint_version < '0.22.0':
        import pylint.checkers.exceptions
        orig_visit_raise = pylint.checkers.exceptions.ExceptionsChecker.visit_raise
        def visit_raise(self, node):
            if not hasattr(node, 'type') and hasattr(node, 'exc'):
                node.type = node.exc
            return orig_visit_raise(self, node)
        pylint.checkers.exceptions.ExceptionsChecker.visit_raise = visit_raise

    if astng_version < '0.23':
        import logilab.astng.scoped_nodes
        from logilab.astng.bases import InferenceContext, InferenceError

        # backport import bug fix (e642ba33ba1bdde04ac9f0c75a25dc40131c55e7)
        def ancestors(self, recurs=True, context=None):
            yielded = set([self])
            if context is None:
                context = InferenceContext()
            for stmt in self.bases:
                path = set(context.path)
                try:
                    for baseobj in stmt.infer(context):
                        if not isinstance(baseobj, logilab.astng.scoped_nodes.Class):
                            # duh ?
                            continue
                        if baseobj in yielded:
                            continue # cf xxx above
                        yielded.add(baseobj)
                        yield baseobj
                        if recurs:
                            for grandpa in baseobj.ancestors(True, context):
                                if grandpa in yielded:
                                    continue # cf xxx above
                                yielded.add(grandpa)
                                yield grandpa
                except InferenceError:
                    # XXX log error ?
                    pass
                context.path = path
        logilab.astng.scoped_nodes.Class.ancestors = ancestors

        # support for classpropery (d110bcf2de4b8bc48e41638cf430f17c5714ffbc)
        try:
            from logilab.astng.rebuilder import TreeRebuilder
        except:
            try:
                from logilab.astng._nodes_ast import TreeRebuilder
            except:
                from logilab.astng._nodes_compiler import TreeRebuilder
        from logilab.astng import nodes

        orig_visit_function = TreeRebuilder.visit_function
        def visit_function(self, node, parent):
            newnode = orig_visit_function(self, node, parent)
            if newnode.decorators is not None:
                for decorator_expr in newnode.decorators.nodes:
                    if isinstance(decorator_expr, nodes.Name):
                        if decorator_expr.name == 'classproperty':
                            newnode.type = 'classmethod'
            return newnode
        TreeRebuilder.visit_function = visit_function

    if astng_version < '0.22':
        from logilab.astng import nodes
        from logilab.astng.bases import _infer_stmts, copy_context, path_wrapper, \
            InferenceError, NotFoundError
        from logilab.astng._exceptions import ASTNGBuildingException
        import logilab.astng.scoped_nodes
        from logilab.astng.node_classes import List, DelName

        # backport of 11886551cfdcf969f0a661f8ab63c1fa1a6dd399 with
        # a bit revert of af896e299ce5e381a928a77a9c28941cad90a243
        def infer_from(self, context=None, asname=True):
            name = context.lookupname
            if name is None:
                raise InferenceError()
            if asname:
                name = self.real_name(name)
            module = self.do_import_module(self.modname)
            try:
                context = copy_context(context)
                context.lookupname = name
                return _infer_stmts(module.getattr(name, ignore_locals=module is self.root()), context)
            except NotFoundError:
                raise InferenceError(name)
        nodes.From.infer = path_wrapper(infer_from)

        def getattr(self, name, context=None, ignore_locals=False):
            if name in self.special_attributes:
                if name == '__file__':
                    return [cf(self.file)] + self.locals.get(name, [])
                if name == '__path__' and self.package:
                    return [List()] + self.locals.get(name, [])
                return std_special_attributes(self, name)
            if not ignore_locals and name in self.locals:
                return self.locals[name]
            if self.package:
                try:
                    return [self.import_module(name, relative_only=True)]
                except (KeyboardInterrupt, SystemExit):
                    raise
                except:
                    pass
            raise NotFoundError(name)
        logilab.astng.scoped_nodes.Module.getattr = logilab.astng.scoped_nodes.remove_nodes(getattr, DelName)

    if astng_version < '0.21.1':
        # backport of 3d463da455e33e7ddc53a295b6a33db7b9e4288b
        from logilab.astng.scoped_nodes import Function
        from logilab.astng.rebuilder import RebuildVisitor
        from logilab.astng.bases import YES, Instance

        orig_init = Function.__init__
        def init(self, name, doc):
            orig_init(self, name, doc)
            self.instance_attrs = {}
        Function.__init__ = init

        orig_getattr = Function.getattr
        def getattr(self, name, context=None):
            if name != '__module__' and name in self.instance_attrs:
                return self.instance_attrs[name]
            return orig_getattr(self, name, context)
        Function.getattr = getattr

        def delayed_assattr(self, node):
            """visit a AssAttr node -> add name to locals, handle members
            definition
            """
            try:
                frame = node.frame()
                for infered in node.expr.infer():
                    if infered is YES:
                        continue
                    try:
                        if infered.__class__ is Instance:
                            infered = infered._proxied
                            iattrs = infered.instance_attrs
                        elif isinstance(infered, Instance):
                            # Const, Tuple, ... we may be wrong, may be not, but
                            # anyway we don't want to pollute builtin's namespace
                            continue
                        elif infered.is_function:
                            iattrs = infered.instance_attrs
                        else:
                            iattrs = infered.locals
                    except AttributeError:
                        # XXX log error
                        #import traceback
                        #traceback.print_exc()
                        continue
                    values = iattrs.setdefault(node.attrname, [])
                    if node in values:
                        continue
                    # get assign in __init__ first XXX useful ?
                    if frame.name == '__init__' and values and not \
                           values[0].frame().name == '__init__':
                        values.insert(0, node)
                    else:
                        values.append(node)
            except InferenceError:
                pass
        RebuildVisitor.delayed_assattr = delayed_assattr

    if astng_version < '0.20.4':
        try:
            from logilab.astng._nodes_ast import TreeRebuilder, _lineno_parent
        except:
            from logilab.astng._nodes_compiler import TreeRebuilder
            _lineno_parent = (lambda *args: TreeRebuilder._set_infos(None, *args))
        from logilab.astng import nodes
        from logilab.astng.bases import NodeNG, Instance
        from logilab.astng.mixins import ParentAssignTypeMixin

        class Set(NodeNG, Instance, ParentAssignTypeMixin):
            _astng_fields = ('elts',)
            elts = None

            def pytype(self):
                return '__builtin__.set'

            def itered(self):
                return self.elts

        def visit_set(self, node, parent):
            newnode = Set()
            _lineno_parent(node, newnode, parent)
            newnode.elts = [self.visit(child, newnode) for child in node.elts]
            newnode.set_line_info(newnode.last_child())
            return newnode
        TreeRebuilder.visit_set = visit_set

        def visit_setcomp(self, node, parent):
            newnode = nodes.SetComp()
            _lineno_parent(node, newnode, parent)
            newnode.elt = self.visit(node.elt, newnode)
            newnode.generators = [self.visit(child, newnode)
                                  for child in node.generators]
            newnode.set_line_info(newnode.last_child())
            return newnode
        TreeRebuilder.visit_setcomp = visit_setcomp

        class DictComp(NodeNG):
            _astng_fields = ('key', 'value', 'generators')
            key = None
            value = None
            generators = None

        def visit_dictcomp(self, node, parent):
            newnode = DictComp()
            _lineno_parent(node, newnode, parent)
            newnode.key = self.visit(node.key, newnode)
            newnode.value = self.visit(node.value, newnode)
            newnode.generators = [self.visit(child, newnode)
                                  for child in node.generators]
            newnode.set_line_info(newnode.last_child())
            return newnode
        TreeRebuilder.visit_dictcomp = visit_dictcomp

        # backport of bfe9e5c53cfb75c3b45ebb5cb8e8902464782c7d
        from logilab.astng.node_classes import From
        orig_from_init = From.__init__
        def from_init(self,  fromname, names, level=0):
            orig_from_init(self, fromname or '', names, level)
        From.__init__ = from_init

        # partial backport of 6d59ad07d722d01e458aaf8fd14fd7dfc7ebaa6e
        from logilab.astng.scoped_nodes import Module
        orig_absolute_modname = Module.absolute_modname
        def absolute_modname(self, modname, level):
            result = orig_absolute_modname(self, modname, level)
            if result[-1] == '.':
                return result[:-1]
            return result
        Module.absolute_modname = absolute_modname

        # python2.4 compatibility (no super on old-style classes)
        from logilab.astng.bases import Proxy, UnboundMethod

        def unbound_igetattr(self, name, context=None):
            if name == 'im_func':
                return iter((self._proxied,))
            return Proxy.igetattr(self, name, context)
        UnboundMethod.igetattr = unbound_igetattr

        def unbound_getattr(self, name, context=None):
            if name == 'im_func':
                return [self._proxied]
            return Proxy.getattr(self, name, context)
        UnboundMethod.getattr = unbound_getattr