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

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

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months 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
OLDNEW
(Empty)
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # Copyright (c) 2009-2010 Arista Networks, Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any later
8 # version.
9 #
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
15 # this program; if not, write to the Free Software Foundation, Inc.,
16 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 """basic checker for Python code"""
18
19 import collections
20 import itertools
21 import sys
22 import re
23
24 import six
25 from six.moves import zip # pylint: disable=redefined-builtin
26
27 from logilab.common.ureports import Table
28
29 import astroid
30 import astroid.bases
31 from astroid import are_exclusive, InferenceError
32
33 from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIG H
34 from pylint.utils import EmptyReport
35 from pylint.reporters import diff_string
36 from pylint.checkers import BaseChecker
37 from pylint.checkers.utils import (
38 check_messages,
39 clobber_in_except,
40 is_builtin_object,
41 is_inside_except,
42 overrides_a_method,
43 safe_infer,
44 get_argument_from_call,
45 has_known_bases,
46 NoSuchArgumentError,
47 is_import_error,
48 unimplemented_abstract_methods,
49 )
50
51
52 # regex for class/function/variable/constant name
53 CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$')
54 MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$')
55 CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$')
56 COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$')
57 DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
58 CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$')
59 # do not require a doc string on system methods
60 NO_REQUIRED_DOC_RGX = re.compile('__.*__')
61 REVERSED_METHODS = (('__getitem__', '__len__'),
62 ('__reversed__', ))
63
64 PY33 = sys.version_info >= (3, 3)
65 PY3K = sys.version_info >= (3, 0)
66 BAD_FUNCTIONS = ['map', 'filter']
67 if sys.version_info < (3, 0):
68 BAD_FUNCTIONS.append('input')
69
70 # Name categories that are always consistent with all naming conventions.
71 EXEMPT_NAME_CATEGORIES = set(('exempt', 'ignore'))
72
73 # A mapping from builtin-qname -> symbol, to be used when generating messages
74 # about dangerous default values as arguments
75 DEFAULT_ARGUMENT_SYMBOLS = dict(
76 zip(['.'.join([astroid.bases.BUILTINS, x]) for x in ('set', 'dict', 'list')] ,
77 ['set()', '{}', '[]'])
78 )
79
80 del re
81
82 def _redefines_import(node):
83 """ Detect that the given node (AssName) is inside an
84 exception handler and redefines an import from the tryexcept body.
85 Returns True if the node redefines an import, False otherwise.
86 """
87 current = node
88 while current and not isinstance(current.parent, astroid.ExceptHandler):
89 current = current.parent
90 if not current or not is_import_error(current.parent):
91 return False
92 try_block = current.parent.parent
93 for import_node in try_block.nodes_of_class((astroid.From, astroid.Import)):
94 for name, alias in import_node.names:
95 if alias:
96 if alias == node.name:
97 return True
98 elif name == node.name:
99 return True
100 return False
101
102 def in_loop(node):
103 """return True if the node is inside a kind of for loop"""
104 parent = node.parent
105 while parent is not None:
106 if isinstance(parent, (astroid.For, astroid.ListComp, astroid.SetComp,
107 astroid.DictComp, astroid.GenExpr)):
108 return True
109 parent = parent.parent
110 return False
111
112 def in_nested_list(nested_list, obj):
113 """return true if the object is an element of <nested_list> or of a nested
114 list
115 """
116 for elmt in nested_list:
117 if isinstance(elmt, (list, tuple)):
118 if in_nested_list(elmt, obj):
119 return True
120 elif elmt == obj:
121 return True
122 return False
123
124 def _loop_exits_early(loop):
125 """Returns true if a loop has a break statement in its body."""
126 loop_nodes = (astroid.For, astroid.While)
127 # Loop over body explicitly to avoid matching break statements
128 # in orelse.
129 for child in loop.body:
130 if isinstance(child, loop_nodes):
131 # break statement may be in orelse of child loop.
132 # pylint: disable=superfluous-parens
133 for orelse in (child.orelse or ()):
134 for _ in orelse.nodes_of_class(astroid.Break, skip_klass=loop_no des):
135 return True
136 continue
137 for _ in child.nodes_of_class(astroid.Break, skip_klass=loop_nodes):
138 return True
139 return False
140
141 def _is_multi_naming_match(match, node_type, confidence):
142 return (match is not None and
143 match.lastgroup is not None and
144 match.lastgroup not in EXEMPT_NAME_CATEGORIES
145 and (node_type != 'method' or confidence != INFERENCE_FAILURE))
146
147
148 if sys.version_info < (3, 0):
149 PROPERTY_CLASSES = set(('__builtin__.property', 'abc.abstractproperty'))
150 else:
151 PROPERTY_CLASSES = set(('builtins.property', 'abc.abstractproperty'))
152
153
154 def _determine_function_name_type(node):
155 """Determine the name type whose regex the a function's name should match.
156
157 :param node: A function node.
158 :returns: One of ('function', 'method', 'attr')
159 """
160 if not node.is_method():
161 return 'function'
162 if node.decorators:
163 decorators = node.decorators.nodes
164 else:
165 decorators = []
166 for decorator in decorators:
167 # If the function is a property (decorated with @property
168 # or @abc.abstractproperty), the name type is 'attr'.
169 if (isinstance(decorator, astroid.Name) or
170 (isinstance(decorator, astroid.Getattr) and
171 decorator.attrname == 'abstractproperty')):
172 infered = safe_infer(decorator)
173 if infered and infered.qname() in PROPERTY_CLASSES:
174 return 'attr'
175 # If the function is decorated using the prop_method.{setter,getter}
176 # form, treat it like an attribute as well.
177 elif (isinstance(decorator, astroid.Getattr) and
178 decorator.attrname in ('setter', 'deleter')):
179 return 'attr'
180 return 'method'
181
182
183
184 def _has_abstract_methods(node):
185 """
186 Determine if the given `node` has abstract methods.
187
188 The methods should be made abstract by decorating them
189 with `abc` decorators.
190 """
191 return len(unimplemented_abstract_methods(node)) > 0
192
193
194 def report_by_type_stats(sect, stats, old_stats):
195 """make a report of
196
197 * percentage of different types documented
198 * percentage of different types with a bad name
199 """
200 # percentage of different types documented and/or with a bad name
201 nice_stats = {}
202 for node_type in ('module', 'class', 'method', 'function'):
203 try:
204 total = stats[node_type]
205 except KeyError:
206 raise EmptyReport()
207 nice_stats[node_type] = {}
208 if total != 0:
209 try:
210 documented = total - stats['undocumented_'+node_type]
211 percent = (documented * 100.) / total
212 nice_stats[node_type]['percent_documented'] = '%.2f' % percent
213 except KeyError:
214 nice_stats[node_type]['percent_documented'] = 'NC'
215 try:
216 percent = (stats['badname_'+node_type] * 100.) / total
217 nice_stats[node_type]['percent_badname'] = '%.2f' % percent
218 except KeyError:
219 nice_stats[node_type]['percent_badname'] = 'NC'
220 lines = ('type', 'number', 'old number', 'difference',
221 '%documented', '%badname')
222 for node_type in ('module', 'class', 'method', 'function'):
223 new = stats[node_type]
224 old = old_stats.get(node_type, None)
225 if old is not None:
226 diff_str = diff_string(old, new)
227 else:
228 old, diff_str = 'NC', 'NC'
229 lines += (node_type, str(new), str(old), diff_str,
230 nice_stats[node_type].get('percent_documented', '0'),
231 nice_stats[node_type].get('percent_badname', '0'))
232 sect.append(Table(children=lines, cols=6, rheaders=1))
233
234 def redefined_by_decorator(node):
235 """return True if the object is a method redefined via decorator.
236
237 For example:
238 @property
239 def x(self): return self._x
240 @x.setter
241 def x(self, value): self._x = value
242 """
243 if node.decorators:
244 for decorator in node.decorators.nodes:
245 if (isinstance(decorator, astroid.Getattr) and
246 getattr(decorator.expr, 'name', None) == node.name):
247 return True
248 return False
249
250 class _BasicChecker(BaseChecker):
251 __implements__ = IAstroidChecker
252 name = 'basic'
253
254 class BasicErrorChecker(_BasicChecker):
255 msgs = {
256 'E0100': ('__init__ method is a generator',
257 'init-is-generator',
258 'Used when the special class method __init__ is turned into a '
259 'generator by a yield in its body.'),
260 'E0101': ('Explicit return in __init__',
261 'return-in-init',
262 'Used when the special class method __init__ has an explicit '
263 'return value.'),
264 'E0102': ('%s already defined line %s',
265 'function-redefined',
266 'Used when a function / class / method is redefined.'),
267 'E0103': ('%r not properly in loop',
268 'not-in-loop',
269 'Used when break or continue keywords are used outside a loop. '),
270 'E0104': ('Return outside function',
271 'return-outside-function',
272 'Used when a "return" statement is found outside a function or '
273 'method.'),
274 'E0105': ('Yield outside function',
275 'yield-outside-function',
276 'Used when a "yield" statement is found outside a function or '
277 'method.'),
278 'E0106': ('Return with argument inside generator',
279 'return-arg-in-generator',
280 'Used when a "return" statement with an argument is found '
281 'outside in a generator function or method (e.g. with some '
282 '"yield" statements).',
283 {'maxversion': (3, 3)}),
284 'E0107': ("Use of the non-existent %s operator",
285 'nonexistent-operator',
286 "Used when you attempt to use the C-style pre-increment or"
287 "pre-decrement operator -- and ++, which doesn't exist in Pyth on."),
288 'E0108': ('Duplicate argument name %s in function definition',
289 'duplicate-argument-name',
290 'Duplicate argument names in function definitions are syntax'
291 ' errors.'),
292 'E0110': ('Abstract class %r with abstract methods instantiated',
293 'abstract-class-instantiated',
294 'Used when an abstract class with `abc.ABCMeta` as metaclass '
295 'has abstract methods and is instantiated.'),
296 'W0120': ('Else clause on loop without a break statement',
297 'useless-else-on-loop',
298 'Loops should only have an else clause if they can exit early '
299 'with a break statement, otherwise the statements under else '
300 'should be on the same scope as the loop itself.'),
301 }
302
303 @check_messages('function-redefined')
304 def visit_class(self, node):
305 self._check_redefinition('class', node)
306
307 @check_messages('init-is-generator', 'return-in-init',
308 'function-redefined', 'return-arg-in-generator',
309 'duplicate-argument-name')
310 def visit_function(self, node):
311 if not redefined_by_decorator(node):
312 self._check_redefinition(node.is_method() and 'method' or 'function' , node)
313 # checks for max returns, branch, return in __init__
314 returns = node.nodes_of_class(astroid.Return,
315 skip_klass=(astroid.Function, astroid.Clas s))
316 if node.is_method() and node.name == '__init__':
317 if node.is_generator():
318 self.add_message('init-is-generator', node=node)
319 else:
320 values = [r.value for r in returns]
321 # Are we returning anything but None from constructors
322 if [v for v in values
323 if not (v is None or
324 (isinstance(v, astroid.Const) and v.value is Non e) or
325 (isinstance(v, astroid.Name) and v.name == 'Non e')
326 )]:
327 self.add_message('return-in-init', node=node)
328 elif node.is_generator():
329 # make sure we don't mix non-None returns and yields
330 if not PY33:
331 for retnode in returns:
332 if isinstance(retnode.value, astroid.Const) and \
333 retnode.value.value is not None:
334 self.add_message('return-arg-in-generator', node=node,
335 line=retnode.fromlineno)
336 # Check for duplicate names
337 args = set()
338 for name in node.argnames():
339 if name in args:
340 self.add_message('duplicate-argument-name', node=node, args=(nam e,))
341 else:
342 args.add(name)
343
344
345 @check_messages('return-outside-function')
346 def visit_return(self, node):
347 if not isinstance(node.frame(), astroid.Function):
348 self.add_message('return-outside-function', node=node)
349
350 @check_messages('yield-outside-function')
351 def visit_yield(self, node):
352 if not isinstance(node.frame(), (astroid.Function, astroid.Lambda)):
353 self.add_message('yield-outside-function', node=node)
354
355 @check_messages('not-in-loop')
356 def visit_continue(self, node):
357 self._check_in_loop(node, 'continue')
358
359 @check_messages('not-in-loop')
360 def visit_break(self, node):
361 self._check_in_loop(node, 'break')
362
363 @check_messages('useless-else-on-loop')
364 def visit_for(self, node):
365 self._check_else_on_loop(node)
366
367 @check_messages('useless-else-on-loop')
368 def visit_while(self, node):
369 self._check_else_on_loop(node)
370
371 @check_messages('nonexistent-operator')
372 def visit_unaryop(self, node):
373 """check use of the non-existent ++ and -- operator operator"""
374 if ((node.op in '+-') and
375 isinstance(node.operand, astroid.UnaryOp) and
376 (node.operand.op == node.op)):
377 self.add_message('nonexistent-operator', node=node, args=node.op*2)
378
379 @check_messages('abstract-class-instantiated')
380 def visit_callfunc(self, node):
381 """ Check instantiating abstract class with
382 abc.ABCMeta as metaclass.
383 """
384 try:
385 infered = next(node.func.infer())
386 except astroid.InferenceError:
387 return
388 if not isinstance(infered, astroid.Class):
389 return
390 # __init__ was called
391 metaclass = infered.metaclass()
392 abstract_methods = _has_abstract_methods(infered)
393 if metaclass is None:
394 # Python 3.4 has `abc.ABC`, which won't be detected
395 # by ClassNode.metaclass()
396 for ancestor in infered.ancestors():
397 if ancestor.qname() == 'abc.ABC' and abstract_methods:
398 self.add_message('abstract-class-instantiated',
399 args=(infered.name, ),
400 node=node)
401 break
402 return
403 if metaclass.qname() == 'abc.ABCMeta' and abstract_methods:
404 self.add_message('abstract-class-instantiated',
405 args=(infered.name, ),
406 node=node)
407
408 def _check_else_on_loop(self, node):
409 """Check that any loop with an else clause has a break statement."""
410 if node.orelse and not _loop_exits_early(node):
411 self.add_message('useless-else-on-loop', node=node,
412 # This is not optimal, but the line previous
413 # to the first statement in the else clause
414 # will usually be the one that contains the else:.
415 line=node.orelse[0].lineno - 1)
416
417 def _check_in_loop(self, node, node_name):
418 """check that a node is inside a for or while loop"""
419 _node = node.parent
420 while _node:
421 if isinstance(_node, (astroid.For, astroid.While)):
422 break
423 _node = _node.parent
424 else:
425 self.add_message('not-in-loop', node=node, args=node_name)
426
427 def _check_redefinition(self, redeftype, node):
428 """check for redefinition of a function / method / class name"""
429 defined_self = node.parent.frame()[node.name]
430 if defined_self is not node and not are_exclusive(node, defined_self):
431 self.add_message('function-redefined', node=node,
432 args=(redeftype, defined_self.fromlineno))
433
434
435
436 class BasicChecker(_BasicChecker):
437 """checks for :
438 * doc strings
439 * number of arguments, local variables, branches, returns and statements in
440 functions, methods
441 * required module attributes
442 * dangerous default values as arguments
443 * redefinition of function / method / class
444 * uses of the global statement
445 """
446
447 __implements__ = IAstroidChecker
448
449 name = 'basic'
450 msgs = {
451 'W0101': ('Unreachable code',
452 'unreachable',
453 'Used when there is some code behind a "return" or "raise" '
454 'statement, which will never be accessed.'),
455 'W0102': ('Dangerous default value %s as argument',
456 'dangerous-default-value',
457 'Used when a mutable value as list or dictionary is detected i n '
458 'a default value for an argument.'),
459 'W0104': ('Statement seems to have no effect',
460 'pointless-statement',
461 'Used when a statement doesn\'t have (or at least seems to) '
462 'any effect.'),
463 'W0105': ('String statement has no effect',
464 'pointless-string-statement',
465 'Used when a string is used as a statement (which of course '
466 'has no effect). This is a particular case of W0104 with its '
467 'own message so you can easily disable it if you\'re using '
468 'those strings as documentation, instead of comments.'),
469 'W0106': ('Expression "%s" is assigned to nothing',
470 'expression-not-assigned',
471 'Used when an expression that is not a function call is assign ed '
472 'to nothing. Probably something else was intended.'),
473 'W0108': ('Lambda may not be necessary',
474 'unnecessary-lambda',
475 'Used when the body of a lambda expression is a function call '
476 'on the same argument list as the lambda itself; such lambda '
477 'expressions are in all but a few cases replaceable with the '
478 'function being called in the body of the lambda.'),
479 'W0109': ("Duplicate key %r in dictionary",
480 'duplicate-key',
481 'Used when a dictionary expression binds the same key multiple '
482 'times.'),
483 'W0122': ('Use of exec',
484 'exec-used',
485 'Used when you use the "exec" statement (function for Python '
486 '3), to discourage its usage. That doesn\'t '
487 'mean you can not use it !'),
488 'W0123': ('Use of eval',
489 'eval-used',
490 'Used when you use the "eval" function, to discourage its '
491 'usage. Consider using `ast.literal_eval` for safely evaluatin g '
492 'strings containing Python expressions '
493 'from untrusted sources. '),
494 'W0141': ('Used builtin function %r',
495 'bad-builtin',
496 'Used when a black listed builtin function is used (see the '
497 'bad-function option). Usual black listed functions are the on es '
498 'like map, or filter , where Python offers now some cleaner '
499 'alternative like list comprehension.'),
500 'W0142': ('Used * or ** magic',
501 'star-args',
502 'Used when a function or method is called using `*args` or '
503 '`**kwargs` to dispatch arguments. This doesn\'t improve '
504 'readability and should be used with care.'),
505 'W0150': ("%s statement in finally block may swallow exception",
506 'lost-exception',
507 'Used when a break or a return statement is found inside the '
508 'finally clause of a try...finally block: the exceptions raise d '
509 'in the try clause will be silently swallowed instead of being '
510 're-raised.'),
511 'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?',
512 'assert-on-tuple',
513 'A call of assert on a tuple will always evaluate to true if '
514 'the tuple is not empty, and will always evaluate to false if '
515 'it is.'),
516 'C0121': ('Missing required attribute "%s"', # W0103
517 'missing-module-attribute',
518 'Used when an attribute required for modules is missing.'),
519
520 'E0109': ('Missing argument to reversed()',
521 'missing-reversed-argument',
522 'Used when reversed() builtin didn\'t receive an argument.'),
523 'E0111': ('The first reversed() argument is not a sequence',
524 'bad-reversed-sequence',
525 'Used when the first argument to reversed() builtin '
526 'isn\'t a sequence (does not implement __reversed__, '
527 'nor __getitem__ and __len__'),
528
529 }
530
531 options = (('required-attributes',
532 {'default' : (), 'type' : 'csv',
533 'metavar' : '<attributes>',
534 'help' : 'Required attributes for module, separated by a '
535 'comma'}
536 ),
537 ('bad-functions',
538 {'default' : BAD_FUNCTIONS,
539 'type' :'csv', 'metavar' : '<builtin function names>',
540 'help' : 'List of builtins function names that should not be '
541 'used, separated by a comma'}
542 ),
543 )
544 reports = (('RP0101', 'Statistics by type', report_by_type_stats),)
545
546 def __init__(self, linter):
547 _BasicChecker.__init__(self, linter)
548 self.stats = None
549 self._tryfinallys = None
550
551 def open(self):
552 """initialize visit variables and statistics
553 """
554 self._tryfinallys = []
555 self.stats = self.linter.add_stats(module=0, function=0,
556 method=0, class_=0)
557
558 @check_messages('missing-module-attribute')
559 def visit_module(self, node):
560 """check module name, docstring and required arguments
561 """
562 self.stats['module'] += 1
563 for attr in self.config.required_attributes:
564 if attr not in node:
565 self.add_message('missing-module-attribute', node=node, args=att r)
566
567 def visit_class(self, node): # pylint: disable=unused-argument
568 """check module name, docstring and redefinition
569 increment branch counter
570 """
571 self.stats['class'] += 1
572
573 @check_messages('pointless-statement', 'pointless-string-statement',
574 'expression-not-assigned')
575 def visit_discard(self, node):
576 """check for various kind of statements without effect"""
577 expr = node.value
578 if isinstance(expr, astroid.Const) and isinstance(expr.value,
579 six.string_types):
580 # treat string statement in a separated message
581 # Handle PEP-257 attribute docstrings.
582 # An attribute docstring is defined as being a string right after
583 # an assignment at the module level, class level or __init__ level.
584 scope = expr.scope()
585 if isinstance(scope, (astroid.Class, astroid.Module, astroid.Functio n)):
586 if isinstance(scope, astroid.Function) and scope.name != '__init __':
587 pass
588 else:
589 sibling = expr.previous_sibling()
590 if (sibling is not None and sibling.scope() is scope and
591 isinstance(sibling, astroid.Assign)):
592 return
593 self.add_message('pointless-string-statement', node=node)
594 return
595 # ignore if this is :
596 # * a direct function call
597 # * the unique child of a try/except body
598 # * a yield (which are wrapped by a discard node in _ast XXX)
599 # warn W0106 if we have any underlying function call (we can't predict
600 # side effects), else pointless-statement
601 if (isinstance(expr, (astroid.Yield, astroid.CallFunc)) or
602 (isinstance(node.parent, astroid.TryExcept) and
603 node.parent.body == [node])):
604 return
605 if any(expr.nodes_of_class(astroid.CallFunc)):
606 self.add_message('expression-not-assigned', node=node,
607 args=expr.as_string())
608 else:
609 self.add_message('pointless-statement', node=node)
610
611 @check_messages('unnecessary-lambda')
612 def visit_lambda(self, node):
613 """check whether or not the lambda is suspicious
614 """
615 # if the body of the lambda is a call expression with the same
616 # argument list as the lambda itself, then the lambda is
617 # possibly unnecessary and at least suspicious.
618 if node.args.defaults:
619 # If the arguments of the lambda include defaults, then a
620 # judgment cannot be made because there is no way to check
621 # that the defaults defined by the lambda are the same as
622 # the defaults defined by the function called in the body
623 # of the lambda.
624 return
625 call = node.body
626 if not isinstance(call, astroid.CallFunc):
627 # The body of the lambda must be a function call expression
628 # for the lambda to be unnecessary.
629 return
630 # XXX are lambda still different with astroid >= 0.18 ?
631 # *args and **kwargs need to be treated specially, since they
632 # are structured differently between the lambda and the function
633 # call (in the lambda they appear in the args.args list and are
634 # indicated as * and ** by two bits in the lambda's flags, but
635 # in the function call they are omitted from the args list and
636 # are indicated by separate attributes on the function call node).
637 ordinary_args = list(node.args.args)
638 if node.args.kwarg:
639 if (not call.kwargs
640 or not isinstance(call.kwargs, astroid.Name)
641 or node.args.kwarg != call.kwargs.name):
642 return
643 elif call.kwargs:
644 return
645 if node.args.vararg:
646 if (not call.starargs
647 or not isinstance(call.starargs, astroid.Name)
648 or node.args.vararg != call.starargs.name):
649 return
650 elif call.starargs:
651 return
652 # The "ordinary" arguments must be in a correspondence such that:
653 # ordinary_args[i].name == call.args[i].name.
654 if len(ordinary_args) != len(call.args):
655 return
656 for i in range(len(ordinary_args)):
657 if not isinstance(call.args[i], astroid.Name):
658 return
659 if node.args.args[i].name != call.args[i].name:
660 return
661 if (isinstance(node.body.func, astroid.Getattr) and
662 isinstance(node.body.func.expr, astroid.CallFunc)):
663 # Chained call, the intermediate call might
664 # return something else (but we don't check that, yet).
665 return
666 self.add_message('unnecessary-lambda', line=node.fromlineno, node=node)
667
668 @check_messages('dangerous-default-value')
669 def visit_function(self, node):
670 """check function name, docstring, arguments, redefinition,
671 variable names, max locals
672 """
673 self.stats[node.is_method() and 'method' or 'function'] += 1
674 self._check_dangerous_default(node)
675
676 def _check_dangerous_default(self, node):
677 # check for dangerous default values as arguments
678 is_iterable = lambda n: isinstance(n, (astroid.List,
679 astroid.Set,
680 astroid.Dict))
681 for default in node.args.defaults:
682 try:
683 value = next(default.infer())
684 except astroid.InferenceError:
685 continue
686
687 if (isinstance(value, astroid.Instance) and
688 value.qname() in DEFAULT_ARGUMENT_SYMBOLS):
689
690 if value is default:
691 msg = DEFAULT_ARGUMENT_SYMBOLS[value.qname()]
692 elif type(value) is astroid.Instance or is_iterable(value):
693 # We are here in the following situation(s):
694 # * a dict/set/list/tuple call which wasn't inferred
695 # to a syntax node ({}, () etc.). This can happen
696 # when the arguments are invalid or unknown to
697 # the inference.
698 # * a variable from somewhere else, which turns out to be a list
699 # or a dict.
700 if is_iterable(default):
701 msg = value.pytype()
702 elif isinstance(default, astroid.CallFunc):
703 msg = '%s() (%s)' % (value.name, value.qname())
704 else:
705 msg = '%s (%s)' % (default.as_string(), value.qname())
706 else:
707 # this argument is a name
708 msg = '%s (%s)' % (default.as_string(),
709 DEFAULT_ARGUMENT_SYMBOLS[value.qname()])
710 self.add_message('dangerous-default-value',
711 node=node,
712 args=(msg, ))
713
714 @check_messages('unreachable', 'lost-exception')
715 def visit_return(self, node):
716 """1 - check is the node has a right sibling (if so, that's some
717 unreachable code)
718 2 - check is the node is inside the finally clause of a try...finally
719 block
720 """
721 self._check_unreachable(node)
722 # Is it inside final body of a try...finally bloc ?
723 self._check_not_in_finally(node, 'return', (astroid.Function,))
724
725 @check_messages('unreachable')
726 def visit_continue(self, node):
727 """check is the node has a right sibling (if so, that's some unreachable
728 code)
729 """
730 self._check_unreachable(node)
731
732 @check_messages('unreachable', 'lost-exception')
733 def visit_break(self, node):
734 """1 - check is the node has a right sibling (if so, that's some
735 unreachable code)
736 2 - check is the node is inside the finally clause of a try...finally
737 block
738 """
739 # 1 - Is it right sibling ?
740 self._check_unreachable(node)
741 # 2 - Is it inside final body of a try...finally bloc ?
742 self._check_not_in_finally(node, 'break', (astroid.For, astroid.While,))
743
744 @check_messages('unreachable')
745 def visit_raise(self, node):
746 """check if the node has a right sibling (if so, that's some unreachable
747 code)
748 """
749 self._check_unreachable(node)
750
751 @check_messages('exec-used')
752 def visit_exec(self, node):
753 """just print a warning on exec statements"""
754 self.add_message('exec-used', node=node)
755
756 @check_messages('bad-builtin', 'star-args', 'eval-used',
757 'exec-used', 'missing-reversed-argument',
758 'bad-reversed-sequence')
759 def visit_callfunc(self, node):
760 """visit a CallFunc node -> check if this is not a blacklisted builtin
761 call and check for * or ** use
762 """
763 if isinstance(node.func, astroid.Name):
764 name = node.func.name
765 # ignore the name if it's not a builtin (i.e. not defined in the
766 # locals nor globals scope)
767 if not (name in node.frame() or
768 name in node.root()):
769 if name == 'exec':
770 self.add_message('exec-used', node=node)
771 elif name == 'reversed':
772 self._check_reversed(node)
773 elif name == 'eval':
774 self.add_message('eval-used', node=node)
775 if name in self.config.bad_functions:
776 self.add_message('bad-builtin', node=node, args=name)
777 if node.starargs or node.kwargs:
778 scope = node.scope()
779 if isinstance(scope, astroid.Function):
780 toprocess = [(n, vn) for (n, vn) in ((node.starargs, scope.args. vararg),
781 (node.kwargs, scope.args.kw arg)) if n]
782 if toprocess:
783 for cfnode, fargname in toprocess[:]:
784 if getattr(cfnode, 'name', None) == fargname:
785 toprocess.remove((cfnode, fargname))
786 if not toprocess:
787 return # star-args can be skipped
788 self.add_message('star-args', node=node.func)
789
790 @check_messages('assert-on-tuple')
791 def visit_assert(self, node):
792 """check the use of an assert statement on a tuple."""
793 if node.fail is None and isinstance(node.test, astroid.Tuple) and \
794 len(node.test.elts) == 2:
795 self.add_message('assert-on-tuple', node=node)
796
797 @check_messages('duplicate-key')
798 def visit_dict(self, node):
799 """check duplicate key in dictionary"""
800 keys = set()
801 for k, _ in node.items:
802 if isinstance(k, astroid.Const):
803 key = k.value
804 if key in keys:
805 self.add_message('duplicate-key', node=node, args=key)
806 keys.add(key)
807
808 def visit_tryfinally(self, node):
809 """update try...finally flag"""
810 self._tryfinallys.append(node)
811
812 def leave_tryfinally(self, node): # pylint: disable=unused-argument
813 """update try...finally flag"""
814 self._tryfinallys.pop()
815
816 def _check_unreachable(self, node):
817 """check unreachable code"""
818 unreach_stmt = node.next_sibling()
819 if unreach_stmt is not None:
820 self.add_message('unreachable', node=unreach_stmt)
821
822 def _check_not_in_finally(self, node, node_name, breaker_classes=()):
823 """check that a node is not inside a finally clause of a
824 try...finally statement.
825 If we found before a try...finally bloc a parent which its type is
826 in breaker_classes, we skip the whole check."""
827 # if self._tryfinallys is empty, we're not a in try...finally bloc
828 if not self._tryfinallys:
829 return
830 # the node could be a grand-grand...-children of the try...finally
831 _parent = node.parent
832 _node = node
833 while _parent and not isinstance(_parent, breaker_classes):
834 if hasattr(_parent, 'finalbody') and _node in _parent.finalbody:
835 self.add_message('lost-exception', node=node, args=node_name)
836 return
837 _node = _parent
838 _parent = _node.parent
839
840 def _check_reversed(self, node):
841 """ check that the argument to `reversed` is a sequence """
842 try:
843 argument = safe_infer(get_argument_from_call(node, position=0))
844 except NoSuchArgumentError:
845 self.add_message('missing-reversed-argument', node=node)
846 else:
847 if argument is astroid.YES:
848 return
849 if argument is None:
850 # Nothing was infered.
851 # Try to see if we have iter().
852 if isinstance(node.args[0], astroid.CallFunc):
853 try:
854 func = next(node.args[0].func.infer())
855 except InferenceError:
856 return
857 if (getattr(func, 'name', None) == 'iter' and
858 is_builtin_object(func)):
859 self.add_message('bad-reversed-sequence', node=node)
860 return
861
862 if isinstance(argument, astroid.Instance):
863 if (argument._proxied.name == 'dict' and
864 is_builtin_object(argument._proxied)):
865 self.add_message('bad-reversed-sequence', node=node)
866 return
867 elif any(ancestor.name == 'dict' and is_builtin_object(ancestor)
868 for ancestor in argument._proxied.ancestors()):
869 # mappings aren't accepted by reversed()
870 self.add_message('bad-reversed-sequence', node=node)
871 return
872
873 for methods in REVERSED_METHODS:
874 for meth in methods:
875 try:
876 argument.getattr(meth)
877 except astroid.NotFoundError:
878 break
879 else:
880 break
881 else:
882 # Check if it is a .deque. It doesn't seem that
883 # we can retrieve special methods
884 # from C implemented constructs.
885 if argument._proxied.qname().endswith(".deque"):
886 return
887 self.add_message('bad-reversed-sequence', node=node)
888 elif not isinstance(argument, (astroid.List, astroid.Tuple)):
889 # everything else is not a proper sequence for reversed()
890 self.add_message('bad-reversed-sequence', node=node)
891
892 _NAME_TYPES = {
893 'module': (MOD_NAME_RGX, 'module'),
894 'const': (CONST_NAME_RGX, 'constant'),
895 'class': (CLASS_NAME_RGX, 'class'),
896 'function': (DEFAULT_NAME_RGX, 'function'),
897 'method': (DEFAULT_NAME_RGX, 'method'),
898 'attr': (DEFAULT_NAME_RGX, 'attribute'),
899 'argument': (DEFAULT_NAME_RGX, 'argument'),
900 'variable': (DEFAULT_NAME_RGX, 'variable'),
901 'class_attribute': (CLASS_ATTRIBUTE_RGX, 'class attribute'),
902 'inlinevar': (COMP_VAR_RGX, 'inline iteration'),
903 }
904
905 def _create_naming_options():
906 name_options = []
907 for name_type, (rgx, human_readable_name) in six.iteritems(_NAME_TYPES):
908 name_type = name_type.replace('_', '-')
909 name_options.append((
910 '%s-rgx' % (name_type,),
911 {'default': rgx, 'type': 'regexp', 'metavar': '<regexp>',
912 'help': 'Regular expression matching correct %s names' % (human_rea dable_name,)}))
913 name_options.append((
914 '%s-name-hint' % (name_type,),
915 {'default': rgx.pattern, 'type': 'string', 'metavar': '<string>',
916 'help': 'Naming hint for %s names' % (human_readable_name,)}))
917 return tuple(name_options)
918
919 class NameChecker(_BasicChecker):
920 msgs = {
921 'C0102': ('Black listed name "%s"',
922 'blacklisted-name',
923 'Used when the name is listed in the black list (unauthorized '
924 'names).'),
925 'C0103': ('Invalid %s name "%s"%s',
926 'invalid-name',
927 'Used when the name doesn\'t match the regular expression '
928 'associated to its type (constant, variable, class...).'),
929 }
930
931 options = (('good-names',
932 {'default' : ('i', 'j', 'k', 'ex', 'Run', '_'),
933 'type' :'csv', 'metavar' : '<names>',
934 'help' : 'Good variable names which should always be accepted,'
935 ' separated by a comma'}
936 ),
937 ('bad-names',
938 {'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'),
939 'type' :'csv', 'metavar' : '<names>',
940 'help' : 'Bad variable names which should always be refused, '
941 'separated by a comma'}
942 ),
943 ('name-group',
944 {'default' : (),
945 'type' :'csv', 'metavar' : '<name1:name2>',
946 'help' : ('Colon-delimited sets of names that determine each'
947 ' other\'s naming style when the name regexes'
948 ' allow several styles.')}
949 ),
950 ('include-naming-hint',
951 {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
952 'help': 'Include a hint for the correct naming format with inva lid-name'}
953 ),
954 ) + _create_naming_options()
955
956
957 def __init__(self, linter):
958 _BasicChecker.__init__(self, linter)
959 self._name_category = {}
960 self._name_group = {}
961 self._bad_names = {}
962
963 def open(self):
964 self.stats = self.linter.add_stats(badname_module=0,
965 badname_class=0, badname_function=0,
966 badname_method=0, badname_attr=0,
967 badname_const=0,
968 badname_variable=0,
969 badname_inlinevar=0,
970 badname_argument=0,
971 badname_class_attribute=0)
972 for group in self.config.name_group:
973 for name_type in group.split(':'):
974 self._name_group[name_type] = 'group_%s' % (group,)
975
976 @check_messages('blacklisted-name', 'invalid-name')
977 def visit_module(self, node):
978 self._check_name('module', node.name.split('.')[-1], node)
979 self._bad_names = {}
980
981 def leave_module(self, node): # pylint: disable=unused-argument
982 for all_groups in six.itervalues(self._bad_names):
983 if len(all_groups) < 2:
984 continue
985 groups = collections.defaultdict(list)
986 min_warnings = sys.maxsize
987 for group in six.itervalues(all_groups):
988 groups[len(group)].append(group)
989 min_warnings = min(len(group), min_warnings)
990 if len(groups[min_warnings]) > 1:
991 by_line = sorted(groups[min_warnings],
992 key=lambda group: min(warning[0].lineno for war ning in group))
993 warnings = itertools.chain(*by_line[1:])
994 else:
995 warnings = groups[min_warnings][0]
996 for args in warnings:
997 self._raise_name_warning(*args)
998
999 @check_messages('blacklisted-name', 'invalid-name')
1000 def visit_class(self, node):
1001 self._check_name('class', node.name, node)
1002 for attr, anodes in six.iteritems(node.instance_attrs):
1003 if not list(node.instance_attr_ancestors(attr)):
1004 self._check_name('attr', attr, anodes[0])
1005
1006 @check_messages('blacklisted-name', 'invalid-name')
1007 def visit_function(self, node):
1008 # Do not emit any warnings if the method is just an implementation
1009 # of a base class method.
1010 confidence = HIGH
1011 if node.is_method():
1012 if overrides_a_method(node.parent.frame(), node.name):
1013 return
1014 confidence = (INFERENCE if has_known_bases(node.parent.frame())
1015 else INFERENCE_FAILURE)
1016
1017 self._check_name(_determine_function_name_type(node),
1018 node.name, node, confidence)
1019 # Check argument names
1020 args = node.args.args
1021 if args is not None:
1022 self._recursive_check_names(args, node)
1023
1024 @check_messages('blacklisted-name', 'invalid-name')
1025 def visit_global(self, node):
1026 for name in node.names:
1027 self._check_name('const', name, node)
1028
1029 @check_messages('blacklisted-name', 'invalid-name')
1030 def visit_assname(self, node):
1031 """check module level assigned names"""
1032 frame = node.frame()
1033 ass_type = node.ass_type()
1034 if isinstance(ass_type, astroid.Comprehension):
1035 self._check_name('inlinevar', node.name, node)
1036 elif isinstance(frame, astroid.Module):
1037 if isinstance(ass_type, astroid.Assign) and not in_loop(ass_type):
1038 if isinstance(safe_infer(ass_type.value), astroid.Class):
1039 self._check_name('class', node.name, node)
1040 else:
1041 if not _redefines_import(node):
1042 # Don't emit if the name redefines an import
1043 # in an ImportError except handler.
1044 self._check_name('const', node.name, node)
1045 elif isinstance(ass_type, astroid.ExceptHandler):
1046 self._check_name('variable', node.name, node)
1047 elif isinstance(frame, astroid.Function):
1048 # global introduced variable aren't in the function locals
1049 if node.name in frame and node.name not in frame.argnames():
1050 if not _redefines_import(node):
1051 self._check_name('variable', node.name, node)
1052 elif isinstance(frame, astroid.Class):
1053 if not list(frame.local_attr_ancestors(node.name)):
1054 self._check_name('class_attribute', node.name, node)
1055
1056 def _recursive_check_names(self, args, node):
1057 """check names in a possibly recursive list <arg>"""
1058 for arg in args:
1059 if isinstance(arg, astroid.AssName):
1060 self._check_name('argument', arg.name, node)
1061 else:
1062 self._recursive_check_names(arg.elts, node)
1063
1064 def _find_name_group(self, node_type):
1065 return self._name_group.get(node_type, node_type)
1066
1067 def _raise_name_warning(self, node, node_type, name, confidence):
1068 type_label = _NAME_TYPES[node_type][1]
1069 hint = ''
1070 if self.config.include_naming_hint:
1071 hint = ' (hint: %s)' % (getattr(self.config, node_type + '_name_hint '))
1072 self.add_message('invalid-name', node=node, args=(type_label, name, hint ),
1073 confidence=confidence)
1074 self.stats['badname_' + node_type] += 1
1075
1076 def _check_name(self, node_type, name, node, confidence=HIGH):
1077 """check for a name using the type's regexp"""
1078 if is_inside_except(node):
1079 clobbering, _ = clobber_in_except(node)
1080 if clobbering:
1081 return
1082 if name in self.config.good_names:
1083 return
1084 if name in self.config.bad_names:
1085 self.stats['badname_' + node_type] += 1
1086 self.add_message('blacklisted-name', node=node, args=name)
1087 return
1088 regexp = getattr(self.config, node_type + '_rgx')
1089 match = regexp.match(name)
1090
1091 if _is_multi_naming_match(match, node_type, confidence):
1092 name_group = self._find_name_group(node_type)
1093 bad_name_group = self._bad_names.setdefault(name_group, {})
1094 warnings = bad_name_group.setdefault(match.lastgroup, [])
1095 warnings.append((node, node_type, name, confidence))
1096
1097 if match is None:
1098 self._raise_name_warning(node, node_type, name, confidence)
1099
1100
1101 class DocStringChecker(_BasicChecker):
1102 msgs = {
1103 'C0111': ('Missing %s docstring', # W0131
1104 'missing-docstring',
1105 'Used when a module, function, class or method has no docstrin g.'
1106 'Some special methods like __init__ doesn\'t necessary require a '
1107 'docstring.'),
1108 'C0112': ('Empty %s docstring', # W0132
1109 'empty-docstring',
1110 'Used when a module, function, class or method has an empty '
1111 'docstring (it would be too easy ;).'),
1112 }
1113 options = (('no-docstring-rgx',
1114 {'default' : NO_REQUIRED_DOC_RGX,
1115 'type' : 'regexp', 'metavar' : '<regexp>',
1116 'help' : 'Regular expression which should only match '
1117 'function or class names that do not require a '
1118 'docstring.'}
1119 ),
1120 ('docstring-min-length',
1121 {'default' : -1,
1122 'type' : 'int', 'metavar' : '<int>',
1123 'help': ('Minimum line length for functions/classes that'
1124 ' require docstrings, shorter ones are exempt.')}
1125 ),
1126 )
1127
1128
1129 def open(self):
1130 self.stats = self.linter.add_stats(undocumented_module=0,
1131 undocumented_function=0,
1132 undocumented_method=0,
1133 undocumented_class=0)
1134 @check_messages('missing-docstring', 'empty-docstring')
1135 def visit_module(self, node):
1136 self._check_docstring('module', node)
1137
1138 @check_messages('missing-docstring', 'empty-docstring')
1139 def visit_class(self, node):
1140 if self.config.no_docstring_rgx.match(node.name) is None:
1141 self._check_docstring('class', node)
1142
1143 @check_messages('missing-docstring', 'empty-docstring')
1144 def visit_function(self, node):
1145 if self.config.no_docstring_rgx.match(node.name) is None:
1146 ftype = node.is_method() and 'method' or 'function'
1147 if isinstance(node.parent.frame(), astroid.Class):
1148 overridden = False
1149 confidence = (INFERENCE if has_known_bases(node.parent.frame())
1150 else INFERENCE_FAILURE)
1151 # check if node is from a method overridden by its ancestor
1152 for ancestor in node.parent.frame().ancestors():
1153 if node.name in ancestor and \
1154 isinstance(ancestor[node.name], astroid.Function):
1155 overridden = True
1156 break
1157 self._check_docstring(ftype, node,
1158 report_missing=not overridden,
1159 confidence=confidence)
1160 else:
1161 self._check_docstring(ftype, node)
1162
1163 def _check_docstring(self, node_type, node, report_missing=True,
1164 confidence=HIGH):
1165 """check the node has a non empty docstring"""
1166 docstring = node.doc
1167 if docstring is None:
1168 if not report_missing:
1169 return
1170 if node.body:
1171 lines = node.body[-1].lineno - node.body[0].lineno + 1
1172 else:
1173 lines = 0
1174 max_lines = self.config.docstring_min_length
1175
1176 if node_type != 'module' and max_lines > -1 and lines < max_lines:
1177 return
1178 self.stats['undocumented_'+node_type] += 1
1179 if (node.body and isinstance(node.body[0], astroid.Discard) and
1180 isinstance(node.body[0].value, astroid.CallFunc)):
1181 # Most likely a string with a format call. Let's see.
1182 func = safe_infer(node.body[0].value.func)
1183 if (isinstance(func, astroid.BoundMethod)
1184 and isinstance(func.bound, astroid.Instance)):
1185 # Strings in Python 3, others in Python 2.
1186 if PY3K and func.bound.name == 'str':
1187 return
1188 elif func.bound.name in ('str', 'unicode', 'bytes'):
1189 return
1190 self.add_message('missing-docstring', node=node, args=(node_type,),
1191 confidence=confidence)
1192 elif not docstring.strip():
1193 self.stats['undocumented_'+node_type] += 1
1194 self.add_message('empty-docstring', node=node, args=(node_type,),
1195 confidence=confidence)
1196
1197
1198 class PassChecker(_BasicChecker):
1199 """check if the pass statement is really necessary"""
1200 msgs = {'W0107': ('Unnecessary pass statement',
1201 'unnecessary-pass',
1202 'Used when a "pass" statement that can be avoided is '
1203 'encountered.'),
1204 }
1205 @check_messages('unnecessary-pass')
1206 def visit_pass(self, node):
1207 if len(node.parent.child_sequence(node)) > 1:
1208 self.add_message('unnecessary-pass', node=node)
1209
1210
1211 class LambdaForComprehensionChecker(_BasicChecker):
1212 """check for using a lambda where a comprehension would do.
1213
1214 See <http://www.artima.com/weblogs/viewpost.jsp?thread=98196>
1215 where GvR says comprehensions would be clearer.
1216 """
1217
1218 msgs = {'W0110': ('map/filter on lambda could be replaced by comprehension',
1219 'deprecated-lambda',
1220 'Used when a lambda is the first argument to "map" or '
1221 '"filter". It could be clearer as a list '
1222 'comprehension or generator expression.',
1223 {'maxversion': (3, 0)}),
1224 }
1225
1226 @check_messages('deprecated-lambda')
1227 def visit_callfunc(self, node):
1228 """visit a CallFunc node, check if map or filter are called with a
1229 lambda
1230 """
1231 if not node.args:
1232 return
1233 if not isinstance(node.args[0], astroid.Lambda):
1234 return
1235 infered = safe_infer(node.func)
1236 if (is_builtin_object(infered)
1237 and infered.name in ['map', 'filter']):
1238 self.add_message('deprecated-lambda', node=node)
1239
1240
1241 def register(linter):
1242 """required method to auto register this checker"""
1243 linter.register_checker(BasicErrorChecker(linter))
1244 linter.register_checker(BasicChecker(linter))
1245 linter.register_checker(NameChecker(linter))
1246 linter.register_checker(DocStringChecker(linter))
1247 linter.register_checker(PassChecker(linter))
1248 linter.register_checker(LambdaForComprehensionChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/pylint/checkers/__init__.py ('k') | third_party/pylint/pylint/checkers/classes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698