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): |
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] |