Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / checkers / variables.py @ 745

History | View | Annotate | Download (50.5 KB)

1
# Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE).
2
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
#
4
# This program is free software; you can redistribute it and/or modify it under
5
# the terms of the GNU General Public License as published by the Free Software
6
# Foundation; either version 2 of the License, or (at your option) any later
7
# version.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License along with
14
# this program; if not, write to the Free Software Foundation, Inc.,
15
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
"""variables checkers for Python code
17
"""
18
import os
19
import sys
20
import re
21
from copy import copy
22

    
23
import six
24

    
25
import astroid
26
from astroid import modutils
27
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH
28
from pylint.utils import get_global_option
29
from pylint.checkers import BaseChecker
30
from pylint.checkers.utils import (
31
    PYMETHODS, is_ancestor_name, is_builtin,
32
    is_defined_before, is_error, is_func_default, is_func_decorator,
33
    assign_parent, check_messages, is_inside_except, clobber_in_except,
34
    get_all_elements, has_known_bases, node_ignores_exception,
35
    is_inside_abstract_class, is_comprehension, is_iterable,
36
    safe_infer)
37

    
38
SPECIAL_OBJ = re.compile("^_{2}[a-z]+_{2}$")
39
FUTURE = '__future__'
40
PY3K = sys.version_info >= (3, 0)
41

    
42

    
43
def _is_from_future_import(stmt, name):
44
    """Check if the name is a future import from another module."""
45
    try:
46
        module = stmt.do_import_module(stmt.modname)
47
    except astroid.InferenceError:
48
        return
49

    
50
    for local_node in module.locals.get(name, []):
51
        if (isinstance(local_node, astroid.ImportFrom)
52
                and local_node.modname == FUTURE):
53
            return True
54

    
55

    
56
def in_for_else_branch(parent, stmt):
57
    """Returns True if stmt in inside the else branch for a parent For stmt."""
58
    return (isinstance(parent, astroid.For) and
59
            any(else_stmt.parent_of(stmt) for else_stmt in parent.orelse))
60

    
61
def overridden_method(klass, name):
62
    """get overridden method if any"""
63
    try:
64
        parent = next(klass.local_attr_ancestors(name))
65
    except (StopIteration, KeyError):
66
        return None
67
    try:
68
        meth_node = parent[name]
69
    except KeyError:
70
        # We have found an ancestor defining <name> but it's not in the local
71
        # dictionary. This may happen with astroid built from living objects.
72
        return None
73
    if isinstance(meth_node, astroid.FunctionDef):
74
        return meth_node
75
    return None
76

    
77
def _get_unpacking_extra_info(node, infered):
78
    """return extra information to add to the message for unpacking-non-sequence
79
    and unbalanced-tuple-unpacking errors
80
    """
81
    more = ''
82
    infered_module = infered.root().name
83
    if node.root().name == infered_module:
84
        if node.lineno == infered.lineno:
85
            more = ' %s' % infered.as_string()
86
        elif infered.lineno:
87
            more = ' defined at line %s' % infered.lineno
88
    elif infered.lineno:
89
        more = ' defined at line %s of %s' % (infered.lineno, infered_module)
90
    return more
91

    
92
def _detect_global_scope(node, frame, defframe):
93
    """ Detect that the given frames shares a global
94
    scope.
95

96
    Two frames shares a global scope when neither
97
    of them are hidden under a function scope, as well
98
    as any of parent scope of them, until the root scope.
99
    In this case, depending from something defined later on
100
    will not work, because it is still undefined.
101

102
    Example:
103
        class A:
104
            # B has the same global scope as `C`, leading to a NameError.
105
            class B(C): ...
106
        class C: ...
107

108
    """
109
    def_scope = scope = None
110
    if frame and frame.parent:
111
        scope = frame.parent.scope()
112
    if defframe and defframe.parent:
113
        def_scope = defframe.parent.scope()
114
    if isinstance(frame, astroid.FunctionDef):
115
        # If the parent of the current node is a
116
        # function, then it can be under its scope
117
        # (defined in, which doesn't concern us) or
118
        # the `->` part of annotations. The same goes
119
        # for annotations of function arguments, they'll have
120
        # their parent the Arguments node.
121
        if not isinstance(node.parent,
122
                          (astroid.FunctionDef, astroid.Arguments)):
123
            return False
124
    elif any(not isinstance(f, (astroid.ClassDef, astroid.Module))
125
             for f in (frame, defframe)):
126
        # Not interested in other frames, since they are already
127
        # not in a global scope.
128
        return False
129

    
130
    break_scopes = []
131
    for s in (scope, def_scope):
132
        # Look for parent scopes. If there is anything different
133
        # than a module or a class scope, then they frames don't
134
        # share a global scope.
135
        parent_scope = s
136
        while parent_scope:
137
            if not isinstance(parent_scope, (astroid.ClassDef, astroid.Module)):
138
                break_scopes.append(parent_scope)
139
                break
140
            if parent_scope.parent:
141
                parent_scope = parent_scope.parent.scope()
142
            else:
143
                break
144
    if break_scopes and len(set(break_scopes)) != 1:
145
        # Store different scopes than expected.
146
        # If the stored scopes are, in fact, the very same, then it means
147
        # that the two frames (frame and defframe) shares the same scope,
148
        # and we could apply our lineno analysis over them.
149
        # For instance, this works when they are inside a function, the node
150
        # that uses a definition and the definition itself.
151
        return False
152
    # At this point, we are certain that frame and defframe shares a scope
153
    # and the definition of the first depends on the second.
154
    return frame.lineno < defframe.lineno
155

    
156
def _fix_dot_imports(not_consumed):
157
    """ Try to fix imports with multiple dots, by returning a dictionary
158
    with the import names expanded. The function unflattens root imports,
159
    like 'xml' (when we have both 'xml.etree' and 'xml.sax'), to 'xml.etree'
160
    and 'xml.sax' respectively.
161
    """
162
    # TODO: this should be improved in issue astroid #46
163
    names = {}
164
    for name, stmts in six.iteritems(not_consumed):
165
        if any(isinstance(stmt, astroid.AssignName)
166
               and isinstance(stmt.assign_type(), astroid.AugAssign)
167
               for stmt in stmts):
168
            continue
169
        for stmt in stmts:
170
            if not isinstance(stmt, (astroid.ImportFrom, astroid.Import)):
171
                continue
172
            for imports in stmt.names:
173
                second_name = None
174
                if imports[0] == "*":
175
                    # In case of wildcard imports,
176
                    # pick the name from inside the imported module.
177
                    second_name = name
178
                else:
179
                    if imports[0].find(".") > -1 or name in imports:
180
                        # Most likely something like 'xml.etree',
181
                        # which will appear in the .locals as 'xml'.
182
                        # Only pick the name if it wasn't consumed.
183
                        second_name = imports[0]
184
                if second_name and second_name not in names:
185
                    names[second_name] = stmt
186
    return sorted(names.items(), key=lambda a: a[1].fromlineno)
187

    
188
def _find_frame_imports(name, frame):
189
    """
190
    Detect imports in the frame, with the required
191
    *name*. Such imports can be considered assignments.
192
    Returns True if an import for the given name was found.
193
    """
194
    imports = frame.nodes_of_class((astroid.Import, astroid.ImportFrom))
195
    for import_node in imports:
196
        for import_name, import_alias in import_node.names:
197
            # If the import uses an alias, check only that.
198
            # Otherwise, check only the import name.
199
            if import_alias:
200
                if import_alias == name:
201
                    return True
202
            elif import_name and import_name == name:
203
                return True
204

    
205

    
206
MSGS = {
207
    'E0601': ('Using variable %r before assignment',
208
              'used-before-assignment',
209
              'Used when a local variable is accessed before it\'s \
210
              assignment.'),
211
    'E0602': ('Undefined variable %r',
212
              'undefined-variable',
213
              'Used when an undefined variable is accessed.'),
214
    'E0603': ('Undefined variable name %r in __all__',
215
              'undefined-all-variable',
216
              'Used when an undefined variable name is referenced in __all__.'),
217
    'E0604': ('Invalid object %r in __all__, must contain only strings',
218
              'invalid-all-object',
219
              'Used when an invalid (non-string) object occurs in __all__.'),
220
    'E0611': ('No name %r in module %r',
221
              'no-name-in-module',
222
              'Used when a name cannot be found in a module.'),
223

    
224
    'W0601': ('Global variable %r undefined at the module level',
225
              'global-variable-undefined',
226
              'Used when a variable is defined through the "global" statement \
227
              but the variable is not defined in the module scope.'),
228
    'W0602': ('Using global for %r but no assignment is done',
229
              'global-variable-not-assigned',
230
              'Used when a variable is defined through the "global" statement \
231
              but no assignment to this variable is done.'),
232
    'W0603': ('Using the global statement', # W0121
233
              'global-statement',
234
              'Used when you use the "global" statement to update a global \
235
              variable. Pylint just try to discourage this \
236
              usage. That doesn\'t mean you can not use it !'),
237
    'W0604': ('Using the global statement at the module level', # W0103
238
              'global-at-module-level',
239
              'Used when you use the "global" statement at the module level \
240
              since it has no effect'),
241
    'W0611': ('Unused %s',
242
              'unused-import',
243
              'Used when an imported module or variable is not used.'),
244
    'W0612': ('Unused variable %r',
245
              'unused-variable',
246
              'Used when a variable is defined but not used.'),
247
    'W0613': ('Unused argument %r',
248
              'unused-argument',
249
              'Used when a function or method argument is not used.'),
250
    'W0614': ('Unused import %s from wildcard import',
251
              'unused-wildcard-import',
252
              'Used when an imported module or variable is not used from a \
253
              `\'from X import *\'` style import.'),
254

    
255
    'W0621': ('Redefining name %r from outer scope (line %s)',
256
              'redefined-outer-name',
257
              'Used when a variable\'s name hide a name defined in the outer \
258
              scope.'),
259
    'W0622': ('Redefining built-in %r',
260
              'redefined-builtin',
261
              'Used when a variable or function override a built-in.'),
262
    'W0623': ('Redefining name %r from %s in exception handler',
263
              'redefine-in-handler',
264
              'Used when an exception handler assigns the exception \
265
               to an existing name'),
266

    
267
    'W0631': ('Using possibly undefined loop variable %r',
268
              'undefined-loop-variable',
269
              'Used when an loop variable (i.e. defined by a for loop or \
270
              a list comprehension or a generator expression) is used outside \
271
              the loop.'),
272

    
273
    'E0632': ('Possible unbalanced tuple unpacking with '
274
              'sequence%s: '
275
              'left side has %d label(s), right side has %d value(s)',
276
              'unbalanced-tuple-unpacking',
277
              'Used when there is an unbalanced tuple unpacking in assignment',
278
              {'old_names': [('W0632', 'unbalanced-tuple-unpacking')]}),
279

    
280
    'E0633': ('Attempting to unpack a non-sequence%s',
281
              'unpacking-non-sequence',
282
              'Used when something which is not '
283
              'a sequence is used in an unpack assignment',
284
              {'old_names': [('W0633', 'unpacking-non-sequence')]}),
285

    
286
    'W0640': ('Cell variable %s defined in loop',
287
              'cell-var-from-loop',
288
              'A variable used in a closure is defined in a loop. '
289
              'This will result in all closures using the same value for '
290
              'the closed-over variable.'),
291

    
292
    }
293

    
294
class VariablesChecker(BaseChecker):
295
    """checks for
296
    * unused variables / imports
297
    * undefined variables
298
    * redefinition of variable from builtins or from an outer scope
299
    * use of variable before assignment
300
    * __all__ consistency
301
    """
302

    
303
    __implements__ = IAstroidChecker
304

    
305
    name = 'variables'
306
    msgs = MSGS
307
    priority = -1
308
    options = (("init-import",
309
                {'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
310
                 'help' : 'Tells whether we should check for unused import in \
311
__init__ files.'}),
312
               ("dummy-variables-rgx",
313
                {'default': ('_$|dummy'),
314
                 'type' :'regexp', 'metavar' : '<regexp>',
315
                 'help' : 'A regular expression matching the name of dummy \
316
variables (i.e. expectedly not used).'}),
317
               ("additional-builtins",
318
                {'default': (), 'type' : 'csv',
319
                 'metavar' : '<comma separated list>',
320
                 'help' : 'List of additional names supposed to be defined in \
321
builtins. Remember that you should avoid to define new builtins when possible.'
322
                }),
323
               ("callbacks",
324
                {'default' : ('cb_', '_cb'), 'type' : 'csv',
325
                 'metavar' : '<callbacks>',
326
                 'help' : 'List of strings which can identify a callback '
327
                          'function by name. A callback name must start or '
328
                          'end with one of those strings.'}
329
               )
330
              )
331
    def __init__(self, linter=None):
332
        BaseChecker.__init__(self, linter)
333
        self._to_consume = None  # list of tuples: (to_consume:dict, consumed:dict, scope_type:str)
334
        self._checking_mod_attr = None
335

    
336
    def visit_module(self, node):
337
        """visit module : update consumption analysis variable
338
        checks globals doesn't overrides builtins
339
        """
340
        self._to_consume = [(copy(node.locals), {}, 'module')]
341
        for name, stmts in six.iteritems(node.locals):
342
            if is_builtin(name) and not is_inside_except(stmts[0]):
343
                # do not print Redefining builtin for additional builtins
344
                self.add_message('redefined-builtin', args=name, node=stmts[0])
345

    
346
    @check_messages('unused-import', 'unused-wildcard-import',
347
                    'redefined-builtin', 'undefined-all-variable',
348
                    'invalid-all-object')
349
    def leave_module(self, node):
350
        """leave module: check globals
351
        """
352
        assert len(self._to_consume) == 1
353
        not_consumed = self._to_consume.pop()[0]
354
        # attempt to check for __all__ if defined
355
        if '__all__' in node.locals:
356
            self._check_all(node, not_consumed)
357
        # don't check unused imports in __init__ files
358
        if not self.config.init_import and node.package:
359
            return
360

    
361
        self._check_imports(not_consumed)
362

    
363
    def _check_all(self, node, not_consumed):
364
        assigned = next(node.igetattr('__all__'))
365
        if assigned is astroid.YES:
366
            return
367

    
368
        for elt in getattr(assigned, 'elts', ()):
369
            try:
370
                elt_name = next(elt.infer())
371
            except astroid.InferenceError:
372
                continue
373
            if elt_name is astroid.YES:
374
                continue
375

    
376
            if (not isinstance(elt_name, astroid.Const)
377
                    or not isinstance(elt_name.value, six.string_types)):
378
                self.add_message('invalid-all-object',
379
                                 args=elt.as_string(), node=elt)
380
                continue
381

    
382
            elt_name = elt_name.value
383
            # If elt is in not_consumed, remove it from not_consumed
384
            if elt_name in not_consumed:
385
                del not_consumed[elt_name]
386
                continue
387

    
388
            if elt_name not in node.locals:
389
                if not node.package:
390
                    self.add_message('undefined-all-variable',
391
                                     args=(elt_name, ),
392
                                     node=elt)
393
                else:
394
                    basename = os.path.splitext(node.file)[0]
395
                    if os.path.basename(basename) == '__init__':
396
                        name = node.name + "." + elt_name
397
                        try:
398
                            modutils.file_from_modpath(name.split("."))
399
                        except ImportError:
400
                            self.add_message('undefined-all-variable',
401
                                             args=(elt_name, ),
402
                                             node=elt)
403
                        except SyntaxError:
404
                            # don't yield an syntax-error warning,
405
                            # because it will be later yielded
406
                            # when the file will be checked
407
                            pass
408

    
409
    def _check_imports(self, not_consumed):
410
        local_names = _fix_dot_imports(not_consumed)
411
        checked = set()
412
        for name, stmt in local_names:
413
            for imports in stmt.names:
414
                real_name = imported_name = imports[0]
415
                if imported_name == "*":
416
                    real_name = name
417
                as_name = imports[1]
418
                if real_name in checked:
419
                    continue
420
                if name not in (real_name, as_name):
421
                    continue
422
                checked.add(real_name)
423

    
424
                if (isinstance(stmt, astroid.Import) or
425
                        (isinstance(stmt, astroid.ImportFrom) and
426
                         not stmt.modname)):
427
                    if (isinstance(stmt, astroid.ImportFrom) and
428
                            SPECIAL_OBJ.search(imported_name)):
429
                        # Filter special objects (__doc__, __all__) etc.,
430
                        # because they can be imported for exporting.
431
                        continue
432
                    if as_name is None:
433
                        msg = "import %s" % imported_name
434
                    else:
435
                        msg = "%s imported as %s" % (imported_name, as_name)
436
                    self.add_message('unused-import', args=msg, node=stmt)
437
                elif (isinstance(stmt, astroid.ImportFrom)
438
                      and stmt.modname != FUTURE):
439

    
440
                    if SPECIAL_OBJ.search(imported_name):
441
                        # Filter special objects (__doc__, __all__) etc.,
442
                        # because they can be imported for exporting.
443
                        continue
444

    
445
                    if _is_from_future_import(stmt, name):
446
                        # Check if the name is in fact loaded from a
447
                        # __future__ import in another module.
448
                        continue
449

    
450
                    if imported_name == '*':
451
                        self.add_message('unused-wildcard-import',
452
                                         args=name, node=stmt)
453
                    else:
454
                        if as_name is None:
455
                            msg = "%s imported from %s" % (imported_name, stmt.modname)
456
                        else:
457
                            fields = (imported_name, stmt.modname, as_name)
458
                            msg = "%s imported from %s as %s" % fields
459
                        self.add_message('unused-import', args=msg, node=stmt)
460
        del self._to_consume
461

    
462
    def visit_classdef(self, node):
463
        """visit class: update consumption analysis variable
464
        """
465
        self._to_consume.append((copy(node.locals), {}, 'class'))
466

    
467
    def leave_classdef(self, _):
468
        """leave class: update consumption analysis variable
469
        """
470
        # do not check for not used locals here (no sense)
471
        self._to_consume.pop()
472

    
473
    def visit_lambda(self, node):
474
        """visit lambda: update consumption analysis variable
475
        """
476
        self._to_consume.append((copy(node.locals), {}, 'lambda'))
477

    
478
    def leave_lambda(self, _):
479
        """leave lambda: update consumption analysis variable
480
        """
481
        # do not check for not used locals here
482
        self._to_consume.pop()
483

    
484
    def visit_generatorexp(self, node):
485
        """visit genexpr: update consumption analysis variable
486
        """
487
        self._to_consume.append((copy(node.locals), {}, 'comprehension'))
488

    
489
    def leave_generatorexp(self, _):
490
        """leave genexpr: update consumption analysis variable
491
        """
492
        # do not check for not used locals here
493
        self._to_consume.pop()
494

    
495
    def visit_dictcomp(self, node):
496
        """visit dictcomp: update consumption analysis variable
497
        """
498
        self._to_consume.append((copy(node.locals), {}, 'comprehension'))
499

    
500
    def leave_dictcomp(self, _):
501
        """leave dictcomp: update consumption analysis variable
502
        """
503
        # do not check for not used locals here
504
        self._to_consume.pop()
505

    
506
    def visit_setcomp(self, node):
507
        """visit setcomp: update consumption analysis variable
508
        """
509
        self._to_consume.append((copy(node.locals), {}, 'comprehension'))
510

    
511
    def leave_setcomp(self, _):
512
        """leave setcomp: update consumption analysis variable
513
        """
514
        # do not check for not used locals here
515
        self._to_consume.pop()
516

    
517
    def visit_functiondef(self, node):
518
        """visit function: update consumption analysis variable and check locals
519
        """
520
        self._to_consume.append((copy(node.locals), {}, 'function'))
521
        if not (self.linter.is_message_enabled('redefined-outer-name') or
522
                self.linter.is_message_enabled('redefined-builtin')):
523
            return
524
        globs = node.root().globals
525
        for name, stmt in node.items():
526
            if is_inside_except(stmt):
527
                continue
528
            if name in globs and not isinstance(stmt, astroid.Global):
529
                definition = globs[name][0]
530
                if (isinstance(definition, astroid.ImportFrom)
531
                        and definition.modname == FUTURE):
532
                    # It is a __future__ directive, not a symbol.
533
                    continue
534

    
535
                line = definition.fromlineno
536
                dummy_rgx = self.config.dummy_variables_rgx
537
                if not dummy_rgx.match(name):
538
                    self.add_message('redefined-outer-name',
539
                                     args=(name, line), node=stmt)
540
            elif is_builtin(name):
541
                # do not print Redefining builtin for additional builtins
542
                self.add_message('redefined-builtin', args=name, node=stmt)
543

    
544
    def leave_functiondef(self, node):
545
        """leave function: check function's locals are consumed"""
546
        not_consumed = self._to_consume.pop()[0]
547
        if not (self.linter.is_message_enabled('unused-variable') or
548
                self.linter.is_message_enabled('unused-argument')):
549
            return
550
        # don't check arguments of function which are only raising an exception
551
        if is_error(node):
552
            return
553
        # don't check arguments of abstract methods or within an interface
554
        is_method = node.is_method()
555
        klass = node.parent.frame()
556
        if is_method and node.is_abstract():
557
            return
558
        if is_method and isinstance(klass, astroid.ClassDef):
559
            confidence = INFERENCE if has_known_bases(klass) else INFERENCE_FAILURE
560
        else:
561
            confidence = HIGH
562
        authorized_rgx = self.config.dummy_variables_rgx
563
        called_overridden = False
564
        argnames = node.argnames()
565
        global_names = set()
566
        nonlocal_names = set()
567
        for global_stmt in node.nodes_of_class(astroid.Global):
568
            global_names.update(set(global_stmt.names))
569
        for nonlocal_stmt in node.nodes_of_class(astroid.Nonlocal):
570
            nonlocal_names.update(set(nonlocal_stmt.names))
571

    
572
        for name, stmts in six.iteritems(not_consumed):
573
            # ignore some special names specified by user configuration
574
            if authorized_rgx.match(name):
575
                continue
576
            # ignore names imported by the global statement
577
            # FIXME: should only ignore them if it's assigned latter
578
            stmt = stmts[0]
579
            if isinstance(stmt, astroid.Global):
580
                continue
581
            if isinstance(stmt, (astroid.Import, astroid.ImportFrom)):
582
                # Detect imports, assigned to global statements.
583
                if not global_names:
584
                    continue
585
                skip = False
586
                for import_name, import_alias in stmt.names:
587
                    # If the import uses an alias, check only that.
588
                    # Otherwise, check only the import name.
589
                    if import_alias:
590
                        if import_alias in global_names:
591
                            skip = True
592
                            break
593
                    elif import_name in global_names:
594
                        skip = True
595
                        break
596
                if skip:
597
                    continue
598

    
599
            # care about functions with unknown argument (builtins)
600
            if name in argnames:
601
                if is_method:
602
                    # don't warn for the first argument of a (non static) method
603
                    if node.type != 'staticmethod' and name == argnames[0]:
604
                        continue
605
                    # don't warn for argument of an overridden method
606
                    if not called_overridden:
607
                        overridden = overridden_method(klass, node.name)
608
                        called_overridden = True
609
                    if overridden is not None and name in overridden.argnames():
610
                        continue
611
                    if node.name in PYMETHODS and node.name not in ('__init__', '__new__'):
612
                        continue
613
                # don't check callback arguments
614
                if any(node.name.startswith(cb) or node.name.endswith(cb)
615
                       for cb in self.config.callbacks):
616
                    continue
617
                self.add_message('unused-argument', args=name, node=stmt,
618
                                 confidence=confidence)
619
            else:
620
                if stmt.parent and isinstance(stmt.parent, astroid.Assign):
621
                    if name in nonlocal_names:
622
                        continue
623
                self.add_message('unused-variable', args=name, node=stmt)
624

    
625
    visit_asyncfunctiondef = visit_functiondef
626
    leave_asyncfunctiondef = leave_functiondef
627

    
628
    @check_messages('global-variable-undefined', 'global-variable-not-assigned',
629
                    'global-statement', 'global-at-module-level',
630
                    'redefined-builtin')
631
    def visit_global(self, node):
632
        """check names imported exists in the global scope"""
633
        frame = node.frame()
634
        if isinstance(frame, astroid.Module):
635
            self.add_message('global-at-module-level', node=node)
636
            return
637
        module = frame.root()
638
        default_message = True
639
        for name in node.names:
640
            try:
641
                assign_nodes = module.getattr(name)
642
            except astroid.NotFoundError:
643
                # unassigned global, skip
644
                assign_nodes = []
645
            for anode in assign_nodes:
646
                if anode.parent is None:
647
                    # node returned for builtin attribute such as __file__,
648
                    # __doc__, etc...
649
                    continue
650
                if anode.frame() is frame:
651
                    # same scope level assignment
652
                    break
653
            else:
654
                if not _find_frame_imports(name, frame):
655
                    self.add_message('global-variable-not-assigned',
656
                                     args=name, node=node)
657
                default_message = False
658
            if not assign_nodes:
659
                continue
660
            for anode in assign_nodes:
661
                if anode.parent is None:
662
                    self.add_message('redefined-builtin', args=name, node=node)
663
                    break
664
                if anode.frame() is module:
665
                    # module level assignment
666
                    break
667
            else:
668
                # global undefined at the module scope
669
                self.add_message('global-variable-undefined', args=name, node=node)
670
                default_message = False
671
        if default_message:
672
            self.add_message('global-statement', node=node)
673

    
674
    def _check_late_binding_closure(self, node, assignment_node):
675
        def _is_direct_lambda_call():
676
            return (isinstance(node_scope.parent, astroid.Call)
677
                    and node_scope.parent.func is node_scope)
678

    
679
        node_scope = node.scope()
680
        if not isinstance(node_scope, (astroid.Lambda, astroid.FunctionDef)):
681
            return
682
        if isinstance(node.parent, astroid.Arguments):
683
            return
684

    
685
        if isinstance(assignment_node, astroid.Comprehension):
686
            if assignment_node.parent.parent_of(node.scope()):
687
                self.add_message('cell-var-from-loop', node=node, args=node.name)
688
        else:
689
            assign_scope = assignment_node.scope()
690
            maybe_for = assignment_node
691
            while not isinstance(maybe_for, astroid.For):
692
                if maybe_for is assign_scope:
693
                    break
694
                maybe_for = maybe_for.parent
695
            else:
696
                if (maybe_for.parent_of(node_scope)
697
                        and not _is_direct_lambda_call()
698
                        and not isinstance(node_scope.statement(), astroid.Return)):
699
                    self.add_message('cell-var-from-loop', node=node, args=node.name)
700

    
701
    def _loopvar_name(self, node, name):
702
        # filter variables according to node's scope
703
        # XXX used to filter parents but don't remember why, and removing this
704
        # fixes a W0631 false positive reported by Paul Hachmann on 2008/12 on
705
        # python-projects (added to func_use_for_or_listcomp_var test)
706
        #astmts = [stmt for stmt in node.lookup(name)[1]
707
        #          if hasattr(stmt, 'ass_type')] and
708
        #          not stmt.statement().parent_of(node)]
709
        if not self.linter.is_message_enabled('undefined-loop-variable'):
710
            return
711
        astmts = [stmt for stmt in node.lookup(name)[1]
712
                  if hasattr(stmt, 'ass_type')]
713
        # filter variables according their respective scope test is_statement
714
        # and parent to avoid #74747. This is not a total fix, which would
715
        # introduce a mechanism similar to special attribute lookup in
716
        # modules. Also, in order to get correct inference in this case, the
717
        # scope lookup rules would need to be changed to return the initial
718
        # assignment (which does not exist in code per se) as well as any later
719
        # modifications.
720
        if not astmts or (astmts[0].is_statement or astmts[0].parent) \
721
             and astmts[0].statement().parent_of(node):
722
            _astmts = []
723
        else:
724
            _astmts = astmts[:1]
725
        for i, stmt in enumerate(astmts[1:]):
726
            if (astmts[i].statement().parent_of(stmt)
727
                    and not in_for_else_branch(astmts[i].statement(), stmt)):
728
                continue
729
            _astmts.append(stmt)
730
        astmts = _astmts
731
        if len(astmts) == 1:
732
            assign = astmts[0].assign_type()
733
            if (isinstance(assign, (astroid.For, astroid.Comprehension,
734
                                    astroid.GeneratorExp))
735
                    and assign.statement() is not node.statement()):
736
                self.add_message('undefined-loop-variable', args=name, node=node)
737

    
738
    @check_messages('redefine-in-handler')
739
    def visit_excepthandler(self, node):
740
        for name in get_all_elements(node.name):
741
            clobbering, args = clobber_in_except(name)
742
            if clobbering:
743
                self.add_message('redefine-in-handler', args=args, node=name)
744

    
745
    def visit_assignname(self, node):
746
        if isinstance(node.assign_type(), astroid.AugAssign):
747
            self.visit_name(node)
748

    
749
    def visit_delname(self, node):
750
        self.visit_name(node)
751

    
752
    @staticmethod
753
    def _defined_in_function_definition(node, frame):
754
        in_annotation_or_default = False
755
        if (isinstance(frame, astroid.FunctionDef) and
756
                node.statement() is frame):
757
            in_annotation_or_default = (
758
                (
759
                    PY3K and (node in frame.args.annotations
760
                              or node is frame.args.varargannotation
761
                              or node is frame.args.kwargannotation)
762
                )
763
                or
764
                frame.args.parent_of(node)
765
            )
766
        return in_annotation_or_default
767

    
768
    @staticmethod
769
    def _next_to_consume(node, name, to_consume):
770
        # mark the name as consumed if it's defined in this scope
771
        found_node = to_consume.get(name)
772
        if (found_node
773
                and isinstance(node.parent, astroid.Assign)
774
                and node.parent == found_node[0].parent):
775
            lhs = found_node[0].parent.targets[0]
776
            if lhs.name == name: # this name is defined in this very statement
777
                found_node = None
778
        return found_node
779

    
780
    @staticmethod
781
    def _is_variable_violation(node, name, defnode, stmt, defstmt,
782
                               frame, defframe, base_scope_type,
783
                               recursive_klass):
784
        maybee0601 = True
785
        annotation_return = False
786
        if frame is not defframe:
787
            maybee0601 = _detect_global_scope(node, frame, defframe)
788
        elif defframe.parent is None:
789
            # we are at the module level, check the name is not
790
            # defined in builtins
791
            if name in defframe.scope_attrs or astroid.builtin_lookup(name)[1]:
792
                maybee0601 = False
793
        else:
794
            # we are in a local scope, check the name is not
795
            # defined in global or builtin scope
796
            if defframe.root().lookup(name)[1]:
797
                maybee0601 = False
798
            else:
799
                # check if we have a nonlocal
800
                if name in defframe.locals:
801
                    maybee0601 = not any(isinstance(child, astroid.Nonlocal)
802
                                         and name in child.names
803
                                         for child in defframe.get_children())
804

    
805
        if (base_scope_type == 'lambda' and
806
                isinstance(frame, astroid.ClassDef)
807
                and name in frame.locals):
808

    
809
            # This rule verifies that if the definition node of the
810
            # checked name is an Arguments node and if the name
811
            # is used a default value in the arguments defaults
812
            # and the actual definition of the variable label
813
            # is happening before the Arguments definition.
814
            #
815
            # bar = None
816
            # foo = lambda bar=bar: bar
817
            #
818
            # In this case, maybee0601 should be False, otherwise
819
            # it should be True.
820
            maybee0601 = not (isinstance(defnode, astroid.Arguments) and
821
                              node in defnode.defaults and
822
                              frame.locals[name][0].fromlineno < defstmt.fromlineno)
823
        elif (isinstance(defframe, astroid.ClassDef) and
824
              isinstance(frame, astroid.FunctionDef)):
825
            # Special rule for function return annotations,
826
            # which uses the same name as the class where
827
            # the function lives.
828
            if (PY3K and node is frame.returns and
829
                    defframe.parent_of(frame.returns)):
830
                maybee0601 = annotation_return = True
831

    
832
            if (maybee0601 and defframe.name in defframe.locals and
833
                    defframe.locals[name][0].lineno < frame.lineno):
834
                # Detect class assignments with the same
835
                # name as the class. In this case, no warning
836
                # should be raised.
837
                maybee0601 = False
838
            if isinstance(node.parent, astroid.Arguments):
839
                maybee0601 = stmt.fromlineno <= defstmt.fromlineno
840
        elif recursive_klass:
841
            maybee0601 = True
842
        else:
843
            maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.fromlineno
844
        return maybee0601, annotation_return
845

    
846
    def _ignore_class_scope(self, node, name, frame):
847
        # Detect if we are in a local class scope, as an assignment.
848
        # For example, the following is fair game.
849
        #
850
        # class A:
851
        #    b = 1
852
        #    c = lambda b=b: b * b
853
        #
854
        # class B:
855
        #    tp = 1
856
        #    def func(self, arg: tp):
857
        #        ...
858
        # class C:
859
        #    tp = 2
860
        #    def func(self, arg=tp):
861
        #        ...
862

    
863
        in_annotation_or_default = self._defined_in_function_definition(
864
            node, frame)
865
        if in_annotation_or_default:
866
            frame_locals = frame.parent.scope().locals
867
        else:
868
            frame_locals = frame.locals
869
        return not ((isinstance(frame, astroid.ClassDef) or
870
                     in_annotation_or_default) and
871
                    name in frame_locals)
872

    
873
    @check_messages(*(MSGS.keys()))
874
    def visit_name(self, node):
875
        """check that a name is defined if the current scope and doesn't
876
        redefine a built-in
877
        """
878
        stmt = node.statement()
879
        if stmt.fromlineno is None:
880
            # name node from a astroid built from live code, skip
881
            assert not stmt.root().file.endswith('.py')
882
            return
883
        name = node.name
884
        frame = stmt.scope()
885
        # if the name node is used as a function default argument's value or as
886
        # a decorator, then start from the parent frame of the function instead
887
        # of the function frame - and thus open an inner class scope
888
        if (is_func_default(node) or is_func_decorator(node)
889
                or is_ancestor_name(frame, node)):
890
            start_index = len(self._to_consume) - 2
891
        else:
892
            start_index = len(self._to_consume) - 1
893
        # iterates through parent scopes, from the inner to the outer
894
        base_scope_type = self._to_consume[start_index][-1]
895
        # pylint: disable=too-many-nested-blocks; refactoring this block is a pain.
896
        for i in range(start_index, -1, -1):
897
            to_consume, consumed, scope_type = self._to_consume[i]
898
            # if the current scope is a class scope but it's not the inner
899
            # scope, ignore it. This prevents to access this scope instead of
900
            # the globals one in function members when there are some common
901
            # names. The only exception is when the starting scope is a
902
            # comprehension and its direct outer scope is a class
903
            if scope_type == 'class' and i != start_index and not (
904
                    base_scope_type == 'comprehension' and i == start_index-1):
905
                if self._ignore_class_scope(node, name, frame):
906
                    continue
907

    
908
            # the name has already been consumed, only check it's not a loop
909
            # variable used outside the loop
910
            if name in consumed:
911
                defnode = assign_parent(consumed[name][0])
912
                self._check_late_binding_closure(node, defnode)
913
                self._loopvar_name(node, name)
914
                break
915
            found_node = self._next_to_consume(node, name, to_consume)
916
            if found_node:
917
                consumed[name] = found_node
918
            else:
919
                continue
920
            # checks for use before assignment
921
            defnode = assign_parent(to_consume[name][0])
922
            if defnode is not None:
923
                self._check_late_binding_closure(node, defnode)
924
                defstmt = defnode.statement()
925
                defframe = defstmt.frame()
926
                # The class reuses itself in the class scope.
927
                recursive_klass = (frame is defframe and
928
                                   defframe.parent_of(node) and
929
                                   isinstance(defframe, astroid.ClassDef) and
930
                                   node.name == defframe.name)
931

    
932
                maybee0601, annotation_return = self._is_variable_violation(
933
                    node, name, defnode, stmt, defstmt,
934
                    frame, defframe,
935
                    base_scope_type, recursive_klass)
936

    
937
                if (maybee0601
938
                        and not is_defined_before(node)
939
                        and not astroid.are_exclusive(stmt, defstmt, ('NameError',
940
                                                                      'Exception',
941
                                                                      'BaseException'))):
942

    
943
                    # Used and defined in the same place, e.g `x += 1` and `del x`
944
                    defined_by_stmt = (
945
                        defstmt is stmt
946
                        and isinstance(node, (astroid.DelName, astroid.AssignName))
947
                    )
948

    
949
                    if (recursive_klass
950
                            or defined_by_stmt
951
                            or annotation_return
952
                            or isinstance(defstmt, astroid.Delete)):
953
                        if not node_ignores_exception(node, NameError):
954
                            self.add_message('undefined-variable', args=name,
955
                                             node=node)
956
                    elif base_scope_type != 'lambda':
957
                        # E0601 may *not* occurs in lambda scope.
958
                        self.add_message('used-before-assignment', args=name, node=node)
959
                    elif base_scope_type == 'lambda':
960
                        # E0601 can occur in class-level scope in lambdas, as in
961
                        # the following example:
962
                        #   class A:
963
                        #      x = lambda attr: f + attr
964
                        #      f = 42
965
                        if isinstance(frame, astroid.ClassDef) and name in frame.locals:
966
                            if isinstance(node.parent, astroid.Arguments):
967
                                if stmt.fromlineno <= defstmt.fromlineno:
968
                                    # Doing the following is fine:
969
                                    #   class A:
970
                                    #      x = 42
971
                                    #      y = lambda attr=x: attr
972
                                    self.add_message('used-before-assignment',
973
                                                     args=name, node=node)
974
                            else:
975
                                self.add_message('undefined-variable',
976
                                                 args=name, node=node)
977
                        elif scope_type == 'lambda':
978
                            self.add_message('undefined-variable',
979
                                             node=node, args=name)
980

    
981
            del to_consume[name]
982
            # check it's not a loop variable used outside the loop
983
            self._loopvar_name(node, name)
984
            break
985
        else:
986
            # we have not found the name, if it isn't a builtin, that's an
987
            # undefined name !
988
            if not (name in astroid.Module.scope_attrs or is_builtin(name)
989
                    or name in self.config.additional_builtins):
990
                if not node_ignores_exception(node, NameError):
991
                    self.add_message('undefined-variable', args=name, node=node)
992

    
993
    @check_messages('no-name-in-module')
994
    def visit_import(self, node):
995
        """check modules attribute accesses"""
996
        if node_ignores_exception(node, ImportError):
997
            # No need to verify this, since ImportError is already
998
            # handled by the client code.
999
            return
1000

    
1001
        for name, _ in node.names:
1002
            parts = name.split('.')
1003
            try:
1004
                module = next(node.infer_name_module(parts[0]))
1005
            except astroid.ResolveError:
1006
                continue
1007
            self._check_module_attrs(node, module, parts[1:])
1008

    
1009
    @check_messages('no-name-in-module')
1010
    def visit_importfrom(self, node):
1011
        """check modules attribute accesses"""
1012
        if node_ignores_exception(node, ImportError):
1013
            # No need to verify this, since ImportError is already
1014
            # handled by the client code.
1015
            return
1016

    
1017
        name_parts = node.modname.split('.')
1018
        try:
1019
            module = node.do_import_module(name_parts[0])
1020
        except Exception:
1021
            return
1022
        module = self._check_module_attrs(node, module, name_parts[1:])
1023
        if not module:
1024
            return
1025
        for name, _ in node.names:
1026
            if name == '*':
1027
                continue
1028
            self._check_module_attrs(node, module, name.split('.'))
1029

    
1030
    @check_messages('unbalanced-tuple-unpacking', 'unpacking-non-sequence')
1031
    def visit_assign(self, node):
1032
        """Check unbalanced tuple unpacking for assignments
1033
        and unpacking non-sequences.
1034
        """
1035
        if not isinstance(node.targets[0], (astroid.Tuple, astroid.List)):
1036
            return
1037

    
1038
        targets = node.targets[0].itered()
1039
        try:
1040
            infered = safe_infer(node.value)
1041
            if infered is not None:
1042
                self._check_unpacking(infered, node, targets)
1043
        except astroid.InferenceError:
1044
            return
1045

    
1046
    def _check_unpacking(self, infered, node, targets):
1047
        """ Check for unbalanced tuple unpacking
1048
        and unpacking non sequences.
1049
        """
1050
        if is_inside_abstract_class(node):
1051
            return
1052
        if is_comprehension(node):
1053
            return
1054
        if infered is astroid.YES:
1055
            return
1056
        if (isinstance(infered.parent, astroid.Arguments) and
1057
                isinstance(node.value, astroid.Name) and
1058
                node.value.name == infered.parent.vararg):
1059
            # Variable-length argument, we can't determine the length.
1060
            return
1061
        if isinstance(infered, (astroid.Tuple, astroid.List)):
1062
            # attempt to check unpacking is properly balanced
1063
            values = infered.itered()
1064
            if len(targets) != len(values):
1065
                # Check if we have starred nodes.
1066
                if any(isinstance(target, astroid.Starred)
1067
                       for target in targets):
1068
                    return
1069
                self.add_message('unbalanced-tuple-unpacking', node=node,
1070
                                 args=(_get_unpacking_extra_info(node, infered),
1071
                                       len(targets),
1072
                                       len(values)))
1073
        # attempt to check unpacking may be possible (ie RHS is iterable)
1074
        else:
1075
            if not is_iterable(infered):
1076
                self.add_message('unpacking-non-sequence', node=node,
1077
                                 args=(_get_unpacking_extra_info(node, infered),))
1078

    
1079

    
1080
    def _check_module_attrs(self, node, module, module_names):
1081
        """check that module_names (list of string) are accessible through the
1082
        given module
1083
        if the latest access name corresponds to a module, return it
1084
        """
1085
        assert isinstance(module, astroid.Module), module
1086
        ignored_modules = get_global_option(self, 'ignored-modules',
1087
                                            default=[])
1088
        while module_names:
1089
            name = module_names.pop(0)
1090
            if name == '__dict__':
1091
                module = None
1092
                break
1093
            try:
1094
                module = next(module.getattr(name)[0].infer())
1095
                if module is astroid.YES:
1096
                    return None
1097
            except astroid.NotFoundError:
1098
                if module.name in ignored_modules:
1099
                    return None
1100
                self.add_message('no-name-in-module',
1101
                                 args=(name, module.name), node=node)
1102
                return None
1103
            except astroid.InferenceError:
1104
                return None
1105
        if module_names:
1106
            # FIXME: other message if name is not the latest part of
1107
            # module_names ?
1108
            modname = module and module.name or '__dict__'
1109
            self.add_message('no-name-in-module', node=node,
1110
                             args=('.'.join(module_names), modname))
1111
            return None
1112
        if isinstance(module, astroid.Module):
1113
            return module
1114
        return None
1115

    
1116

    
1117
class VariablesChecker3k(VariablesChecker):
1118
    '''Modified variables checker for 3k'''
1119
    # listcomp have now also their scope
1120

    
1121
    def visit_listcomp(self, node):
1122
        """visit dictcomp: update consumption analysis variable
1123
        """
1124
        self._to_consume.append((copy(node.locals), {}, 'comprehension'))
1125

    
1126
    def leave_listcomp(self, _):
1127
        """leave dictcomp: update consumption analysis variable
1128
        """
1129
        # do not check for not used locals here
1130
        self._to_consume.pop()
1131

    
1132
    def leave_module(self, node):
1133
        """ Update consumption analysis variable
1134
        for metaclasses.
1135
        """
1136
        module_locals = self._to_consume[0][0]
1137
        module_imports = self._to_consume[0][1]
1138
        consumed = {}
1139

    
1140
        for klass in node.nodes_of_class(astroid.ClassDef):
1141
            found = metaclass = name = None
1142
            if not klass._metaclass:
1143
                # Skip if this class doesn't use
1144
                # explictly a metaclass, but inherits it from ancestors
1145
                continue
1146

    
1147
            metaclass = klass.metaclass()
1148

    
1149
            # Look the name in the already found locals.
1150
            # If it's not found there, look in the module locals
1151
            # and in the imported modules.
1152
            if isinstance(klass._metaclass, astroid.Name):
1153
                name = klass._metaclass.name
1154
            elif metaclass:
1155
                # if it uses a `metaclass=module.Class`
1156
                name = metaclass.root().name
1157

    
1158
            if name:
1159
                found = consumed.setdefault(
1160
                    name, module_locals.get(name, module_imports.get(name)))
1161

    
1162
            if found is None and not metaclass:
1163
                name = None
1164
                if isinstance(klass._metaclass, astroid.Name):
1165
                    name = klass._metaclass.name
1166
                elif isinstance(klass._metaclass, astroid.Attribute):
1167
                    name = klass._metaclass.as_string()
1168

    
1169
                if name is not None:
1170
                    if not (name in astroid.Module.scope_attrs or
1171
                            is_builtin(name) or
1172
                            name in self.config.additional_builtins or
1173
                            name in node.locals):
1174
                        self.add_message('undefined-variable',
1175
                                         node=klass,
1176
                                         args=(name, ))
1177
        # Pop the consumed items, in order to
1178
        # avoid having unused-import false positives
1179
        for name in consumed:
1180
            module_locals.pop(name, None)
1181
        super(VariablesChecker3k, self).leave_module(node)
1182

    
1183
if sys.version_info >= (3, 0):
1184
    VariablesChecker = VariablesChecker3k
1185

    
1186

    
1187
def register(linter):
1188
    """required method to auto register this checker"""
1189
    linter.register_checker(VariablesChecker(linter))