OLD | NEW |
1 # pylint: disable=W0611 | 1 # pylint: disable=W0611 |
2 # | 2 # |
3 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). | 3 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). |
4 # http://www.logilab.fr/ -- mailto:contact@logilab.fr | 4 # http://www.logilab.fr/ -- mailto:contact@logilab.fr |
5 # | 5 # |
6 # This program is free software; you can redistribute it and/or modify it under | 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 | 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 | 8 # Foundation; either version 2 of the License, or (at your option) any later |
9 # version. | 9 # version. |
10 # | 10 # |
(...skipping 12 matching lines...) Expand all Loading... |
23 import string | 23 import string |
24 | 24 |
25 import astroid | 25 import astroid |
26 from astroid import scoped_nodes | 26 from astroid import scoped_nodes |
27 from logilab.common.compat import builtins | 27 from logilab.common.compat import builtins |
28 | 28 |
29 BUILTINS_NAME = builtins.__name__ | 29 BUILTINS_NAME = builtins.__name__ |
30 COMP_NODE_TYPES = astroid.ListComp, astroid.SetComp, astroid.DictComp, astroid.G
enExpr | 30 COMP_NODE_TYPES = astroid.ListComp, astroid.SetComp, astroid.DictComp, astroid.G
enExpr |
31 PY3K = sys.version_info[0] == 3 | 31 PY3K = sys.version_info[0] == 3 |
32 | 32 |
| 33 if not PY3K: |
| 34 EXCEPTIONS_MODULE = "exceptions" |
| 35 else: |
| 36 EXCEPTIONS_MODULE = "builtins" |
| 37 |
33 | 38 |
34 class NoSuchArgumentError(Exception): | 39 class NoSuchArgumentError(Exception): |
35 pass | 40 pass |
36 | 41 |
37 def is_inside_except(node): | 42 def is_inside_except(node): |
38 """Returns true if node is inside the name of an except handler.""" | 43 """Returns true if node is inside the name of an except handler.""" |
39 current = node | 44 current = node |
40 while current and not isinstance(current.parent, astroid.ExceptHandler): | 45 while current and not isinstance(current.parent, astroid.ExceptHandler): |
41 current = current.parent | 46 current = current.parent |
42 | 47 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 return (False, None) | 80 return (False, None) |
76 | 81 |
77 | 82 |
78 def safe_infer(node): | 83 def safe_infer(node): |
79 """return the inferred value for the given node. | 84 """return the inferred value for the given node. |
80 Return None if inference failed or if there is some ambiguity (more than | 85 Return None if inference failed or if there is some ambiguity (more than |
81 one node has been inferred) | 86 one node has been inferred) |
82 """ | 87 """ |
83 try: | 88 try: |
84 inferit = node.infer() | 89 inferit = node.infer() |
85 value = inferit.next() | 90 value = next(inferit) |
86 except astroid.InferenceError: | 91 except astroid.InferenceError: |
87 return | 92 return |
88 try: | 93 try: |
89 inferit.next() | 94 next(inferit) |
90 return # None if there is ambiguity on the inferred node | 95 return # None if there is ambiguity on the inferred node |
91 except astroid.InferenceError: | 96 except astroid.InferenceError: |
92 return # there is some kind of ambiguity | 97 return # there is some kind of ambiguity |
93 except StopIteration: | 98 except StopIteration: |
94 return value | 99 return value |
95 | 100 |
96 def is_super(node): | 101 def is_super(node): |
97 """return True if the node is referencing the "super" builtin function | 102 """return True if the node is referencing the "super" builtin function |
98 """ | 103 """ |
99 if getattr(node, 'name', None) == 'super' and \ | 104 if getattr(node, 'name', None) == 'super' and \ |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 while _node: | 150 while _node: |
146 if isinstance(_node, COMP_NODE_TYPES): | 151 if isinstance(_node, COMP_NODE_TYPES): |
147 for ass_node in _node.nodes_of_class(astroid.AssName): | 152 for ass_node in _node.nodes_of_class(astroid.AssName): |
148 if ass_node.name == varname: | 153 if ass_node.name == varname: |
149 return True | 154 return True |
150 elif isinstance(_node, astroid.For): | 155 elif isinstance(_node, astroid.For): |
151 for ass_node in _node.target.nodes_of_class(astroid.AssName): | 156 for ass_node in _node.target.nodes_of_class(astroid.AssName): |
152 if ass_node.name == varname: | 157 if ass_node.name == varname: |
153 return True | 158 return True |
154 elif isinstance(_node, astroid.With): | 159 elif isinstance(_node, astroid.With): |
155 for expr, vars in _node.items: | 160 for expr, ids in _node.items: |
156 if expr.parent_of(var_node): | 161 if expr.parent_of(var_node): |
157 break | 162 break |
158 if (vars and | 163 if (ids and |
159 isinstance(vars, astroid.AssName) and | 164 isinstance(ids, astroid.AssName) and |
160 vars.name == varname): | 165 ids.name == varname): |
161 return True | 166 return True |
162 elif isinstance(_node, (astroid.Lambda, astroid.Function)): | 167 elif isinstance(_node, (astroid.Lambda, astroid.Function)): |
163 if _node.args.is_argument(varname): | 168 if _node.args.is_argument(varname): |
164 return True | 169 return True |
165 if getattr(_node, 'name', None) == varname: | 170 if getattr(_node, 'name', None) == varname: |
166 return True | 171 return True |
167 break | 172 break |
168 elif isinstance(_node, astroid.ExceptHandler): | 173 elif isinstance(_node, astroid.ExceptHandler): |
169 if isinstance(_node.name, astroid.AssName): | 174 if isinstance(_node.name, astroid.AssName): |
170 ass_node = _node.name | 175 ass_node = _node.name |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 :returns: The node representing the argument, None if the argument is not fo
und. | 410 :returns: The node representing the argument, None if the argument is not fo
und. |
406 :raises ValueError: if both position and keyword are None. | 411 :raises ValueError: if both position and keyword are None. |
407 :raises NoSuchArgumentError: if no argument at the provided position or with | 412 :raises NoSuchArgumentError: if no argument at the provided position or with |
408 the provided keyword. | 413 the provided keyword. |
409 """ | 414 """ |
410 if position is None and keyword is None: | 415 if position is None and keyword is None: |
411 raise ValueError('Must specify at least one of: position or keyword.') | 416 raise ValueError('Must specify at least one of: position or keyword.') |
412 try: | 417 try: |
413 if position is not None and not isinstance(callfunc_node.args[position],
astroid.Keyword): | 418 if position is not None and not isinstance(callfunc_node.args[position],
astroid.Keyword): |
414 return callfunc_node.args[position] | 419 return callfunc_node.args[position] |
415 except IndexError, error: | 420 except IndexError as error: |
416 raise NoSuchArgumentError(error) | 421 raise NoSuchArgumentError(error) |
417 if keyword: | 422 if keyword: |
418 for arg in callfunc_node.args: | 423 for arg in callfunc_node.args: |
419 if isinstance(arg, astroid.Keyword) and arg.arg == keyword: | 424 if isinstance(arg, astroid.Keyword) and arg.arg == keyword: |
420 return arg.value | 425 return arg.value |
421 raise NoSuchArgumentError | 426 raise NoSuchArgumentError |
| 427 |
| 428 def inherit_from_std_ex(node): |
| 429 """ |
| 430 Return true if the given class node is subclass of |
| 431 exceptions.Exception. |
| 432 """ |
| 433 if node.name in ('Exception', 'BaseException') \ |
| 434 and node.root().name == EXCEPTIONS_MODULE: |
| 435 return True |
| 436 return any(inherit_from_std_ex(parent) |
| 437 for parent in node.ancestors(recurs=False)) |
| 438 |
| 439 def is_import_error(handler): |
| 440 """ |
| 441 Check if the given exception handler catches |
| 442 ImportError. |
| 443 |
| 444 :param handler: A node, representing an ExceptHandler node. |
| 445 :returns: True if the handler catches ImportError, False otherwise. |
| 446 """ |
| 447 names = None |
| 448 if isinstance(handler.type, astroid.Tuple): |
| 449 names = [name for name in handler.type.elts |
| 450 if isinstance(name, astroid.Name)] |
| 451 elif isinstance(handler.type, astroid.Name): |
| 452 names = [handler.type] |
| 453 else: |
| 454 # Don't try to infer that. |
| 455 return |
| 456 for name in names: |
| 457 try: |
| 458 for infered in name.infer(): |
| 459 if (isinstance(infered, astroid.Class) and |
| 460 inherit_from_std_ex(infered) and |
| 461 infered.name == 'ImportError'): |
| 462 return True |
| 463 except astroid.InferenceError: |
| 464 continue |
| 465 |
| 466 def has_known_bases(klass): |
| 467 """Returns true if all base classes of a class could be inferred.""" |
| 468 try: |
| 469 return klass._all_bases_known |
| 470 except AttributeError: |
| 471 pass |
| 472 for base in klass.bases: |
| 473 result = safe_infer(base) |
| 474 # TODO: check for A->B->A->B pattern in class structure too? |
| 475 if (not isinstance(result, astroid.Class) or |
| 476 result is klass or |
| 477 not has_known_bases(result)): |
| 478 klass._all_bases_known = False |
| 479 return False |
| 480 klass._all_bases_known = True |
| 481 return True |
| 482 |
| 483 def decorated_with_property(node): |
| 484 """ Detect if the given function node is decorated with a property. """ |
| 485 if not node.decorators: |
| 486 return False |
| 487 for decorator in node.decorators.nodes: |
| 488 if not isinstance(decorator, astroid.Name): |
| 489 continue |
| 490 try: |
| 491 for infered in decorator.infer(): |
| 492 if isinstance(infered, astroid.Class): |
| 493 if (infered.root().name == BUILTINS_NAME and |
| 494 infered.name == 'property'): |
| 495 return True |
| 496 for ancestor in infered.ancestors(): |
| 497 if (ancestor.name == 'property' and |
| 498 ancestor.root().name == BUILTINS_NAME): |
| 499 return True |
| 500 except astroid.InferenceError: |
| 501 pass |
OLD | NEW |