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

Side by Side Diff: third_party/pylint/pylint/checkers/utils.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 # pylint: disable=W0611
2 #
3 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
4 # http://www.logilab.fr/ -- mailto:contact@logilab.fr
5 #
6 # This program is free software; you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 """some functions that may be useful for various checkers
19 """
20
21 import re
22 import sys
23 import string
24
25 import astroid
26 from astroid import scoped_nodes
27 from logilab.common.compat import builtins
28
29 BUILTINS_NAME = builtins.__name__
30 COMP_NODE_TYPES = astroid.ListComp, astroid.SetComp, astroid.DictComp, astroid.G enExpr
31 PY3K = sys.version_info[0] == 3
32
33 if not PY3K:
34 EXCEPTIONS_MODULE = "exceptions"
35 else:
36 EXCEPTIONS_MODULE = "builtins"
37 ABC_METHODS = set(('abc.abstractproperty', 'abc.abstractmethod',
38 'abc.abstractclassmethod', 'abc.abstractstaticmethod'))
39
40
41 class NoSuchArgumentError(Exception):
42 pass
43
44 def is_inside_except(node):
45 """Returns true if node is inside the name of an except handler."""
46 current = node
47 while current and not isinstance(current.parent, astroid.ExceptHandler):
48 current = current.parent
49
50 return current and current is current.parent.name
51
52
53 def get_all_elements(node):
54 """Recursively returns all atoms in nested lists and tuples."""
55 if isinstance(node, (astroid.Tuple, astroid.List)):
56 for child in node.elts:
57 for e in get_all_elements(child):
58 yield e
59 else:
60 yield node
61
62
63 def clobber_in_except(node):
64 """Checks if an assignment node in an except handler clobbers an existing
65 variable.
66
67 Returns (True, args for W0623) if assignment clobbers an existing variable,
68 (False, None) otherwise.
69 """
70 if isinstance(node, astroid.AssAttr):
71 return (True, (node.attrname, 'object %r' % (node.expr.as_string(),)))
72 elif isinstance(node, astroid.AssName):
73 name = node.name
74 if is_builtin(name):
75 return (True, (name, 'builtins'))
76 else:
77 stmts = node.lookup(name)[1]
78 if (stmts and not isinstance(stmts[0].ass_type(),
79 (astroid.Assign, astroid.AugAssign,
80 astroid.ExceptHandler))):
81 return (True, (name, 'outer scope (line %s)' % stmts[0].fromline no))
82 return (False, None)
83
84
85 def safe_infer(node):
86 """return the inferred value for the given node.
87 Return None if inference failed or if there is some ambiguity (more than
88 one node has been inferred)
89 """
90 try:
91 inferit = node.infer()
92 value = next(inferit)
93 except astroid.InferenceError:
94 return
95 try:
96 next(inferit)
97 return # None if there is ambiguity on the inferred node
98 except astroid.InferenceError:
99 return # there is some kind of ambiguity
100 except StopIteration:
101 return value
102
103 def is_super(node):
104 """return True if the node is referencing the "super" builtin function
105 """
106 if getattr(node, 'name', None) == 'super' and \
107 node.root().name == BUILTINS_NAME:
108 return True
109 return False
110
111 def is_error(node):
112 """return true if the function does nothing but raising an exception"""
113 for child_node in node.get_children():
114 if isinstance(child_node, astroid.Raise):
115 return True
116 return False
117
118 def is_raising(body):
119 """return true if the given statement node raise an exception"""
120 for node in body:
121 if isinstance(node, astroid.Raise):
122 return True
123 return False
124
125 def is_empty(body):
126 """return true if the given node does nothing but 'pass'"""
127 return len(body) == 1 and isinstance(body[0], astroid.Pass)
128
129 builtins = builtins.__dict__.copy()
130 SPECIAL_BUILTINS = ('__builtins__',) # '__path__', '__file__')
131
132 def is_builtin_object(node):
133 """Returns True if the given node is an object from the __builtin__ module." ""
134 return node and node.root().name == BUILTINS_NAME
135
136 def is_builtin(name): # was is_native_builtin
137 """return true if <name> could be considered as a builtin defined by python
138 """
139 if name in builtins:
140 return True
141 if name in SPECIAL_BUILTINS:
142 return True
143 return False
144
145 def is_defined_before(var_node):
146 """return True if the variable node is defined by a parent node (list,
147 set, dict, or generator comprehension, lambda) or in a previous sibling
148 node on the same line (statement_defining ; statement_using)
149 """
150 varname = var_node.name
151 _node = var_node.parent
152 while _node:
153 if isinstance(_node, COMP_NODE_TYPES):
154 for ass_node in _node.nodes_of_class(astroid.AssName):
155 if ass_node.name == varname:
156 return True
157 elif isinstance(_node, astroid.For):
158 for ass_node in _node.target.nodes_of_class(astroid.AssName):
159 if ass_node.name == varname:
160 return True
161 elif isinstance(_node, astroid.With):
162 for expr, ids in _node.items:
163 if expr.parent_of(var_node):
164 break
165 if (ids and
166 isinstance(ids, astroid.AssName) and
167 ids.name == varname):
168 return True
169 elif isinstance(_node, (astroid.Lambda, astroid.Function)):
170 if _node.args.is_argument(varname):
171 return True
172 if getattr(_node, 'name', None) == varname:
173 return True
174 break
175 elif isinstance(_node, astroid.ExceptHandler):
176 if isinstance(_node.name, astroid.AssName):
177 ass_node = _node.name
178 if ass_node.name == varname:
179 return True
180 _node = _node.parent
181 # possibly multiple statements on the same line using semi colon separator
182 stmt = var_node.statement()
183 _node = stmt.previous_sibling()
184 lineno = stmt.fromlineno
185 while _node and _node.fromlineno == lineno:
186 for ass_node in _node.nodes_of_class(astroid.AssName):
187 if ass_node.name == varname:
188 return True
189 for imp_node in _node.nodes_of_class((astroid.From, astroid.Import)):
190 if varname in [name[1] or name[0] for name in imp_node.names]:
191 return True
192 _node = _node.previous_sibling()
193 return False
194
195 def is_func_default(node):
196 """return true if the given Name node is used in function default argument's
197 value
198 """
199 parent = node.scope()
200 if isinstance(parent, astroid.Function):
201 for default_node in parent.args.defaults:
202 for default_name_node in default_node.nodes_of_class(astroid.Name):
203 if default_name_node is node:
204 return True
205 return False
206
207 def is_func_decorator(node):
208 """return true if the name is used in function decorator"""
209 parent = node.parent
210 while parent is not None:
211 if isinstance(parent, astroid.Decorators):
212 return True
213 if (parent.is_statement or
214 isinstance(parent, astroid.Lambda) or
215 isinstance(parent, (scoped_nodes.ComprehensionScope,
216 scoped_nodes.ListComp))):
217 break
218 parent = parent.parent
219 return False
220
221 def is_ancestor_name(frame, node):
222 """return True if `frame` is a astroid.Class node with `node` in the
223 subtree of its bases attribute
224 """
225 try:
226 bases = frame.bases
227 except AttributeError:
228 return False
229 for base in bases:
230 if node in base.nodes_of_class(astroid.Name):
231 return True
232 return False
233
234 def assign_parent(node):
235 """return the higher parent which is not an AssName, Tuple or List node
236 """
237 while node and isinstance(node, (astroid.AssName,
238 astroid.Tuple,
239 astroid.List)):
240 node = node.parent
241 return node
242
243 def overrides_an_abstract_method(class_node, name):
244 """return True if pnode is a parent of node"""
245 for ancestor in class_node.ancestors():
246 if name in ancestor and isinstance(ancestor[name], astroid.Function) and \
247 ancestor[name].is_abstract(pass_is_abstract=False):
248 return True
249 return False
250
251 def overrides_a_method(class_node, name):
252 """return True if <name> is a method overridden from an ancestor"""
253 for ancestor in class_node.ancestors():
254 if name in ancestor and isinstance(ancestor[name], astroid.Function):
255 return True
256 return False
257
258 PYMETHODS = set(('__new__', '__init__', '__del__', '__hash__',
259 '__str__', '__repr__',
260 '__len__', '__iter__',
261 '__delete__', '__get__', '__set__',
262 '__getitem__', '__setitem__', '__delitem__', '__contains__',
263 '__getattribute__', '__getattr__', '__setattr__', '__delattr__' ,
264 '__call__',
265 '__enter__', '__exit__',
266 '__cmp__', '__ge__', '__gt__', '__le__', '__lt__', '__eq__',
267 '__nonzero__', '__neg__', '__invert__',
268 '__mul__', '__imul__', '__rmul__',
269 '__div__', '__idiv__', '__rdiv__',
270 '__add__', '__iadd__', '__radd__',
271 '__sub__', '__isub__', '__rsub__',
272 '__pow__', '__ipow__', '__rpow__',
273 '__mod__', '__imod__', '__rmod__',
274 '__and__', '__iand__', '__rand__',
275 '__or__', '__ior__', '__ror__',
276 '__xor__', '__ixor__', '__rxor__',
277 # XXX To be continued
278 ))
279
280 def check_messages(*messages):
281 """decorator to store messages that are handled by a checker method"""
282
283 def store_messages(func):
284 func.checks_msgs = messages
285 return func
286 return store_messages
287
288 class IncompleteFormatString(Exception):
289 """A format string ended in the middle of a format specifier."""
290 pass
291
292 class UnsupportedFormatCharacter(Exception):
293 """A format character in a format string is not one of the supported
294 format characters."""
295 def __init__(self, index):
296 Exception.__init__(self, index)
297 self.index = index
298
299 def parse_format_string(format_string):
300 """Parses a format string, returning a tuple of (keys, num_args), where keys
301 is the set of mapping keys in the format string, and num_args is the number
302 of arguments required by the format string. Raises
303 IncompleteFormatString or UnsupportedFormatCharacter if a
304 parse error occurs."""
305 keys = set()
306 num_args = 0
307 def next_char(i):
308 i += 1
309 if i == len(format_string):
310 raise IncompleteFormatString
311 return (i, format_string[i])
312 i = 0
313 while i < len(format_string):
314 char = format_string[i]
315 if char == '%':
316 i, char = next_char(i)
317 # Parse the mapping key (optional).
318 key = None
319 if char == '(':
320 depth = 1
321 i, char = next_char(i)
322 key_start = i
323 while depth != 0:
324 if char == '(':
325 depth += 1
326 elif char == ')':
327 depth -= 1
328 i, char = next_char(i)
329 key_end = i - 1
330 key = format_string[key_start:key_end]
331
332 # Parse the conversion flags (optional).
333 while char in '#0- +':
334 i, char = next_char(i)
335 # Parse the minimum field width (optional).
336 if char == '*':
337 num_args += 1
338 i, char = next_char(i)
339 else:
340 while char in string.digits:
341 i, char = next_char(i)
342 # Parse the precision (optional).
343 if char == '.':
344 i, char = next_char(i)
345 if char == '*':
346 num_args += 1
347 i, char = next_char(i)
348 else:
349 while char in string.digits:
350 i, char = next_char(i)
351 # Parse the length modifier (optional).
352 if char in 'hlL':
353 i, char = next_char(i)
354 # Parse the conversion type (mandatory).
355 if PY3K:
356 flags = 'diouxXeEfFgGcrs%a'
357 else:
358 flags = 'diouxXeEfFgGcrs%'
359 if char not in flags:
360 raise UnsupportedFormatCharacter(i)
361 if key:
362 keys.add(key)
363 elif char != '%':
364 num_args += 1
365 i += 1
366 return keys, num_args
367
368
369 def is_attr_protected(attrname):
370 """return True if attribute name is protected (start with _ and some other
371 details), False otherwise.
372 """
373 return attrname[0] == '_' and not attrname == '_' and not (
374 attrname.startswith('__') and attrname.endswith('__'))
375
376 def node_frame_class(node):
377 """return klass node for a method node (or a staticmethod or a
378 classmethod), return null otherwise
379 """
380 klass = node.frame()
381
382 while klass is not None and not isinstance(klass, astroid.Class):
383 if klass.parent is None:
384 klass = None
385 else:
386 klass = klass.parent.frame()
387
388 return klass
389
390 def is_super_call(expr):
391 """return True if expression node is a function call and if function name
392 is super. Check before that you're in a method.
393 """
394 return (isinstance(expr, astroid.CallFunc) and
395 isinstance(expr.func, astroid.Name) and
396 expr.func.name == 'super')
397
398 def is_attr_private(attrname):
399 """Check that attribute name is private (at least two leading underscores,
400 at most one trailing underscore)
401 """
402 regex = re.compile('^_{2,}.*[^_]+_?$')
403 return regex.match(attrname)
404
405 def get_argument_from_call(callfunc_node, position=None, keyword=None):
406 """Returns the specified argument from a function call.
407
408 :param callfunc_node: Node representing a function call to check.
409 :param int position: position of the argument.
410 :param str keyword: the keyword of the argument.
411
412 :returns: The node representing the argument, None if the argument is not fo und.
413 :raises ValueError: if both position and keyword are None.
414 :raises NoSuchArgumentError: if no argument at the provided position or with
415 the provided keyword.
416 """
417 if position is None and keyword is None:
418 raise ValueError('Must specify at least one of: position or keyword.')
419 try:
420 if position is not None and not isinstance(callfunc_node.args[position], astroid.Keyword):
421 return callfunc_node.args[position]
422 except IndexError as error:
423 raise NoSuchArgumentError(error)
424 if keyword:
425 for arg in callfunc_node.args:
426 if isinstance(arg, astroid.Keyword) and arg.arg == keyword:
427 return arg.value
428 raise NoSuchArgumentError
429
430 def inherit_from_std_ex(node):
431 """
432 Return true if the given class node is subclass of
433 exceptions.Exception.
434 """
435 if node.name in ('Exception', 'BaseException') \
436 and node.root().name == EXCEPTIONS_MODULE:
437 return True
438 return any(inherit_from_std_ex(parent)
439 for parent in node.ancestors(recurs=False))
440
441 def is_import_error(handler):
442 """
443 Check if the given exception handler catches
444 ImportError.
445
446 :param handler: A node, representing an ExceptHandler node.
447 :returns: True if the handler catches ImportError, False otherwise.
448 """
449 names = None
450 if isinstance(handler.type, astroid.Tuple):
451 names = [name for name in handler.type.elts
452 if isinstance(name, astroid.Name)]
453 elif isinstance(handler.type, astroid.Name):
454 names = [handler.type]
455 else:
456 # Don't try to infer that.
457 return
458 for name in names:
459 try:
460 for infered in name.infer():
461 if (isinstance(infered, astroid.Class) and
462 inherit_from_std_ex(infered) and
463 infered.name == 'ImportError'):
464 return True
465 except astroid.InferenceError:
466 continue
467
468 def has_known_bases(klass):
469 """Returns true if all base classes of a class could be inferred."""
470 try:
471 return klass._all_bases_known
472 except AttributeError:
473 pass
474 for base in klass.bases:
475 result = safe_infer(base)
476 # TODO: check for A->B->A->B pattern in class structure too?
477 if (not isinstance(result, astroid.Class) or
478 result is klass or
479 not has_known_bases(result)):
480 klass._all_bases_known = False
481 return False
482 klass._all_bases_known = True
483 return True
484
485 def decorated_with_property(node):
486 """ Detect if the given function node is decorated with a property. """
487 if not node.decorators:
488 return False
489 for decorator in node.decorators.nodes:
490 if not isinstance(decorator, astroid.Name):
491 continue
492 try:
493 for infered in decorator.infer():
494 if isinstance(infered, astroid.Class):
495 if (infered.root().name == BUILTINS_NAME and
496 infered.name == 'property'):
497 return True
498 for ancestor in infered.ancestors():
499 if (ancestor.name == 'property' and
500 ancestor.root().name == BUILTINS_NAME):
501 return True
502 except astroid.InferenceError:
503 pass
504
505
506 def decorated_with_abc(func):
507 """Determine if the `func` node is decorated with `abc` decorators."""
508 if func.decorators:
509 for node in func.decorators.nodes:
510 try:
511 infered = next(node.infer())
512 except astroid.InferenceError:
513 continue
514 if infered and infered.qname() in ABC_METHODS:
515 return True
516
517
518 def unimplemented_abstract_methods(node, is_abstract_cb=decorated_with_abc):
519 """
520 Get the unimplemented abstract methods for the given *node*.
521
522 A method can be considered abstract if the callback *is_abstract_cb*
523 returns a ``True`` value. The check defaults to verifying that
524 a method is decorated with abstract methods.
525 The function will work only for new-style classes. For old-style
526 classes, it will simply return an empty dictionary.
527 For the rest of them, it will return a dictionary of abstract method
528 names and their inferred objects.
529 """
530 visited = {}
531 try:
532 mro = reversed(node.mro())
533 except NotImplementedError:
534 # Old style class, it will not have a mro.
535 return {}
536 except astroid.ResolveError:
537 # Probably inconsistent hierarchy, don'try
538 # to figure this out here.
539 return {}
540 for ancestor in mro:
541 for obj in ancestor.values():
542 infered = obj
543 if isinstance(obj, astroid.AssName):
544 infered = safe_infer(obj)
545 if not infered:
546 continue
547 if not isinstance(infered, astroid.Function):
548 if obj.name in visited:
549 del visited[obj.name]
550 if isinstance(infered, astroid.Function):
551 # It's critical to use the original name,
552 # since after inferring, an object can be something
553 # else than expected, as in the case of the
554 # following assignment.
555 #
556 # class A:
557 # def keys(self): pass
558 # __iter__ = keys
559 abstract = is_abstract_cb(infered)
560 if abstract:
561 visited[obj.name] = infered
562 elif not abstract and obj.name in visited:
563 del visited[obj.name]
564 return visited
OLDNEW
« no previous file with comments | « third_party/pylint/pylint/checkers/typecheck.py ('k') | third_party/pylint/pylint/checkers/variables.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698