Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(342)

Side by Side Diff: third_party/pylint/checkers/classes.py

Issue 719313003: Revert "pylint: upgrade to 1.3.1" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/pylint/checkers/base.py ('k') | third_party/pylint/checkers/design_analysis.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # 3 #
4 # This program is free software; you can redistribute it and/or modify it under 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 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 6 # Foundation; either version 2 of the License, or (at your option) any later
7 # version. 7 # version.
8 # 8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT 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 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. 11 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 # 12 #
13 # You should have received a copy of the GNU General Public License along with 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., 14 # this program; if not, write to the Free Software Foundation, Inc.,
15 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 15 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 """classes checker for Python code 16 """classes checker for Python code
17 """ 17 """
18 from __future__ import generators 18 from __future__ import generators
19 19
20 import sys 20 from logilab import astng
21 from logilab.astng import YES, Instance, are_exclusive
21 22
22 import astroid 23 from pylint.interfaces import IASTNGChecker
23 from astroid import YES, Instance, are_exclusive, AssAttr, Class
24 from astroid.bases import Generator
25
26 from pylint.interfaces import IAstroidChecker
27 from pylint.checkers import BaseChecker 24 from pylint.checkers import BaseChecker
28 from pylint.checkers.utils import ( 25 from pylint.checkers.utils import PYMETHODS, overrides_a_method, check_messages
29 PYMETHODS, overrides_a_method, check_messages, is_attr_private,
30 is_attr_protected, node_frame_class, safe_infer)
31
32 if sys.version_info >= (3, 0):
33 NEXT_METHOD = '__next__'
34 else:
35 NEXT_METHOD = 'next'
36 ITER_METHODS = ('__iter__', '__getitem__')
37 26
38 def class_is_abstract(node): 27 def class_is_abstract(node):
39 """return true if the given class node should be considered as an abstract 28 """return true if the given class node should be considered as an abstract
40 class 29 class
41 """ 30 """
42 for method in node.methods(): 31 for method in node.methods():
43 if method.parent.frame() is node: 32 if method.parent.frame() is node:
44 if method.is_abstract(pass_is_abstract=False): 33 if method.is_abstract(pass_is_abstract=False):
45 return True 34 return True
46 return False 35 return False
47 36
48 37
49 MSGS = { 38 MSGS = {
50 'F0202': ('Unable to check methods signature (%s / %s)', 39 'F0202': ('Unable to check methods signature (%s / %s)',
51 'method-check-failed',
52 'Used when PyLint has been unable to check methods signature \ 40 'Used when PyLint has been unable to check methods signature \
53 compatibility for an unexpected reason. Please report this kind \ 41 compatibility for an unexpected reason. Please report this kind \
54 if you don\'t make sense of it.'), 42 if you don\'t make sense of it.'),
55 43
56 'E0202': ('An attribute defined in %s line %s hides this method', 44 'E0202': ('An attribute affected in %s line %s hide this method',
57 'method-hidden',
58 'Used when a class defines a method which is hidden by an ' 45 'Used when a class defines a method which is hidden by an '
59 'instance attribute from an ancestor class or set by some ' 46 'instance attribute from an ancestor class or set by some '
60 'client code.'), 47 'client code.'),
61 'E0203': ('Access to member %r before its definition line %s', 48 'E0203': ('Access to member %r before its definition line %s',
62 'access-member-before-definition',
63 'Used when an instance member is accessed before it\'s actually\ 49 'Used when an instance member is accessed before it\'s actually\
64 assigned.'), 50 assigned.'),
65 'W0201': ('Attribute %r defined outside __init__', 51 'W0201': ('Attribute %r defined outside __init__',
66 'attribute-defined-outside-init',
67 'Used when an instance attribute is defined outside the __init__\ 52 'Used when an instance attribute is defined outside the __init__\
68 method.'), 53 method.'),
69 54
70 'W0212': ('Access to a protected member %s of a client class', # E0214 55 'W0212': ('Access to a protected member %s of a client class', # E0214
71 'protected-access',
72 'Used when a protected member (i.e. class member with a name \ 56 'Used when a protected member (i.e. class member with a name \
73 beginning with an underscore) is access outside the class or a \ 57 beginning with an underscore) is access outside the class or a \
74 descendant of the class where it\'s defined.'), 58 descendant of the class where it\'s defined.'),
75 59
76 'E0211': ('Method has no argument', 60 'E0211': ('Method has no argument',
77 'no-method-argument',
78 'Used when a method which should have the bound instance as \ 61 'Used when a method which should have the bound instance as \
79 first argument has no argument defined.'), 62 first argument has no argument defined.'),
80 'E0213': ('Method should have "self" as first argument', 63 'E0213': ('Method should have "self" as first argument',
81 'no-self-argument',
82 'Used when a method has an attribute different the "self" as\ 64 'Used when a method has an attribute different the "self" as\
83 first argument. This is considered as an error since this is\ 65 first argument. This is considered as an error since this is\
84 a so common convention that you shouldn\'t break it!'), 66 a so common convention that you shouldn\'t break it!'),
85 'C0202': ('Class method %s should have %s as first argument', # E0212 67 'C0202': ('Class method should have %s as first argument', # E0212
86 'bad-classmethod-argument', 68 'Used when a class method has an attribute different than "cls"\
87 'Used when a class method has a first argument named differently ' 69 as first argument, to easily differentiate them from regular \
88 'than the value specified in valid-classmethod-first-arg option ' 70 instance methods.'),
89 '(default to "cls"), recommended to easily differentiate them ' 71 'C0203': ('Metaclass method should have "mcs" as first argument', # E0214
90 'from regular instance methods.'), 72 'Used when a metaclass method has an attribute different the \
91 'C0203': ('Metaclass method %s should have %s as first argument', # E0214 73 "mcs" as first argument.'),
92 'bad-mcs-method-argument',
93 'Used when a metaclass method has a first agument named '
94 'differently than the value specified in valid-classmethod-first'
95 '-arg option (default to "cls"), recommended to easily '
96 'differentiate them from regular instance methods.'),
97 'C0204': ('Metaclass class method %s should have %s as first argument',
98 'bad-mcs-classmethod-argument',
99 'Used when a metaclass class method has a first argument named '
100 'differently than the value specified in valid-metaclass-'
101 'classmethod-first-arg option (default to "mcs"), recommended to '
102 'easily differentiate them from regular instance methods.'),
103 74
104 'W0211': ('Static method with %r as first argument', 75 'W0211': ('Static method with %r as first argument',
105 'bad-staticmethod-argument', 76 'Used when a static method has "self" or "cls" as first argument.'
106 'Used when a static method has "self" or a value specified in ' 77 ),
107 'valid-classmethod-first-arg option or '
108 'valid-metaclass-classmethod-first-arg option as first argument.'
109 ),
110 'R0201': ('Method could be a function', 78 'R0201': ('Method could be a function',
111 'no-self-use',
112 'Used when a method doesn\'t use its bound instance, and so could\ 79 'Used when a method doesn\'t use its bound instance, and so could\
113 be written as a function.' 80 be written as a function.'
114 ), 81 ),
115 82
116 'E0221': ('Interface resolved to %s is not a class', 83 'E0221': ('Interface resolved to %s is not a class',
117 'interface-is-not-class',
118 'Used when a class claims to implement an interface which is not \ 84 'Used when a class claims to implement an interface which is not \
119 a class.'), 85 a class.'),
120 'E0222': ('Missing method %r from %s interface', 86 'E0222': ('Missing method %r from %s interface',
121 'missing-interface-method',
122 'Used when a method declared in an interface is missing from a \ 87 'Used when a method declared in an interface is missing from a \
123 class implementing this interface'), 88 class implementing this interface'),
124 'W0221': ('Arguments number differs from %s method', 89 'W0221': ('Arguments number differs from %s method',
125 'arguments-differ',
126 'Used when a method has a different number of arguments than in \ 90 'Used when a method has a different number of arguments than in \
127 the implemented interface or in an overridden method.'), 91 the implemented interface or in an overridden method.'),
128 'W0222': ('Signature differs from %s method', 92 'W0222': ('Signature differs from %s method',
129 'signature-differs',
130 'Used when a method signature is different than in the \ 93 'Used when a method signature is different than in the \
131 implemented interface or in an overridden method.'), 94 implemented interface or in an overridden method.'),
132 'W0223': ('Method %r is abstract in class %r but is not overridden', 95 'W0223': ('Method %r is abstract in class %r but is not overridden',
133 'abstract-method',
134 'Used when an abstract method (i.e. raise NotImplementedError) is \ 96 'Used when an abstract method (i.e. raise NotImplementedError) is \
135 not overridden in concrete class.' 97 not overridden in concrete class.'
136 ), 98 ),
137 'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224 99 'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224
138 'unresolved-interface',
139 'Used when a PyLint as failed to find interfaces implemented by \ 100 'Used when a PyLint as failed to find interfaces implemented by \
140 a class'), 101 a class'),
141 102
142 103
143 'W0231': ('__init__ method from base class %r is not called', 104 'W0231': ('__init__ method from base class %r is not called',
144 'super-init-not-called',
145 'Used when an ancestor class method has an __init__ method \ 105 'Used when an ancestor class method has an __init__ method \
146 which is not called by a derived class.'), 106 which is not called by a derived class.'),
147 'W0232': ('Class has no __init__ method', 107 'W0232': ('Class has no __init__ method',
148 'no-init',
149 'Used when a class has no __init__ method, neither its parent \ 108 'Used when a class has no __init__ method, neither its parent \
150 classes.'), 109 classes.'),
151 'W0233': ('__init__ method from a non direct base class %r is called', 110 'W0233': ('__init__ method from a non direct base class %r is called',
152 'non-parent-init-called',
153 'Used when an __init__ method is called on a class which is not \ 111 'Used when an __init__ method is called on a class which is not \
154 in the direct ancestors for the analysed class.'), 112 in the direct ancestors for the analysed class.'),
155 'W0234': ('__iter__ returns non-iterator',
156 'non-iterator-returned',
157 'Used when an __iter__ method returns something which is not an \
158 iterable (i.e. has no `%s` method)' % NEXT_METHOD),
159 'E0235': ('__exit__ must accept 3 arguments: type, value, traceback',
160 'bad-context-manager',
161 'Used when the __exit__ special method, belonging to a \
162 context manager, does not accept 3 arguments \
163 (type, value, traceback).'),
164 'E0236': ('Invalid object %r in __slots__, must contain '
165 'only non empty strings',
166 'invalid-slots-object',
167 'Used when an invalid (non-string) object occurs in __slots__.'),
168 'E0237': ('Assigning to attribute %r not defined in class slots',
169 'assigning-non-slot',
170 'Used when assigning to an attribute not defined '
171 'in the class slots.'),
172 'E0238': ('Invalid __slots__ object',
173 'invalid-slots',
174 'Used when an invalid __slots__ is found in class. '
175 'Only a string, an iterable or a sequence is permitted.')
176
177 113
178 } 114 }
179 115
180 116
181 class ClassChecker(BaseChecker): 117 class ClassChecker(BaseChecker):
182 """checks for : 118 """checks for :
183 * methods without self as first argument 119 * methods without self as first argument
184 * overridden methods signature 120 * overridden methods signature
185 * access only to existent members via self 121 * access only to existent members via self
186 * attributes not defined in the __init__ method 122 * attributes not defined in the __init__ method
187 * supported interfaces implementation 123 * supported interfaces implementation
188 * unreachable code 124 * unreachable code
189 """ 125 """
190 126
191 __implements__ = (IAstroidChecker,) 127 __implements__ = (IASTNGChecker,)
192 128
193 # configuration section name 129 # configuration section name
194 name = 'classes' 130 name = 'classes'
195 # messages 131 # messages
196 msgs = MSGS 132 msgs = MSGS
197 priority = -2 133 priority = -2
198 # configuration options 134 # configuration options
199 options = (('ignore-iface-methods', 135 options = (('ignore-iface-methods',
200 {'default' : (#zope interface 136 {'default' : (#zope interface
201 'isImplementedBy', 'deferred', 'extends', 'names', 137 'isImplementedBy', 'deferred', 'extends', 'names',
202 'namesAndDescriptions', 'queryDescriptionFor', 'getBases', 138 'namesAndDescriptions', 'queryDescriptionFor', 'getBases',
203 'getDescriptionFor', 'getDoc', 'getName', 'getTaggedValue', 139 'getDescriptionFor', 'getDoc', 'getName', 'getTaggedValue',
204 'getTaggedValueTags', 'isEqualOrExtendedBy', 'setTaggedValue ', 140 'getTaggedValueTags', 'isEqualOrExtendedBy', 'setTaggedValue',
205 'isImplementedByInstancesOf', 141 'isImplementedByInstancesOf',
206 # twisted 142 # twisted
207 'adaptWith', 143 'adaptWith',
208 # logilab.common interface 144 # logilab.common interface
209 'is_implemented_by'), 145 'is_implemented_by'),
210 'type' : 'csv', 146 'type' : 'csv',
211 'metavar' : '<method names>', 147 'metavar' : '<method names>',
212 'help' : 'List of interface methods to ignore, \ 148 'help' : 'List of interface methods to ignore, \
213 separated by a comma. This is used for instance to not check methods defines \ 149 separated by a comma. This is used for instance to not check methods defines \
214 in Zope\'s Interface base class.'} 150 in Zope\'s Interface base class.'}
215 ), 151 ),
152
216 ('defining-attr-methods', 153 ('defining-attr-methods',
217 {'default' : ('__init__', '__new__', 'setUp'), 154 {'default' : ('__init__', '__new__', 'setUp'),
218 'type' : 'csv', 155 'type' : 'csv',
219 'metavar' : '<method names>', 156 'metavar' : '<method names>',
220 'help' : 'List of method names used to declare (i.e. assign) \ 157 'help' : 'List of method names used to declare (i.e. assign) \
221 instance attributes.'} 158 instance attributes.'}
222 ), 159 ),
223 ('valid-classmethod-first-arg', 160 ('valid-classmethod-first-arg',
224 {'default' : ('cls',), 161 {'default' : ('cls',),
225 'type' : 'csv', 162 'type' : 'csv',
226 'metavar' : '<argument names>', 163 'metavar' : '<argument names>',
227 'help' : 'List of valid names for the first argument in \ 164 'help' : 'List of valid names for the first argument in \
228 a class method.'} 165 a class method.'}
229 ), 166 ),
230 ('valid-metaclass-classmethod-first-arg', 167
231 {'default' : ('mcs',), 168 )
232 'type' : 'csv',
233 'metavar' : '<argument names>',
234 'help' : 'List of valid names for the first argument in \
235 a metaclass class method.'}
236 ),
237 )
238 169
239 def __init__(self, linter=None): 170 def __init__(self, linter=None):
240 BaseChecker.__init__(self, linter) 171 BaseChecker.__init__(self, linter)
241 self._accessed = [] 172 self._accessed = []
242 self._first_attrs = [] 173 self._first_attrs = []
243 self._meth_could_be_func = None 174 self._meth_could_be_func = None
244 175
245 def visit_class(self, node): 176 def visit_class(self, node):
246 """init visit variable _accessed and check interfaces 177 """init visit variable _accessed and check interfaces
247 """ 178 """
248 self._accessed.append({}) 179 self._accessed.append({})
249 self._check_bases_classes(node) 180 self._check_bases_classes(node)
250 self._check_interfaces(node) 181 self._check_interfaces(node)
251 # if not an interface, exception, metaclass 182 # if not an interface, exception, metaclass
252 if node.type == 'class': 183 if node.type == 'class':
253 try: 184 try:
254 node.local_attr('__init__') 185 node.local_attr('__init__')
255 except astroid.NotFoundError: 186 except astng.NotFoundError:
256 self.add_message('no-init', args=node, node=node) 187 self.add_message('W0232', args=node, node=node)
257 self._check_slots(node)
258 188
259 @check_messages('access-member-before-definition', 'attribute-defined-outsid e-init') 189 @check_messages('E0203', 'W0201')
260 def leave_class(self, cnode): 190 def leave_class(self, cnode):
261 """close a class node: 191 """close a class node:
262 check that instance attributes are defined in __init__ and check 192 check that instance attributes are defined in __init__ and check
263 access to existent members 193 access to existent members
264 """ 194 """
265 # check access to existent members on non metaclass classes 195 # check access to existent members on non metaclass classes
266 accessed = self._accessed.pop() 196 accessed = self._accessed.pop()
267 if cnode.type != 'metaclass': 197 if cnode.type != 'metaclass':
268 self._check_accessed_members(cnode, accessed) 198 self._check_accessed_members(cnode, accessed)
269 # checks attributes are defined in an allowed method such as __init__ 199 # checks attributes are defined in an allowed method such as __init__
270 if not self.linter.is_message_enabled('attribute-defined-outside-init'): 200 if 'W0201' not in self.active_msgs:
271 return 201 return
272 defining_methods = self.config.defining_attr_methods 202 defining_methods = self.config.defining_attr_methods
273 current_module = cnode.root() 203 for attr, nodes in cnode.instance_attrs.items():
274 for attr, nodes in cnode.instance_attrs.iteritems():
275 # skip nodes which are not in the current module and it may screw up
276 # the output, while it's not worth it
277 nodes = [n for n in nodes if not 204 nodes = [n for n in nodes if not
278 isinstance(n.statement(), (astroid.Delete, astroid.AugAssig n)) 205 isinstance(n.statement(), (astng.Delete, astng.AugAssign))]
279 and n.root() is current_module]
280 if not nodes: 206 if not nodes:
281 continue # error detected by typechecking 207 continue # error detected by typechecking
208 attr_defined = False
282 # check if any method attr is defined in is a defining method 209 # check if any method attr is defined in is a defining method
283 if any(node.frame().name in defining_methods 210 for node in nodes:
284 for node in nodes): 211 if node.frame().name in defining_methods:
285 continue 212 attr_defined = True
286 213 if not attr_defined:
287 # check attribute is defined in a parent's __init__ 214 # check attribute is defined in a parent's __init__
288 for parent in cnode.instance_attr_ancestors(attr): 215 for parent in cnode.instance_attr_ancestors(attr):
289 attr_defined = False 216 attr_defined = False
290 # check if any parent method attr is defined in is a defining me thod 217 # check if any parent method attr is defined in is a definin g method
291 for node in parent.instance_attrs[attr]: 218 for node in parent.instance_attrs[attr]:
292 if node.frame().name in defining_methods: 219 if node.frame().name in defining_methods:
293 attr_defined = True 220 attr_defined = True
294 if attr_defined: 221 if attr_defined:
295 # we're done :) 222 # we're done :)
296 break 223 break
297 else: 224 else:
298 # check attribute is defined as a class attribute 225 # check attribute is defined as a class attribute
299 try: 226 try:
300 cnode.local_attr(attr) 227 cnode.local_attr(attr)
301 except astroid.NotFoundError: 228 except astng.NotFoundError:
302 for node in nodes: 229 self.add_message('W0201', args=attr, node=node)
303 if node.frame().name not in defining_methods:
304 self.add_message('attribute-defined-outside-init',
305 args=attr, node=node)
306 230
307 def visit_function(self, node): 231 def visit_function(self, node):
308 """check method arguments, overriding""" 232 """check method arguments, overriding"""
309 # ignore actual functions 233 # ignore actual functions
310 if not node.is_method(): 234 if not node.is_method():
311 return 235 return
312 klass = node.parent.frame() 236 klass = node.parent.frame()
313 self._meth_could_be_func = True 237 self._meth_could_be_func = True
314 # check first argument is self if this is actually a method 238 # check first argument is self if this is actually a method
315 self._check_first_arg_for_type(node, klass.type == 'metaclass') 239 self._check_first_arg_for_type(node, klass.type == 'metaclass')
316 if node.name == '__init__': 240 if node.name == '__init__':
317 self._check_init(node) 241 self._check_init(node)
318 return 242 return
319 # check signature if the method overloads inherited method 243 # check signature if the method overloads inherited method
320 for overridden in klass.local_attr_ancestors(node.name): 244 for overridden in klass.local_attr_ancestors(node.name):
321 # get astroid for the searched method 245 # get astng for the searched method
322 try: 246 try:
323 meth_node = overridden[node.name] 247 meth_node = overridden[node.name]
324 except KeyError: 248 except KeyError:
325 # we have found the method but it's not in the local 249 # we have found the method but it's not in the local
326 # dictionary. 250 # dictionary.
327 # This may happen with astroid build from living objects 251 # This may happen with astng build from living objects
328 continue 252 continue
329 if not isinstance(meth_node, astroid.Function): 253 if not isinstance(meth_node, astng.Function):
330 continue 254 continue
331 self._check_signature(node, meth_node, 'overridden') 255 self._check_signature(node, meth_node, 'overridden')
332 break 256 break
333 if node.decorators: 257 # check if the method overload an attribute
334 for decorator in node.decorators.nodes:
335 if isinstance(decorator, astroid.Getattr) and \
336 decorator.attrname in ('getter', 'setter', 'deleter'):
337 # attribute affectation will call this method, not hiding it
338 return
339 if isinstance(decorator, astroid.Name) and decorator.name == 'pr operty':
340 # attribute affectation will either call a setter or raise
341 # an attribute error, anyway not hiding the function
342 return
343 # check if the method is hidden by an attribute
344 try: 258 try:
345 overridden = klass.instance_attr(node.name)[0] # XXX 259 overridden = klass.instance_attr(node.name)[0] # XXX
346 overridden_frame = overridden.frame() 260 args = (overridden.root().name, overridden.fromlineno)
347 if (isinstance(overridden_frame, astroid.Function) 261 self.add_message('E0202', args=args, node=node)
348 and overridden_frame.type == 'method'): 262 except astng.NotFoundError:
349 overridden_frame = overridden_frame.parent.frame()
350 if (isinstance(overridden_frame, Class)
351 and klass._is_subtype_of(overridden_frame.qname())):
352 args = (overridden.root().name, overridden.fromlineno)
353 self.add_message('method-hidden', args=args, node=node)
354 except astroid.NotFoundError:
355 pass 263 pass
356 264
357 # check non-iterators in __iter__
358 if node.name == '__iter__':
359 self._check_iter(node)
360 elif node.name == '__exit__':
361 self._check_exit(node)
362
363 def _check_slots(self, node):
364 if '__slots__' not in node.locals:
365 return
366 for slots in node.igetattr('__slots__'):
367 # check if __slots__ is a valid type
368 for meth in ITER_METHODS:
369 try:
370 slots.getattr(meth)
371 break
372 except astroid.NotFoundError:
373 continue
374 else:
375 self.add_message('invalid-slots', node=node)
376 continue
377
378 if isinstance(slots, astroid.Const):
379 # a string, ignore the following checks
380 continue
381 if not hasattr(slots, 'itered'):
382 # we can't obtain the values, maybe a .deque?
383 continue
384
385 if isinstance(slots, astroid.Dict):
386 values = [item[0] for item in slots.items]
387 else:
388 values = slots.itered()
389 if values is YES:
390 return
391
392 for elt in values:
393 try:
394 self._check_slots_elt(elt)
395 except astroid.InferenceError:
396 continue
397
398 def _check_slots_elt(self, elt):
399 for infered in elt.infer():
400 if infered is YES:
401 continue
402 if (not isinstance(infered, astroid.Const) or
403 not isinstance(infered.value, str)):
404 self.add_message('invalid-slots-object',
405 args=infered.as_string(),
406 node=elt)
407 continue
408 if not infered.value:
409 self.add_message('invalid-slots-object',
410 args=infered.as_string(),
411 node=elt)
412
413 def _check_iter(self, node):
414 try:
415 infered = node.infer_call_result(node)
416 except astroid.InferenceError:
417 return
418
419 for infered_node in infered:
420 if (infered_node is YES
421 or isinstance(infered_node, Generator)):
422 continue
423 if isinstance(infered_node, astroid.Instance):
424 try:
425 infered_node.local_attr(NEXT_METHOD)
426 except astroid.NotFoundError:
427 self.add_message('non-iterator-returned',
428 node=node)
429 break
430
431 def _check_exit(self, node):
432 positional = sum(1 for arg in node.args.args if arg.name != 'self')
433 if positional < 3 and not node.args.vararg:
434 self.add_message('bad-context-manager',
435 node=node)
436 elif positional > 3:
437 self.add_message('bad-context-manager',
438 node=node)
439
440 def leave_function(self, node): 265 def leave_function(self, node):
441 """on method node, check if this method couldn't be a function 266 """on method node, check if this method couldn't be a function
442 267
443 ignore class, static and abstract methods, initializer, 268 ignore class, static and abstract methods, initializer,
444 methods overridden from a parent class and any 269 methods overridden from a parent class and any
445 kind of method defined in an interface for this warning 270 kind of method defined in an interface for this warning
446 """ 271 """
447 if node.is_method(): 272 if node.is_method():
448 if node.args.args is not None: 273 if node.args.args is not None:
449 self._first_attrs.pop() 274 self._first_attrs.pop()
450 if not self.linter.is_message_enabled('no-self-use'): 275 if 'R0201' not in self.active_msgs:
451 return 276 return
452 class_node = node.parent.frame() 277 class_node = node.parent.frame()
453 if (self._meth_could_be_func and node.type == 'method' 278 if (self._meth_could_be_func and node.type == 'method'
454 and not node.name in PYMETHODS 279 and not node.name in PYMETHODS
455 and not (node.is_abstract() or 280 and not (node.is_abstract() or
456 overrides_a_method(class_node, node.name)) 281 overrides_a_method(class_node, node.name))
457 and class_node.type != 'interface'): 282 and class_node.type != 'interface'):
458 self.add_message('no-self-use', node=node) 283 self.add_message('R0201', node=node)
459 284
460 def visit_getattr(self, node): 285 def visit_getattr(self, node):
461 """check if the getattr is an access to a class member 286 """check if the getattr is an access to a class member
462 if so, register it. Also check for access to protected 287 if so, register it. Also check for access to protected
463 class member from outside its class (but ignore __special__ 288 class member from outside its class (but ignore __special__
464 methods) 289 methods)
465 """ 290 """
466 attrname = node.attrname 291 attrname = node.attrname
467 # Check self 292 if self._first_attrs and isinstance(node.expr, astng.Name) and \
468 if self.is_first_attr(node): 293 node.expr.name == self._first_attrs[-1]:
469 self._accessed[-1].setdefault(attrname, []).append(node) 294 self._accessed[-1].setdefault(attrname, []).append(node)
470 return 295 return
471 if not self.linter.is_message_enabled('protected-access'): 296 if 'W0212' not in self.active_msgs:
472 return 297 return
473 298 if attrname[0] == '_' and not attrname == '_' and not (
474 self._check_protected_attribute_access(node) 299 attrname.startswith('__') and attrname.endswith('__')):
475 300 # XXX move this in a reusable function
476 def visit_assattr(self, node): 301 klass = node.frame()
477 if isinstance(node.ass_type(), astroid.AugAssign) and self.is_first_attr (node): 302 while klass is not None and not isinstance(klass, astng.Class):
478 self._accessed[-1].setdefault(node.attrname, []).append(node) 303 if klass.parent is None:
479 self._check_in_slots(node) 304 klass = None
480 305 else:
481 def _check_in_slots(self, node): 306 klass = klass.parent.frame()
482 """ Check that the given assattr node
483 is defined in the class slots.
484 """
485 infered = safe_infer(node.expr)
486 if infered and isinstance(infered, Instance):
487 klass = infered._proxied
488 if '__slots__' not in klass.locals or not klass.newstyle:
489 return
490
491 slots = klass.slots()
492 # If any ancestor doesn't use slots, the slots
493 # defined for this class are superfluous.
494 if any('__slots__' not in ancestor.locals and
495 ancestor.name != 'object'
496 for ancestor in klass.ancestors()):
497 return
498
499 if not any(slot.value == node.attrname for slot in slots):
500 # If we have a '__dict__' in slots, then
501 # assigning any name is valid.
502 if not any(slot.value == '__dict__' for slot in slots):
503 self.add_message('assigning-non-slot',
504 args=(node.attrname, ), node=node)
505
506 @check_messages('protected-access')
507 def visit_assign(self, assign_node):
508 node = assign_node.targets[0]
509 if not isinstance(node, AssAttr):
510 return
511
512 if self.is_first_attr(node):
513 return
514
515 self._check_protected_attribute_access(node)
516
517 def _check_protected_attribute_access(self, node):
518 '''Given an attribute access node (set or get), check if attribute
519 access is legitimate. Call _check_first_attr with node before calling
520 this method. Valid cases are:
521 * self._attr in a method or cls._attr in a classmethod. Checked by
522 _check_first_attr.
523 * Klass._attr inside "Klass" class.
524 * Klass2._attr inside "Klass" class when Klass2 is a base class of
525 Klass.
526 '''
527 attrname = node.attrname
528
529 if is_attr_protected(attrname):
530
531 klass = node_frame_class(node)
532
533 # XXX infer to be more safe and less dirty ?? 307 # XXX infer to be more safe and less dirty ??
534 # in classes, check we are not getting a parent method 308 # in classes, check we are not getting a parent method
535 # through the class object or through super 309 # through the class object or through super
536 callee = node.expr.as_string() 310 callee = node.expr.as_string()
311 if klass is None or not (callee == klass.name or
312 callee in klass.basenames
313 or (isinstance(node.expr, astng.CallFunc)
314 and isinstance(node.expr.func, astng.Name)
315 and node.expr.func.name == 'super')):
316 self.add_message('W0212', node=node, args=attrname)
537 317
538 # We are not in a class, no remaining valid case
539 if klass is None:
540 self.add_message('protected-access', node=node, args=attrname)
541 return
542
543 # If the expression begins with a call to super, that's ok.
544 if isinstance(node.expr, astroid.CallFunc) and \
545 isinstance(node.expr.func, astroid.Name) and \
546 node.expr.func.name == 'super':
547 return
548
549 # We are in a class, one remaining valid cases, Klass._attr inside
550 # Klass
551 if not (callee == klass.name or callee in klass.basenames):
552 self.add_message('protected-access', node=node, args=attrname)
553 318
554 def visit_name(self, node): 319 def visit_name(self, node):
555 """check if the name handle an access to a class member 320 """check if the name handle an access to a class member
556 if so, register it 321 if so, register it
557 """ 322 """
558 if self._first_attrs and (node.name == self._first_attrs[-1] or 323 if self._first_attrs and (node.name == self._first_attrs[-1] or
559 not self._first_attrs[-1]): 324 not self._first_attrs[-1]):
560 self._meth_could_be_func = False 325 self._meth_could_be_func = False
561 326
562 def _check_accessed_members(self, node, accessed): 327 def _check_accessed_members(self, node, accessed):
563 """check that accessed members are defined""" 328 """check that accessed members are defined"""
564 # XXX refactor, probably much simpler now that E0201 is in type checker 329 # XXX refactor, probably much simpler now that E0201 is in type checker
565 for attr, nodes in accessed.iteritems(): 330 for attr, nodes in accessed.items():
566 # deactivate "except doesn't do anything", that's expected 331 # deactivate "except doesn't do anything", that's expected
567 # pylint: disable=W0704 332 # pylint: disable=W0704
333 # is it a class attribute ?
568 try: 334 try:
569 # is it a class attribute ?
570 node.local_attr(attr) 335 node.local_attr(attr)
571 # yes, stop here 336 # yes, stop here
572 continue 337 continue
573 except astroid.NotFoundError: 338 except astng.NotFoundError:
574 pass 339 pass
575 # is it an instance attribute of a parent class ? 340 # is it an instance attribute of a parent class ?
576 try: 341 try:
577 node.instance_attr_ancestors(attr).next() 342 node.instance_attr_ancestors(attr).next()
578 # yes, stop here 343 # yes, stop here
579 continue 344 continue
580 except StopIteration: 345 except StopIteration:
581 pass 346 pass
582 # is it an instance attribute ? 347 # is it an instance attribute ?
583 try: 348 try:
584 defstmts = node.instance_attr(attr) 349 defstmts = node.instance_attr(attr)
585 except astroid.NotFoundError: 350 except astng.NotFoundError:
586 pass 351 pass
587 else: 352 else:
588 # filter out augment assignment nodes
589 defstmts = [stmt for stmt in defstmts if stmt not in nodes]
590 if not defstmts:
591 # only augment assignment for this node, no-member should be
592 # triggered by the typecheck checker
593 continue
594 # filter defstmts to only pick the first one when there are
595 # several assignments in the same scope
596 scope = defstmts[0].scope()
597 defstmts = [stmt for i, stmt in enumerate(defstmts)
598 if i == 0 or stmt.scope() is not scope]
599 # if there are still more than one, don't attempt to be smarter
600 # than we can be
601 if len(defstmts) == 1: 353 if len(defstmts) == 1:
602 defstmt = defstmts[0] 354 defstmt = defstmts[0]
603 # check that if the node is accessed in the same method as 355 # check that if the node is accessed in the same method as
604 # it's defined, it's accessed after the initial assignment 356 # it's defined, it's accessed after the initial assignment
605 frame = defstmt.frame() 357 frame = defstmt.frame()
606 lno = defstmt.fromlineno 358 lno = defstmt.fromlineno
607 for _node in nodes: 359 for _node in nodes:
608 if _node.frame() is frame and _node.fromlineno < lno \ 360 if _node.frame() is frame and _node.fromlineno < lno \
609 and not are_exclusive(_node.statement(), defstmt, ('A ttributeError', 'Exception', 'BaseException')): 361 and not are_exclusive(_node.statement(), defstmt, ('A ttributeError', 'Exception', 'BaseException')):
610 self.add_message('access-member-before-definition', 362 self.add_message('E0203', node=_node,
611 node=_node, args=(attr, lno)) 363 args=(attr, lno))
612 364
613 def _check_first_arg_for_type(self, node, metaclass=0): 365 def _check_first_arg_for_type(self, node, metaclass=0):
614 """check the name of first argument, expect: 366 """check the name of first argument, expect:
615 367
616 * 'self' for a regular method 368 * 'self' for a regular method
617 * 'cls' for a class method or a metaclass regular method (actually 369 * 'cls' for a class method
618 valid-classmethod-first-arg value) 370 * 'mcs' for a metaclass
619 * 'mcs' for a metaclass class method (actually
620 valid-metaclass-classmethod-first-arg)
621 * not one of the above for a static method 371 * not one of the above for a static method
622 """ 372 """
623 # don't care about functions with unknown argument (builtins) 373 # don't care about functions with unknown argument (builtins)
624 if node.args.args is None: 374 if node.args.args is None:
625 return 375 return
626 first_arg = node.args.args and node.argnames()[0] 376 first_arg = node.args.args and node.argnames()[0]
627 self._first_attrs.append(first_arg) 377 self._first_attrs.append(first_arg)
628 first = self._first_attrs[-1] 378 first = self._first_attrs[-1]
629 # static method 379 # static method
630 if node.type == 'staticmethod': 380 if node.type == 'staticmethod':
631 if (first_arg == 'self' or 381 if first_arg in ('self', 'cls', 'mcs'):
632 first_arg in self.config.valid_classmethod_first_arg or 382 self.add_message('W0211', args=first, node=node)
633 first_arg in self.config.valid_metaclass_classmethod_first_a rg):
634 self.add_message('bad-staticmethod-argument', args=first, node=n ode)
635 return
636 self._first_attrs[-1] = None 383 self._first_attrs[-1] = None
637 # class / regular method with no args 384 # class / regular method with no args
638 elif not node.args.args: 385 elif not node.args.args:
639 self.add_message('no-method-argument', node=node) 386 self.add_message('E0211', node=node)
640 # metaclass 387 # metaclass method
641 elif metaclass: 388 elif metaclass:
642 # metaclass __new__ or classmethod 389 if first != 'mcs':
643 if node.type == 'classmethod': 390 self.add_message('C0203', node=node)
644 self._check_first_arg_config( 391 # class method
645 first, 392 elif node.type == 'classmethod':
646 self.config.valid_metaclass_classmethod_first_arg, node, 393 if first not in self.config.valid_classmethod_first_arg:
647 'bad-mcs-classmethod-argument', node.name) 394 if len(self.config.valid_classmethod_first_arg) == 1:
648 # metaclass regular method 395 valid = repr(self.config.valid_classmethod_first_arg[0])
649 else: 396 else:
650 self._check_first_arg_config( 397 valid = ', '.join(
651 first, 398 repr(v)
652 self.config.valid_classmethod_first_arg, node, 'bad-mcs-meth od-argument', 399 for v in self.config.valid_classmethod_first_arg[:-1])
653 node.name) 400 valid = '%s or %r' % (
654 # regular class 401 valid, self.config.valid_classmethod_first_arg[-1])
655 else: 402 self.add_message('C0202', args=valid, node=node)
656 # class method 403 # regular method without self as argument
657 if node.type == 'classmethod': 404 elif first != 'self':
658 self._check_first_arg_config( 405 self.add_message('E0213', node=node)
659 first,
660 self.config.valid_classmethod_first_arg, node, 'bad-classmet hod-argument',
661 node.name)
662 # regular method without self as argument
663 elif first != 'self':
664 self.add_message('no-self-argument', node=node)
665
666 def _check_first_arg_config(self, first, config, node, message,
667 method_name):
668 if first not in config:
669 if len(config) == 1:
670 valid = repr(config[0])
671 else:
672 valid = ', '.join(repr(v) for v in config[:-1])
673 valid = '%s or %r' % (valid, config[-1])
674 self.add_message(message, args=(method_name, valid), node=node)
675 406
676 def _check_bases_classes(self, node): 407 def _check_bases_classes(self, node):
677 """check that the given class node implements abstract methods from 408 """check that the given class node implements abstract methods from
678 base classes 409 base classes
679 """ 410 """
680 # check if this class abstract 411 # check if this class abstract
681 if class_is_abstract(node): 412 if class_is_abstract(node):
682 return 413 return
683 for method in node.methods(): 414 for method in node.methods():
684 owner = method.parent.frame() 415 owner = method.parent.frame()
685 if owner is node: 416 if owner is node:
686 continue 417 continue
687 # owner is not this class, it must be a parent class 418 # owner is not this class, it must be a parent class
688 # check that the ancestor's method is not abstract 419 # check that the ancestor's method is not abstract
689 if method.name in node.locals:
690 # it is redefined as an attribute or with a descriptor
691 continue
692 if method.is_abstract(pass_is_abstract=False): 420 if method.is_abstract(pass_is_abstract=False):
693 self.add_message('abstract-method', node=node, 421 self.add_message('W0223', node=node,
694 args=(method.name, owner.name)) 422 args=(method.name, owner.name))
695 423
696 def _check_interfaces(self, node): 424 def _check_interfaces(self, node):
697 """check that the given class node really implements declared 425 """check that the given class node really implements declared
698 interfaces 426 interfaces
699 """ 427 """
700 e0221_hack = [False] 428 e0221_hack = [False]
701 def iface_handler(obj): 429 def iface_handler(obj):
702 """filter interface objects, it should be classes""" 430 """filter interface objects, it should be classes"""
703 if not isinstance(obj, astroid.Class): 431 if not isinstance(obj, astng.Class):
704 e0221_hack[0] = True 432 e0221_hack[0] = True
705 self.add_message('interface-is-not-class', node=node, 433 self.add_message('E0221', node=node,
706 args=(obj.as_string(),)) 434 args=(obj.as_string(),))
707 return False 435 return False
708 return True 436 return True
709 ignore_iface_methods = self.config.ignore_iface_methods 437 ignore_iface_methods = self.config.ignore_iface_methods
710 try: 438 try:
711 for iface in node.interfaces(handler_func=iface_handler): 439 for iface in node.interfaces(handler_func=iface_handler):
712 for imethod in iface.methods(): 440 for imethod in iface.methods():
713 name = imethod.name 441 name = imethod.name
714 if name.startswith('_') or name in ignore_iface_methods: 442 if name.startswith('_') or name in ignore_iface_methods:
715 # don't check method beginning with an underscore, 443 # don't check method beginning with an underscore,
716 # usually belonging to the interface implementation 444 # usually belonging to the interface implementation
717 continue 445 continue
718 # get class method astroid 446 # get class method astng
719 try: 447 try:
720 method = node_method(node, name) 448 method = node_method(node, name)
721 except astroid.NotFoundError: 449 except astng.NotFoundError:
722 self.add_message('missing-interface-method', args=(name, iface.name), 450 self.add_message('E0222', args=(name, iface.name),
723 node=node) 451 node=node)
724 continue 452 continue
725 # ignore inherited methods 453 # ignore inherited methods
726 if method.parent.frame() is not node: 454 if method.parent.frame() is not node:
727 continue 455 continue
728 # check signature 456 # check signature
729 self._check_signature(method, imethod, 457 self._check_signature(method, imethod,
730 '%s interface' % iface.name) 458 '%s interface' % iface.name)
731 except astroid.InferenceError: 459 except astng.InferenceError:
732 if e0221_hack[0]: 460 if e0221_hack[0]:
733 return 461 return
734 implements = Instance(node).getattr('__implements__')[0] 462 implements = Instance(node).getattr('__implements__')[0]
735 assignment = implements.parent 463 assignment = implements.parent
736 assert isinstance(assignment, astroid.Assign) 464 assert isinstance(assignment, astng.Assign)
737 # assignment.expr can be a Name or a Tuple or whatever. 465 # assignment.expr can be a Name or a Tuple or whatever.
738 # Use as_string() for the message 466 # Use as_string() for the message
739 # FIXME: in case of multiple interfaces, find which one could not 467 # FIXME: in case of multiple interfaces, find which one could not
740 # be resolved 468 # be resolved
741 self.add_message('unresolved-interface', node=implements, 469 self.add_message('F0220', node=implements,
742 args=(node.name, assignment.value.as_string())) 470 args=(node.name, assignment.value.as_string()))
743 471
744 def _check_init(self, node): 472 def _check_init(self, node):
745 """check that the __init__ method call super or ancestors'__init__ 473 """check that the __init__ method call super or ancestors'__init__
746 method 474 method
747 """ 475 """
748 if (not self.linter.is_message_enabled('super-init-not-called') and 476 if not set(('W0231', 'W0233')) & self.active_msgs:
749 not self.linter.is_message_enabled('non-parent-init-called')):
750 return 477 return
751 klass_node = node.parent.frame() 478 klass_node = node.parent.frame()
752 to_call = _ancestors_to_call(klass_node) 479 to_call = _ancestors_to_call(klass_node)
753 not_called_yet = dict(to_call) 480 not_called_yet = dict(to_call)
754 for stmt in node.nodes_of_class(astroid.CallFunc): 481 for stmt in node.nodes_of_class(astng.CallFunc):
755 expr = stmt.func 482 expr = stmt.func
756 if not isinstance(expr, astroid.Getattr) \ 483 if not isinstance(expr, astng.Getattr) \
757 or expr.attrname != '__init__': 484 or expr.attrname != '__init__':
758 continue 485 continue
759 # skip the test if using super 486 # skip the test if using super
760 if isinstance(expr.expr, astroid.CallFunc) and \ 487 if isinstance(expr.expr, astng.CallFunc) and \
761 isinstance(expr.expr.func, astroid.Name) and \ 488 isinstance(expr.expr.func, astng.Name) and \
762 expr.expr.func.name == 'super': 489 expr.expr.func.name == 'super':
763 return 490 return
764 try: 491 try:
765 klass = expr.expr.infer().next() 492 klass = expr.expr.infer().next()
766 if klass is YES: 493 if klass is YES:
767 continue 494 continue
768 try: 495 try:
769 del not_called_yet[klass] 496 del not_called_yet[klass]
770 except KeyError: 497 except KeyError:
771 if klass not in to_call: 498 if klass not in to_call:
772 self.add_message('non-parent-init-called', node=expr, ar gs=klass.name) 499 self.add_message('W0233', node=expr, args=klass.name)
773 except astroid.InferenceError: 500 except astng.InferenceError:
774 continue 501 continue
775 for klass, method in not_called_yet.iteritems(): 502 for klass in not_called_yet.keys():
776 if klass.name == 'object' or method.parent.name == 'object': 503 if klass.name == 'object':
777 continue 504 continue
778 self.add_message('super-init-not-called', args=klass.name, node=node ) 505 self.add_message('W0231', args=klass.name, node=node)
779 506
780 def _check_signature(self, method1, refmethod, class_type): 507 def _check_signature(self, method1, refmethod, class_type):
781 """check that the signature of the two given methods match 508 """check that the signature of the two given methods match
782 509
783 class_type is in 'class', 'interface' 510 class_type is in 'class', 'interface'
784 """ 511 """
785 if not (isinstance(method1, astroid.Function) 512 if not (isinstance(method1, astng.Function)
786 and isinstance(refmethod, astroid.Function)): 513 and isinstance(refmethod, astng.Function)):
787 self.add_message('method-check-failed', args=(method1, refmethod), n ode=method1) 514 self.add_message('F0202', args=(method1, refmethod), node=method1)
788 return 515 return
789 # don't care about functions with unknown argument (builtins) 516 # don't care about functions with unknown argument (builtins)
790 if method1.args.args is None or refmethod.args.args is None: 517 if method1.args.args is None or refmethod.args.args is None:
791 return 518 return
792 # if we use *args, **kwargs, skip the below checks 519 # if we use *args, **kwargs, skip the below checks
793 if method1.args.vararg or method1.args.kwarg: 520 if method1.args.vararg or method1.args.kwarg:
794 return 521 return
795 if is_attr_private(method1.name):
796 return
797 if len(method1.args.args) != len(refmethod.args.args): 522 if len(method1.args.args) != len(refmethod.args.args):
798 self.add_message('arguments-differ', args=class_type, node=method1) 523 self.add_message('W0221', args=class_type, node=method1)
799 elif len(method1.args.defaults) < len(refmethod.args.defaults): 524 elif len(method1.args.defaults) < len(refmethod.args.defaults):
800 self.add_message('signature-differs', args=class_type, node=method1) 525 self.add_message('W0222', args=class_type, node=method1)
801 526
802 def is_first_attr(self, node):
803 """Check that attribute lookup name use first attribute variable name
804 (self for method, cls for classmethod and mcs for metaclass).
805 """
806 return self._first_attrs and isinstance(node.expr, astroid.Name) and \
807 node.expr.name == self._first_attrs[-1]
808 527
809 def _ancestors_to_call(klass_node, method='__init__'): 528 def _ancestors_to_call(klass_node, method='__init__'):
810 """return a dictionary where keys are the list of base classes providing 529 """return a dictionary where keys are the list of base classes providing
811 the queried method, and so that should/may be called from the method node 530 the queried method, and so that should/may be called from the method node
812 """ 531 """
813 to_call = {} 532 to_call = {}
814 for base_node in klass_node.ancestors(recurs=False): 533 for base_node in klass_node.ancestors(recurs=False):
815 try: 534 try:
816 to_call[base_node] = base_node.igetattr(method).next() 535 base_node.local_attr(method)
817 except astroid.InferenceError: 536 to_call[base_node] = 1
537 except astng.NotFoundError:
818 continue 538 continue
819 return to_call 539 return to_call
820 540
821 541
822 def node_method(node, method_name): 542 def node_method(node, method_name):
823 """get astroid for <method_name> on the given class node, ensuring it 543 """get astng for <method_name> on the given class node, ensuring it
824 is a Function node 544 is a Function node
825 """ 545 """
826 for n in node.local_attr(method_name): 546 for n in node.local_attr(method_name):
827 if isinstance(n, astroid.Function): 547 if isinstance(n, astng.Function):
828 return n 548 return n
829 raise astroid.NotFoundError(method_name) 549 raise astng.NotFoundError(method_name)
830 550
831 def register(linter): 551 def register(linter):
832 """required method to auto register this checker """ 552 """required method to auto register this checker """
833 linter.register_checker(ClassChecker(linter)) 553 linter.register_checker(ClassChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/base.py ('k') | third_party/pylint/checkers/design_analysis.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698