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/checkers/base.py

Issue 876793002: pylint: upgrade to 1.4.1 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 5 years, 11 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
« no previous file with comments | « third_party/pylint/__pkginfo__.py ('k') | third_party/pylint/checkers/classes.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-2013 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # Copyright (c) 2009-2010 Arista Networks, Inc. 3 # Copyright (c) 2009-2010 Arista Networks, Inc.
4 # 4 #
5 # This program is free software; you can redistribute it and/or modify it under 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 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 7 # Foundation; either version 2 of the License, or (at your option) any later
8 # version. 8 # version.
9 # 9 #
10 # This program is distributed in the hope that it will be useful, but WITHOUT 10 # This program is distributed in the hope that it will be useful, but WITHOUT
(...skipping 27 matching lines...) Expand all
38 check_messages, 38 check_messages,
39 clobber_in_except, 39 clobber_in_except,
40 is_builtin_object, 40 is_builtin_object,
41 is_inside_except, 41 is_inside_except,
42 overrides_a_method, 42 overrides_a_method,
43 safe_infer, 43 safe_infer,
44 get_argument_from_call, 44 get_argument_from_call,
45 has_known_bases, 45 has_known_bases,
46 NoSuchArgumentError, 46 NoSuchArgumentError,
47 is_import_error, 47 is_import_error,
48 unimplemented_abstract_methods,
48 ) 49 )
49 50
50 51
51 # regex for class/function/variable/constant name 52 # regex for class/function/variable/constant name
52 CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$') 53 CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$')
53 MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$') 54 MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$')
54 CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$') 55 CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$')
55 COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$') 56 COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$')
56 DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$') 57 DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
57 CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$') 58 CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$')
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 return (match is not None and 142 return (match is not None and
142 match.lastgroup is not None and 143 match.lastgroup is not None and
143 match.lastgroup not in EXEMPT_NAME_CATEGORIES 144 match.lastgroup not in EXEMPT_NAME_CATEGORIES
144 and (node_type != 'method' or confidence != INFERENCE_FAILURE)) 145 and (node_type != 'method' or confidence != INFERENCE_FAILURE))
145 146
146 147
147 if sys.version_info < (3, 0): 148 if sys.version_info < (3, 0):
148 PROPERTY_CLASSES = set(('__builtin__.property', 'abc.abstractproperty')) 149 PROPERTY_CLASSES = set(('__builtin__.property', 'abc.abstractproperty'))
149 else: 150 else:
150 PROPERTY_CLASSES = set(('builtins.property', 'abc.abstractproperty')) 151 PROPERTY_CLASSES = set(('builtins.property', 'abc.abstractproperty'))
151 ABC_METHODS = set(('abc.abstractproperty', 'abc.abstractmethod', 152
152 'abc.abstractclassmethod', 'abc.abstractstaticmethod'))
153 153
154 def _determine_function_name_type(node): 154 def _determine_function_name_type(node):
155 """Determine the name type whose regex the a function's name should match. 155 """Determine the name type whose regex the a function's name should match.
156 156
157 :param node: A function node. 157 :param node: A function node.
158 :returns: One of ('function', 'method', 'attr') 158 :returns: One of ('function', 'method', 'attr')
159 """ 159 """
160 if not node.is_method(): 160 if not node.is_method():
161 return 'function' 161 return 'function'
162 if node.decorators: 162 if node.decorators:
163 decorators = node.decorators.nodes 163 decorators = node.decorators.nodes
164 else: 164 else:
165 decorators = [] 165 decorators = []
166 for decorator in decorators: 166 for decorator in decorators:
167 # If the function is a property (decorated with @property 167 # If the function is a property (decorated with @property
168 # or @abc.abstractproperty), the name type is 'attr'. 168 # or @abc.abstractproperty), the name type is 'attr'.
169 if (isinstance(decorator, astroid.Name) or 169 if (isinstance(decorator, astroid.Name) or
170 (isinstance(decorator, astroid.Getattr) and 170 (isinstance(decorator, astroid.Getattr) and
171 decorator.attrname == 'abstractproperty')): 171 decorator.attrname == 'abstractproperty')):
172 infered = safe_infer(decorator) 172 infered = safe_infer(decorator)
173 if infered and infered.qname() in PROPERTY_CLASSES: 173 if infered and infered.qname() in PROPERTY_CLASSES:
174 return 'attr' 174 return 'attr'
175 # If the function is decorated using the prop_method.{setter,getter} 175 # If the function is decorated using the prop_method.{setter,getter}
176 # form, treat it like an attribute as well. 176 # form, treat it like an attribute as well.
177 elif (isinstance(decorator, astroid.Getattr) and 177 elif (isinstance(decorator, astroid.Getattr) and
178 decorator.attrname in ('setter', 'deleter')): 178 decorator.attrname in ('setter', 'deleter')):
179 return 'attr' 179 return 'attr'
180 return 'method' 180 return 'method'
181 181
182 def decorated_with_abc(func): 182
183 """ Determine if the `func` node is decorated 183
184 with `abc` decorators (abstractmethod et co.) 184 def _has_abstract_methods(node):
185 """ 185 """
186 if func.decorators: 186 Determine if the given `node` has abstract methods.
187 for node in func.decorators.nodes:
188 try:
189 infered = next(node.infer())
190 except InferenceError:
191 continue
192 if infered and infered.qname() in ABC_METHODS:
193 return True
194 187
195 def has_abstract_methods(node): 188 The methods should be made abstract by decorating them
189 with `abc` decorators.
196 """ 190 """
197 Determine if the given `node` has 191 return len(unimplemented_abstract_methods(node)) > 0
198 abstract methods, defined with `abc` module. 192
199 """
200 return any(decorated_with_abc(meth)
201 for meth in node.methods())
202 193
203 def report_by_type_stats(sect, stats, old_stats): 194 def report_by_type_stats(sect, stats, old_stats):
204 """make a report of 195 """make a report of
205 196
206 * percentage of different types documented 197 * percentage of different types documented
207 * percentage of different types with a bad name 198 * percentage of different types with a bad name
208 """ 199 """
209 # percentage of different types documented and/or with a bad name 200 # percentage of different types documented and/or with a bad name
210 nice_stats = {} 201 nice_stats = {}
211 for node_type in ('module', 'class', 'method', 'function'): 202 for node_type in ('module', 'class', 'method', 'function'):
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 '"yield" statements).', 282 '"yield" statements).',
292 {'maxversion': (3, 3)}), 283 {'maxversion': (3, 3)}),
293 'E0107': ("Use of the non-existent %s operator", 284 'E0107': ("Use of the non-existent %s operator",
294 'nonexistent-operator', 285 'nonexistent-operator',
295 "Used when you attempt to use the C-style pre-increment or" 286 "Used when you attempt to use the C-style pre-increment or"
296 "pre-decrement operator -- and ++, which doesn't exist in Pyth on."), 287 "pre-decrement operator -- and ++, which doesn't exist in Pyth on."),
297 'E0108': ('Duplicate argument name %s in function definition', 288 'E0108': ('Duplicate argument name %s in function definition',
298 'duplicate-argument-name', 289 'duplicate-argument-name',
299 'Duplicate argument names in function definitions are syntax' 290 'Duplicate argument names in function definitions are syntax'
300 ' errors.'), 291 ' errors.'),
301 'E0110': ('Abstract class with abstract methods instantiated', 292 'E0110': ('Abstract class %r with abstract methods instantiated',
302 'abstract-class-instantiated', 293 'abstract-class-instantiated',
303 'Used when an abstract class with `abc.ABCMeta` as metaclass ' 294 'Used when an abstract class with `abc.ABCMeta` as metaclass '
304 'has abstract methods and is instantiated.'), 295 'has abstract methods and is instantiated.'),
305 'W0120': ('Else clause on loop without a break statement', 296 'W0120': ('Else clause on loop without a break statement',
306 'useless-else-on-loop', 297 'useless-else-on-loop',
307 'Loops should only have an else clause if they can exit early ' 298 'Loops should only have an else clause if they can exit early '
308 'with a break statement, otherwise the statements under else ' 299 'with a break statement, otherwise the statements under else '
309 'should be on the same scope as the loop itself.'), 300 'should be on the same scope as the loop itself.'),
310 } 301 }
311 302
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 abc.ABCMeta as metaclass. 382 abc.ABCMeta as metaclass.
392 """ 383 """
393 try: 384 try:
394 infered = next(node.func.infer()) 385 infered = next(node.func.infer())
395 except astroid.InferenceError: 386 except astroid.InferenceError:
396 return 387 return
397 if not isinstance(infered, astroid.Class): 388 if not isinstance(infered, astroid.Class):
398 return 389 return
399 # __init__ was called 390 # __init__ was called
400 metaclass = infered.metaclass() 391 metaclass = infered.metaclass()
401 abstract_methods = has_abstract_methods(infered) 392 abstract_methods = _has_abstract_methods(infered)
402 if metaclass is None: 393 if metaclass is None:
403 # Python 3.4 has `abc.ABC`, which won't be detected 394 # Python 3.4 has `abc.ABC`, which won't be detected
404 # by ClassNode.metaclass() 395 # by ClassNode.metaclass()
405 for ancestor in infered.ancestors(): 396 for ancestor in infered.ancestors():
406 if ancestor.qname() == 'abc.ABC' and abstract_methods: 397 if ancestor.qname() == 'abc.ABC' and abstract_methods:
407 self.add_message('abstract-class-instantiated', node=node) 398 self.add_message('abstract-class-instantiated',
399 args=(infered.name, ),
400 node=node)
408 break 401 break
409 return 402 return
410 if metaclass.qname() == 'abc.ABCMeta' and abstract_methods: 403 if metaclass.qname() == 'abc.ABCMeta' and abstract_methods:
411 self.add_message('abstract-class-instantiated', node=node) 404 self.add_message('abstract-class-instantiated',
405 args=(infered.name, ),
406 node=node)
412 407
413 def _check_else_on_loop(self, node): 408 def _check_else_on_loop(self, node):
414 """Check that any loop with an else clause has a break statement.""" 409 """Check that any loop with an else clause has a break statement."""
415 if node.orelse and not _loop_exits_early(node): 410 if node.orelse and not _loop_exits_early(node):
416 self.add_message('useless-else-on-loop', node=node, 411 self.add_message('useless-else-on-loop', node=node,
417 # This is not optimal, but the line previous 412 # This is not optimal, but the line previous
418 # to the first statement in the else clause 413 # to the first statement in the else clause
419 # will usually be the one that contains the else:. 414 # will usually be the one that contains the else:.
420 line=node.orelse[0].lineno - 1) 415 line=node.orelse[0].lineno - 1)
421 416
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
669 # return something else (but we don't check that, yet). 664 # return something else (but we don't check that, yet).
670 return 665 return
671 self.add_message('unnecessary-lambda', line=node.fromlineno, node=node) 666 self.add_message('unnecessary-lambda', line=node.fromlineno, node=node)
672 667
673 @check_messages('dangerous-default-value') 668 @check_messages('dangerous-default-value')
674 def visit_function(self, node): 669 def visit_function(self, node):
675 """check function name, docstring, arguments, redefinition, 670 """check function name, docstring, arguments, redefinition,
676 variable names, max locals 671 variable names, max locals
677 """ 672 """
678 self.stats[node.is_method() and 'method' or 'function'] += 1 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):
679 # check for dangerous default values as arguments 677 # check for dangerous default values as arguments
678 is_iterable = lambda n: isinstance(n, (astroid.List,
679 astroid.Set,
680 astroid.Dict))
680 for default in node.args.defaults: 681 for default in node.args.defaults:
681 try: 682 try:
682 value = next(default.infer()) 683 value = next(default.infer())
683 except astroid.InferenceError: 684 except astroid.InferenceError:
684 continue 685 continue
685 686
686 if (isinstance(value, astroid.Instance) and 687 if (isinstance(value, astroid.Instance) and
687 value.qname() in DEFAULT_ARGUMENT_SYMBOLS): 688 value.qname() in DEFAULT_ARGUMENT_SYMBOLS):
689
688 if value is default: 690 if value is default:
689 msg = DEFAULT_ARGUMENT_SYMBOLS[value.qname()] 691 msg = DEFAULT_ARGUMENT_SYMBOLS[value.qname()]
690 elif type(value) is astroid.Instance: 692 elif type(value) is astroid.Instance or is_iterable(value):
691 if isinstance(default, astroid.CallFunc): 693 # We are here in the following situation(s):
692 # this argument is direct call to list() or dict() etc 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):
693 msg = '%s() (%s)' % (value.name, value.qname()) 703 msg = '%s() (%s)' % (value.name, value.qname())
694 else: 704 else:
695 # this argument is a variable from somewhere else which turns
696 # out to be a list or dict
697 msg = '%s (%s)' % (default.as_string(), value.qname()) 705 msg = '%s (%s)' % (default.as_string(), value.qname())
698 else: 706 else:
699 # this argument is a name 707 # this argument is a name
700 msg = '%s (%s)' % (default.as_string(), 708 msg = '%s (%s)' % (default.as_string(),
701 DEFAULT_ARGUMENT_SYMBOLS[value.qname()]) 709 DEFAULT_ARGUMENT_SYMBOLS[value.qname()])
702 self.add_message('dangerous-default-value', node=node, args=(msg ,)) 710 self.add_message('dangerous-default-value',
711 node=node,
712 args=(msg, ))
703 713
704 @check_messages('unreachable', 'lost-exception') 714 @check_messages('unreachable', 'lost-exception')
705 def visit_return(self, node): 715 def visit_return(self, node):
706 """1 - check is the node has a right sibling (if so, that's some 716 """1 - check is the node has a right sibling (if so, that's some
707 unreachable code) 717 unreachable code)
708 2 - check is the node is inside the finally clause of a try...finally 718 2 - check is the node is inside the finally clause of a try...finally
709 block 719 block
710 """ 720 """
711 self._check_unreachable(node) 721 self._check_unreachable(node)
712 # Is it inside final body of a try...finally bloc ? 722 # Is it inside final body of a try...finally bloc ?
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 1239
1230 1240
1231 def register(linter): 1241 def register(linter):
1232 """required method to auto register this checker""" 1242 """required method to auto register this checker"""
1233 linter.register_checker(BasicErrorChecker(linter)) 1243 linter.register_checker(BasicErrorChecker(linter))
1234 linter.register_checker(BasicChecker(linter)) 1244 linter.register_checker(BasicChecker(linter))
1235 linter.register_checker(NameChecker(linter)) 1245 linter.register_checker(NameChecker(linter))
1236 linter.register_checker(DocStringChecker(linter)) 1246 linter.register_checker(DocStringChecker(linter))
1237 linter.register_checker(PassChecker(linter)) 1247 linter.register_checker(PassChecker(linter))
1238 linter.register_checker(LambdaForComprehensionChecker(linter)) 1248 linter.register_checker(LambdaForComprehensionChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/__pkginfo__.py ('k') | third_party/pylint/checkers/classes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698