264
283
self.messages.append(messageClass(self.filename, *args, **kwargs))
266
285
def handleChildren(self, tree):
267
for node in tree.getChildNodes():
286
for node in iter_child_nodes(tree):
268
287
self.handleNode(node, tree)
289
def isDocstring(self, node):
291
Determine if the given node is a docstring, as long as it is at the
292
correct place in the node tree.
294
return isinstance(node, _ast.Str) or \
295
(isinstance(node, _ast.Expr) and
296
isinstance(node.value, _ast.Str))
270
298
def handleNode(self, node, parent):
271
299
node.parent = parent
272
300
if self.traceTree:
273
301
print ' ' * self.nodeDepth + node.__class__.__name__
274
302
self.nodeDepth += 1
303
if self.futuresAllowed and not \
304
(isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):
305
self.futuresAllowed = False
275
306
nodeType = node.__class__.__name__.upper()
276
if nodeType not in ('STMT', 'FROM'):
277
self.futuresAllowed = False
279
308
handler = getattr(self, nodeType)
286
315
def ignore(self, node):
289
STMT = PRINT = PRINTNL = TUPLE = LIST = ASSTUPLE = ASSATTR = \
290
ASSLIST = GETATTR = SLICE = SLICEOBJ = IF = CALLFUNC = DISCARD = \
291
RETURN = ADD = MOD = SUB = NOT = UNARYSUB = INVERT = ASSERT = COMPARE = \
292
SUBSCRIPT = AND = OR = TRYEXCEPT = RAISE = YIELD = DICT = LEFTSHIFT = \
293
RIGHTSHIFT = KEYWORD = TRYFINALLY = WHILE = EXEC = MUL = DIV = POWER = \
294
FLOORDIV = BITAND = BITOR = BITXOR = LISTCOMPFOR = LISTCOMPIF = \
295
AUGASSIGN = BACKQUOTE = UNARYADD = GENEXPR = GENEXPRFOR = GENEXPRIF = \
296
IFEXP = handleChildren
298
CONST = PASS = CONTINUE = BREAK = ELLIPSIS = ignore
319
RETURN = DELETE = PRINT = WHILE = IF = WITH = RAISE = TRYEXCEPT = \
320
TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren
322
CONTINUE = BREAK = PASS = ignore
325
BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = COMPARE = \
326
CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = handleChildren
328
NUM = STR = ELLIPSIS = ignore
331
SLICE = EXTSLICE = INDEX = handleChildren
333
# expression contexts are node instances too, though being constants
334
LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
337
AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
338
BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
339
EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
341
# additional node types
342
COMPREHENSION = EXCEPTHANDLER = KEYWORD = handleChildren
300
344
def addBinding(self, lineno, value, reportRedef=True):
301
345
'''Called when a binding is altered.
356
382
self.scope.globals.update(dict.fromkeys(node.names))
358
384
def LISTCOMP(self, node):
359
for qual in node.quals:
360
self.handleNode(qual, node)
361
self.handleNode(node.expr, node)
363
GENEXPRINNER = LISTCOMP
385
# handle generators before element
386
for gen in node.generators:
387
self.handleNode(gen, node)
388
self.handleNode(node.elt, node)
390
GENERATOREXP = SETCOMP = LISTCOMP
392
# dictionary comprehensions; introduced in Python 2.7
393
def DICTCOMP(self, node):
394
for gen in node.generators:
395
self.handleNode(gen, node)
396
self.handleNode(node.key, node)
397
self.handleNode(node.value, node)
365
399
def FOR(self, node):
387
423
def NAME(self, node):
389
Locate the name in locals / function / globals scopes.
425
Handle occurrence of Name (which can be a load/store/delete access.)
392
importStarred = self.scope.importStarred
394
self.scope[node.name].used = (self.scope, node.lineno)
400
# try enclosing function scopes
402
for scope in self.scopeStack[-2:0:-1]:
403
importStarred = importStarred or scope.importStarred
404
if not isinstance(scope, FunctionScope):
427
# Locate the name in locals / function / globals scopes.
428
if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):
430
importStarred = self.scope.importStarred
407
scope[node.name].used = (self.scope, node.lineno)
432
self.scope[node.id].used = (self.scope, node.lineno)
438
# try enclosing function scopes
415
importStarred = importStarred or self.scopeStack[0].importStarred
417
self.scopeStack[0][node.name].used = (self.scope, node.lineno)
419
if ((not hasattr(__builtin__, node.name))
420
and node.name not in _MAGIC_GLOBALS
421
and not importStarred):
422
if (os.path.basename(self.filename) == '__init__.py' and
423
node.name == '__path__'):
424
# the special name __path__ is valid only in packages
440
for scope in self.scopeStack[-2:0:-1]:
441
importStarred = importStarred or scope.importStarred
442
if not isinstance(scope, FunctionScope):
445
scope[node.id].used = (self.scope, node.lineno)
427
self.report(messages.UndefinedName, node.lineno, node.name)
430
def FUNCTION(self, node):
431
if getattr(node, "decorators", None) is not None:
432
self.handleChildren(node.decorators)
453
importStarred = importStarred or self.scopeStack[0].importStarred
455
self.scopeStack[0][node.id].used = (self.scope, node.lineno)
457
if ((not hasattr(__builtin__, node.id))
458
and node.id not in _MAGIC_GLOBALS
459
and not importStarred):
460
if (os.path.basename(self.filename) == '__init__.py' and
461
node.id == '__path__'):
462
# the special name __path__ is valid only in packages
465
self.report(messages.UndefinedName, node.lineno, node.id)
466
elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
467
# if the name hasn't already been defined in the current scope
468
if isinstance(self.scope, FunctionScope) and node.id not in self.scope:
469
# for each function or module scope above us
470
for scope in self.scopeStack[:-1]:
471
if not isinstance(scope, (FunctionScope, ModuleScope)):
473
# if the name was defined in that scope, and the name has
474
# been accessed already in the current scope, and hasn't
475
# been declared global
477
and scope[node.id].used
478
and scope[node.id].used[0] is self.scope
479
and node.id not in self.scope.globals):
480
# then it's probably a mistake
481
self.report(messages.UndefinedLocal,
482
scope[node.id].used[1],
484
scope[node.id].source.lineno)
487
if isinstance(node.parent,
488
(_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
489
binding = Binding(node.id, node)
490
elif (node.id == '__all__' and
491
isinstance(self.scope, ModuleScope)):
492
binding = ExportBinding(node.id, node.parent.value)
494
binding = Assignment(node.id, node)
495
if node.id in self.scope:
496
binding.used = self.scope[node.id].used
497
self.addBinding(node.lineno, binding)
498
elif isinstance(node.ctx, _ast.Del):
499
if isinstance(self.scope, FunctionScope) and \
500
node.id in self.scope.globals:
501
del self.scope.globals[node.id]
503
self.addBinding(node.lineno, UnBinding(node.id, node))
505
# must be a Param context -- this only happens for names in function
506
# arguments, but these aren't dispatched through here
508
"Got impossible expression context: %r" % (node.ctx,))
511
def FUNCTIONDEF(self, node):
512
# the decorators attribute is called decorator_list as of Python 2.6
513
if hasattr(node, 'decorators'):
514
for deco in node.decorators:
515
self.handleNode(deco, node)
517
for deco in node.decorator_list:
518
self.handleNode(deco, node)
433
519
self.addBinding(node.lineno, FunctionDefinition(node.name, node))
434
520
self.LAMBDA(node)
436
522
def LAMBDA(self, node):
437
for default in node.defaults:
523
for default in node.args.defaults:
438
524
self.handleNode(default, node)
440
526
def runFunction():
443
529
def addArgs(arglist):
444
530
for arg in arglist:
445
if isinstance(arg, tuple):
531
if isinstance(arg, _ast.Tuple):
449
self.report(messages.DuplicateArgument, node.lineno, arg)
535
self.report(messages.DuplicateArgument,
452
539
self.pushFunctionScope()
453
addArgs(node.argnames)
540
addArgs(node.args.args)
541
# vararg/kwarg identifiers are not Name nodes
543
args.append(node.args.vararg)
545
args.append(node.args.kwarg)
454
546
for name in args:
455
547
self.addBinding(node.lineno, Argument(name, node), reportRedef=False)
456
self.handleNode(node.code, node)
548
if isinstance(node.body, list):
549
# case for FunctionDefs
550
for stmt in node.body:
551
self.handleNode(stmt, node)
554
self.handleNode(node.body, node)
457
555
def checkUnusedAssignments():
459
557
Check to see if any assignments have not been used.
469
567
self.deferFunction(runFunction)
472
def CLASS(self, node):
570
def CLASSDEF(self, node):
474
572
Check names used in a class definition, including its decorators, base
475
573
classes, and the body of its definition. Additionally, add its name to
476
574
the current scope.
478
if getattr(node, "decorators", None) is not None:
479
self.handleChildren(node.decorators)
576
# decorator_list is present as of Python 2.6
577
for deco in getattr(node, 'decorator_list', []):
578
self.handleNode(deco, node)
480
579
for baseNode in node.bases:
481
580
self.handleNode(baseNode, node)
482
581
self.pushClassScope()
483
self.handleChildren(node.code)
582
for stmt in node.body:
583
self.handleNode(stmt, node)
485
585
self.addBinding(node.lineno, Binding(node.name, node))
488
def ASSNAME(self, node):
489
if node.flags == 'OP_DELETE':
490
if isinstance(self.scope, FunctionScope) and node.name in self.scope.globals:
491
del self.scope.globals[node.name]
493
self.addBinding(node.lineno, UnBinding(node.name, node))
495
# if the name hasn't already been defined in the current scope
496
if isinstance(self.scope, FunctionScope) and node.name not in self.scope:
497
# for each function or module scope above us
498
for scope in self.scopeStack[:-1]:
499
if not isinstance(scope, (FunctionScope, ModuleScope)):
501
# if the name was defined in that scope, and the name has
502
# been accessed already in the current scope, and hasn't
503
# been declared global
504
if (node.name in scope
505
and scope[node.name].used
506
and scope[node.name].used[0] is self.scope
507
and node.name not in self.scope.globals):
508
# then it's probably a mistake
509
self.report(messages.UndefinedLocal,
510
scope[node.name].used[1],
512
scope[node.name].source.lineno)
515
if isinstance(node.parent,
516
(ast.For, ast.ListCompFor, ast.GenExprFor,
517
ast.AssTuple, ast.AssList)):
518
binding = Binding(node.name, node)
519
elif (node.name == '__all__' and
520
isinstance(self.scope, ModuleScope) and
521
isinstance(node.parent, ast.Assign)):
522
binding = ExportBinding(node.name, node.parent.expr)
524
binding = Assignment(node.name, node)
525
if node.name in self.scope:
526
binding.used = self.scope[node.name].used
527
self.addBinding(node.lineno, binding)
529
587
def ASSIGN(self, node):
530
self.handleNode(node.expr, node)
531
for subnode in node.nodes[::-1]:
532
self.handleNode(subnode, node)
588
self.handleNode(node.value, node)
589
for target in node.targets:
590
self.handleNode(target, node)
592
def AUGASSIGN(self, node):
593
# AugAssign is awkward: must set the context explicitly and visit twice,
594
# once with AugLoad context, once with AugStore context
595
node.target.ctx = _ast.AugLoad()
596
self.handleNode(node.target, node)
597
self.handleNode(node.value, node)
598
node.target.ctx = _ast.AugStore()
599
self.handleNode(node.target, node)
534
601
def IMPORT(self, node):
535
for name, alias in node.names:
602
for alias in node.names:
603
name = alias.asname or alias.name
537
604
importation = Importation(name, node)
538
605
self.addBinding(node.lineno, importation)
540
def FROM(self, node):
541
if node.modname == '__future__':
607
def IMPORTFROM(self, node):
608
if node.module == '__future__':
542
609
if not self.futuresAllowed:
543
self.report(messages.LateFutureImport, node.lineno, [n[0] for n in node.names])
610
self.report(messages.LateFutureImport, node.lineno,
611
[n.name for n in node.names])
545
613
self.futuresAllowed = False
547
for name, alias in node.names:
615
for alias in node.names:
616
if alias.name == '*':
549
617
self.scope.importStarred = True
550
self.report(messages.ImportStarUsed, node.lineno, node.modname)
618
self.report(messages.ImportStarUsed, node.lineno, node.module)
620
name = alias.asname or alias.name
553
621
importation = Importation(name, node)
554
if node.modname == '__future__':
622
if node.module == '__future__':
555
623
importation.used = (self.scope, node.lineno)
556
624
self.addBinding(node.lineno, importation)