UtilitiesPython2/py2flakes/checker.py

changeset 945
8cd4d08fa9f6
parent 802
e8882d16384c
child 1509
c0b5e693b0eb
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
12 import compiler 12 import compiler
13 from compiler import ast 13 from compiler import ast
14 14
15 from py2flakes import messages 15 from py2flakes import messages
16 16
17
17 class Binding(object): 18 class Binding(object):
18 """ 19 """
19 Represents the binding of a value to a name. 20 Represents the binding of a value to a name.
20 21
21 The checker uses this to keep track of which names have been bound and 22 The checker uses this to keep track of which names have been bound and
35 self.__class__.__name__, 36 self.__class__.__name__,
36 self.name, 37 self.name,
37 self.source.lineno, 38 self.source.lineno,
38 id(self)) 39 id(self))
39 40
41
40 class UnBinding(Binding): 42 class UnBinding(Binding):
41 ''' 43 '''
42 Created by the 'del' operator. 44 Created by the 'del' operator.
43 ''' 45 '''
44 46
47
45 class Importation(Binding): 48 class Importation(Binding):
46 """ 49 """
47 A binding created by an import statement. 50 A binding created by an import statement.
48 """ 51 """
49 def __init__(self, name, source): 52 def __init__(self, name, source):
50 self.fullName = name 53 self.fullName = name
51 name = name.split('.')[0] 54 name = name.split('.')[0]
52 super(Importation, self).__init__(name, source) 55 super(Importation, self).__init__(name, source)
53 56
57
54 class Argument(Binding): 58 class Argument(Binding):
55 """ 59 """
56 Represents binding a name as an argument. 60 Represents binding a name as an argument.
57 """ 61 """
62
58 63
59 class Assignment(Binding): 64 class Assignment(Binding):
60 """ 65 """
61 Represents binding a name with an explicit assignment. 66 Represents binding a name with an explicit assignment.
62 67
63 The checker will raise warnings for any Assignment that isn't used. Also, 68 The checker will raise warnings for any Assignment that isn't used. Also,
64 the checker does not consider assignments in tuple/list unpacking to be 69 the checker does not consider assignments in tuple/list unpacking to be
65 Assignments, rather it treats them as simple Bindings. 70 Assignments, rather it treats them as simple Bindings.
66 """ 71 """
67 72
73
68 class FunctionDefinition(Binding): 74 class FunctionDefinition(Binding):
69 """ 75 """
70 Represents a function definition. 76 Represents a function definition.
71 """ 77 """
72 pass 78 pass
79
73 80
74 class ExportBinding(Binding): 81 class ExportBinding(Binding):
75 """ 82 """
76 A binding created by an __all__ assignment. If the names in the list 83 A binding created by an __all__ assignment. If the names in the list
77 can be determined statically, they will be treated as names for export and 84 can be determined statically, they will be treated as names for export and
94 for node in self.source.nodes: 101 for node in self.source.nodes:
95 if isinstance(node, ast.Const): 102 if isinstance(node, ast.Const):
96 names.append(node.value) 103 names.append(node.value)
97 return names 104 return names
98 105
106
99 class Scope(dict): 107 class Scope(dict):
100 """ 108 """
101 Class defining the scope base class. 109 Class defining the scope base class.
102 """ 110 """
103 importStarred = False # set to True when import * is found 111 importStarred = False # set to True when import * is found
106 return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self)) 114 return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self))
107 115
108 def __init__(self): 116 def __init__(self):
109 super(Scope, self).__init__() 117 super(Scope, self).__init__()
110 118
119
111 class ClassScope(Scope): 120 class ClassScope(Scope):
112 """ 121 """
113 Class representing a name scope for a class. 122 Class representing a name scope for a class.
114 """ 123 """
115 pass 124 pass
125
116 126
117 class FunctionScope(Scope): 127 class FunctionScope(Scope):
118 """ 128 """
119 Class representing a name scope for a function. 129 Class representing a name scope for a function.
120 """ 130 """
121 def __init__(self): 131 def __init__(self):
122 super(FunctionScope, self).__init__() 132 super(FunctionScope, self).__init__()
123 self.globals = {} 133 self.globals = {}
124 134
135
125 class ModuleScope(Scope): 136 class ModuleScope(Scope):
126 """ 137 """
127 Class representing a name scope for a module. 138 Class representing a name scope for a module.
128 """ 139 """
129 pass 140 pass
130 141
131 # Globally defined names which are not attributes of the __builtin__ module. 142 # Globally defined names which are not attributes of the __builtin__ module.
132 _MAGIC_GLOBALS = ['__file__', '__builtins__'] 143 _MAGIC_GLOBALS = ['__file__', '__builtins__']
144
133 145
134 class Checker(object): 146 class Checker(object):
135 """ 147 """
136 Class to check the cleanliness and sanity of Python code. 148 Class to check the cleanliness and sanity of Python code.
137 """ 149 """
321 if node.vars is not None: 333 if node.vars is not None:
322 self.handleNode(node.vars, node) 334 self.handleNode(node.vars, node)
323 335
324 self.handleChildren(node.body) 336 self.handleChildren(node.body)
325 337
326
327 def GLOBAL(self, node): 338 def GLOBAL(self, node):
328 """ 339 """
329 Keep track of globals declarations. 340 Keep track of globals declarations.
330 """ 341 """
331 if isinstance(self.scope, FunctionScope): 342 if isinstance(self.scope, FunctionScope):
341 def FOR(self, node): 352 def FOR(self, node):
342 """ 353 """
343 Process bindings for loop variables. 354 Process bindings for loop variables.
344 """ 355 """
345 vars = [] 356 vars = []
357
346 def collectLoopVars(n): 358 def collectLoopVars(n):
347 if hasattr(n, 'name'): 359 if hasattr(n, 'name'):
348 vars.append(n.name) 360 vars.append(n.name)
349 else: 361 else:
350 for c in n.getChildNodes(): 362 for c in n.getChildNodes():
400 # the special name __path__ is valid only in packages 412 # the special name __path__ is valid only in packages
401 pass 413 pass
402 else: 414 else:
403 self.report(messages.UndefinedName, node.lineno, node.name) 415 self.report(messages.UndefinedName, node.lineno, node.name)
404 416
405
406 def FUNCTION(self, node): 417 def FUNCTION(self, node):
407 if getattr(node, "decorators", None) is not None: 418 if getattr(node, "decorators", None) is not None:
408 self.handleChildren(node.decorators) 419 self.handleChildren(node.decorators)
409 self.addBinding(node.lineno, FunctionDefinition(node.name, node)) 420 self.addBinding(node.lineno, FunctionDefinition(node.name, node))
410 self.LAMBDA(node) 421 self.LAMBDA(node)
428 self.pushFunctionScope() 439 self.pushFunctionScope()
429 addArgs(node.argnames) 440 addArgs(node.argnames)
430 for name in args: 441 for name in args:
431 self.addBinding(node.lineno, Argument(name, node), reportRedef=False) 442 self.addBinding(node.lineno, Argument(name, node), reportRedef=False)
432 self.handleNode(node.code, node) 443 self.handleNode(node.code, node)
444
433 def checkUnusedAssignments(): 445 def checkUnusedAssignments():
434 """ 446 """
435 Check to see if any assignments have not been used. 447 Check to see if any assignments have not been used.
436 """ 448 """
437 for name, binding in self.scope.iteritems(): 449 for name, binding in self.scope.iteritems():
442 self.deferAssignment(checkUnusedAssignments) 454 self.deferAssignment(checkUnusedAssignments)
443 self.popScope() 455 self.popScope()
444 456
445 self.deferFunction(runFunction) 457 self.deferFunction(runFunction)
446 458
447
448 def CLASS(self, node): 459 def CLASS(self, node):
449 """ 460 """
450 Check names used in a class definition, including its decorators, base 461 Check names used in a class definition, including its decorators, base
451 classes, and the body of its definition. Additionally, add its name to 462 classes, and the body of its definition. Additionally, add its name to
452 the current scope. 463 the current scope.
457 self.handleNode(baseNode, node) 468 self.handleNode(baseNode, node)
458 self.addBinding(node.lineno, Binding(node.name, node)) 469 self.addBinding(node.lineno, Binding(node.name, node))
459 self.pushClassScope() 470 self.pushClassScope()
460 self.handleChildren(node.code) 471 self.handleChildren(node.code)
461 self.popScope() 472 self.popScope()
462
463 473
464 def ASSNAME(self, node): 474 def ASSNAME(self, node):
465 if node.flags == 'OP_DELETE': 475 if node.flags == 'OP_DELETE':
466 if isinstance(self.scope, FunctionScope) and node.name in self.scope.globals: 476 if isinstance(self.scope, FunctionScope) and node.name in self.scope.globals:
467 del self.scope.globals[node.name] 477 del self.scope.globals[node.name]

eric ide

mercurial