| OLD | NEW |
| 1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
| 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 3 # | 3 # |
| 4 # This file is part of astroid. | 4 # This file is part of astroid. |
| 5 # | 5 # |
| 6 # astroid is free software: you can redistribute it and/or modify it | 6 # astroid is free software: you can redistribute it and/or modify it |
| 7 # under the terms of the GNU Lesser General Public License as published by the | 7 # under the terms of the GNU Lesser General Public License as published by the |
| 8 # Free Software Foundation, either version 2.1 of the License, or (at your | 8 # Free Software Foundation, either version 2.1 of the License, or (at your |
| 9 # option) any later version. | 9 # option) any later version. |
| 10 # | 10 # |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 __doctype__ = "restructuredtext en" | 24 __doctype__ = "restructuredtext en" |
| 25 | 25 |
| 26 import sys | 26 import sys |
| 27 from itertools import chain | 27 from itertools import chain |
| 28 try: | 28 try: |
| 29 from io import BytesIO | 29 from io import BytesIO |
| 30 except ImportError: | 30 except ImportError: |
| 31 from cStringIO import StringIO as BytesIO | 31 from cStringIO import StringIO as BytesIO |
| 32 | 32 |
| 33 import six |
| 33 from logilab.common.compat import builtins | 34 from logilab.common.compat import builtins |
| 34 from logilab.common.decorators import cached, cachedproperty | 35 from logilab.common.decorators import cached, cachedproperty |
| 35 | 36 |
| 36 from astroid.exceptions import NotFoundError, \ | 37 from astroid.exceptions import NotFoundError, \ |
| 37 AstroidBuildingException, InferenceError | 38 AstroidBuildingException, InferenceError |
| 38 from astroid.node_classes import Const, DelName, DelAttr, \ | 39 from astroid.node_classes import Const, DelName, DelAttr, \ |
| 39 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ | 40 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ |
| 40 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc | 41 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc |
| 41 from astroid.bases import NodeNG, InferenceContext, Instance,\ | 42 from astroid.bases import NodeNG, InferenceContext, Instance,\ |
| 42 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \ | 43 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, \ |
| 43 BUILTINS | 44 BUILTINS |
| 44 from astroid.mixins import FilterStmtsMixin | 45 from astroid.mixins import FilterStmtsMixin |
| 45 from astroid.bases import Statement | 46 from astroid.bases import Statement |
| 46 from astroid.manager import AstroidManager | 47 from astroid.manager import AstroidManager |
| 47 | 48 |
| 48 ITER_METHODS = ('__iter__', '__getitem__') | 49 ITER_METHODS = ('__iter__', '__getitem__') |
| 49 PY3K = sys.version_info >= (3, 0) | 50 PY3K = sys.version_info >= (3, 0) |
| 50 | 51 |
| 51 | 52 |
| 52 def remove_nodes(func, cls): | 53 def remove_nodes(func, cls): |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 def __iter__(self): | 185 def __iter__(self): |
| 185 """method from the `dict` interface returning an iterator on | 186 """method from the `dict` interface returning an iterator on |
| 186 `self.keys()` | 187 `self.keys()` |
| 187 """ | 188 """ |
| 188 return iter(self.keys()) | 189 return iter(self.keys()) |
| 189 | 190 |
| 190 def keys(self): | 191 def keys(self): |
| 191 """method from the `dict` interface returning a tuple containing | 192 """method from the `dict` interface returning a tuple containing |
| 192 locally defined names | 193 locally defined names |
| 193 """ | 194 """ |
| 194 return self.locals.keys() | 195 return list(self.locals.keys()) |
| 195 | 196 |
| 196 def values(self): | 197 def values(self): |
| 197 """method from the `dict` interface returning a tuple containing | 198 """method from the `dict` interface returning a tuple containing |
| 198 locally defined nodes which are instance of `Function` or `Class` | 199 locally defined nodes which are instance of `Function` or `Class` |
| 199 """ | 200 """ |
| 200 return [self[key] for key in self.keys()] | 201 return [self[key] for key in self.keys()] |
| 201 | 202 |
| 202 def items(self): | 203 def items(self): |
| 203 """method from the `dict` interface returning a list of tuple | 204 """method from the `dict` interface returning a list of tuple |
| 204 containing each locally defined name with its associated node, | 205 containing each locally defined name with its associated node, |
| 205 which is an instance of `Function` or `Class` | 206 which is an instance of `Function` or `Class` |
| 206 """ | 207 """ |
| 207 return zip(self.keys(), self.values()) | 208 return list(zip(self.keys(), self.values())) |
| 208 | 209 |
| 209 | 210 |
| 210 def __contains__(self, name): | 211 def __contains__(self, name): |
| 211 return name in self.locals | 212 return name in self.locals |
| 212 has_key = __contains__ | 213 has_key = __contains__ |
| 213 | 214 |
| 214 # Module ##################################################################### | 215 # Module ##################################################################### |
| 215 | 216 |
| 216 class Module(LocalsDictNodeNG): | 217 class Module(LocalsDictNodeNG): |
| 217 _astroid_fields = ('body',) | 218 _astroid_fields = ('body',) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) | 250 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) |
| 250 | 251 |
| 251 def __init__(self, name, doc, pure_python=True): | 252 def __init__(self, name, doc, pure_python=True): |
| 252 self.name = name | 253 self.name = name |
| 253 self.doc = doc | 254 self.doc = doc |
| 254 self.pure_python = pure_python | 255 self.pure_python = pure_python |
| 255 self.locals = self.globals = {} | 256 self.locals = self.globals = {} |
| 256 self.body = [] | 257 self.body = [] |
| 257 self.future_imports = set() | 258 self.future_imports = set() |
| 258 | 259 |
| 259 @property | 260 @cachedproperty |
| 260 def file_stream(self): | 261 def file_stream(self): |
| 261 if self.file_bytes is not None: | 262 if self.file_bytes is not None: |
| 262 return BytesIO(self.file_bytes) | 263 return BytesIO(self.file_bytes) |
| 263 if self.file is not None: | 264 if self.file is not None: |
| 264 return open(self.file, 'rb') | 265 return open(self.file, 'rb') |
| 265 return None | 266 return None |
| 266 | 267 |
| 267 def block_range(self, lineno): | 268 def block_range(self, lineno): |
| 268 """return block line numbers. | 269 """return block line numbers. |
| 269 | 270 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 except Exception:# XXX pylint tests never pass here; do we need it? | 305 except Exception:# XXX pylint tests never pass here; do we need it? |
| 305 import traceback | 306 import traceback |
| 306 traceback.print_exc() | 307 traceback.print_exc() |
| 307 raise NotFoundError(name) | 308 raise NotFoundError(name) |
| 308 getattr = remove_nodes(getattr, DelName) | 309 getattr = remove_nodes(getattr, DelName) |
| 309 | 310 |
| 310 def igetattr(self, name, context=None): | 311 def igetattr(self, name, context=None): |
| 311 """inferred getattr""" | 312 """inferred getattr""" |
| 312 # set lookup name since this is necessary to infer on import nodes for | 313 # set lookup name since this is necessary to infer on import nodes for |
| 313 # instance | 314 # instance |
| 314 context = copy_context(context) | 315 if not context: |
| 315 context.lookupname = name | 316 context = InferenceContext() |
| 316 try: | 317 try: |
| 317 return _infer_stmts(self.getattr(name, context), context, frame=self
) | 318 return _infer_stmts(self.getattr(name, context), context, frame=self
, lookupname=name) |
| 318 except NotFoundError: | 319 except NotFoundError: |
| 319 raise InferenceError(name) | 320 raise InferenceError(name) |
| 320 | 321 |
| 321 def fully_defined(self): | 322 def fully_defined(self): |
| 322 """return True if this module has been built from a .py file | 323 """return True if this module has been built from a .py file |
| 323 and so contains a complete representation including the code | 324 and so contains a complete representation including the code |
| 324 """ | 325 """ |
| 325 return self.file is not None and self.file.endswith('.py') | 326 return self.file is not None and self.file.endswith('.py') |
| 326 | 327 |
| 327 def statement(self): | 328 def statement(self): |
| 328 """return the first parent node marked as statement node | 329 """return the first parent node marked as statement node |
| 329 consider a module as a statement... | 330 consider a module as a statement... |
| 330 """ | 331 """ |
| 331 return self | 332 return self |
| 332 | 333 |
| 333 def previous_sibling(self): | 334 def previous_sibling(self): |
| 334 """module has no sibling""" | 335 """module has no sibling""" |
| 335 return | 336 return |
| 336 | 337 |
| 337 def next_sibling(self): | 338 def next_sibling(self): |
| 338 """module has no sibling""" | 339 """module has no sibling""" |
| 339 return | 340 return |
| 340 | 341 |
| 341 if sys.version_info < (2, 8): | 342 if sys.version_info < (2, 8): |
| 342 def absolute_import_activated(self): | 343 @cachedproperty |
| 344 def _absolute_import_activated(self): |
| 343 for stmt in self.locals.get('absolute_import', ()): | 345 for stmt in self.locals.get('absolute_import', ()): |
| 344 if isinstance(stmt, From) and stmt.modname == '__future__': | 346 if isinstance(stmt, From) and stmt.modname == '__future__': |
| 345 return True | 347 return True |
| 346 return False | 348 return False |
| 347 else: | 349 else: |
| 348 absolute_import_activated = lambda self: True | 350 _absolute_import_activated = True |
| 351 |
| 352 def absolute_import_activated(self): |
| 353 return self._absolute_import_activated |
| 349 | 354 |
| 350 def import_module(self, modname, relative_only=False, level=None): | 355 def import_module(self, modname, relative_only=False, level=None): |
| 351 """import the given module considering self as context""" | 356 """import the given module considering self as context""" |
| 352 if relative_only and level is None: | 357 if relative_only and level is None: |
| 353 level = 0 | 358 level = 0 |
| 354 absmodname = self.relative_to_absolute_name(modname, level) | 359 absmodname = self.relative_to_absolute_name(modname, level) |
| 355 try: | 360 try: |
| 356 return MANAGER.ast_from_module_name(absmodname) | 361 return MANAGER.ast_from_module_name(absmodname) |
| 357 except AstroidBuildingException: | 362 except AstroidBuildingException: |
| 358 # we only want to import a sub module or package of this module, | 363 # we only want to import a sub module or package of this module, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 else: | 406 else: |
| 402 try: | 407 try: |
| 403 return living.__all__ | 408 return living.__all__ |
| 404 except AttributeError: | 409 except AttributeError: |
| 405 return [name for name in living.__dict__.keys() | 410 return [name for name in living.__dict__.keys() |
| 406 if not name.startswith('_')] | 411 if not name.startswith('_')] |
| 407 # else lookup the astroid | 412 # else lookup the astroid |
| 408 # | 413 # |
| 409 # We separate the different steps of lookup in try/excepts | 414 # We separate the different steps of lookup in try/excepts |
| 410 # to avoid catching too many Exceptions | 415 # to avoid catching too many Exceptions |
| 411 # However, we can not analyse dynamically constructed __all__ | 416 default = [name for name in self.keys() if not name.startswith('_')] |
| 412 try: | 417 try: |
| 413 all = self['__all__'] | 418 all = self['__all__'] |
| 414 except KeyError: | 419 except KeyError: |
| 415 return [name for name in self.keys() if not name.startswith('_')] | 420 return default |
| 416 try: | 421 try: |
| 417 explicit = all.assigned_stmts().next() | 422 explicit = next(all.assigned_stmts()) |
| 418 except InferenceError: | 423 except InferenceError: |
| 419 return [name for name in self.keys() if not name.startswith('_')] | 424 return default |
| 420 except AttributeError: | 425 except AttributeError: |
| 421 # not an assignment node | 426 # not an assignment node |
| 422 # XXX infer? | 427 # XXX infer? |
| 423 return [name for name in self.keys() if not name.startswith('_')] | 428 return default |
| 429 |
| 430 # Try our best to detect the exported name. |
| 431 infered = [] |
| 424 try: | 432 try: |
| 425 # should be a Tuple/List of constant string / 1 string not allowed | 433 explicit = next(explicit.infer()) |
| 426 return [const.value for const in explicit.elts] | 434 except InferenceError: |
| 427 except AttributeError: | 435 return default |
| 428 return [name for name in self.keys() if not name.startswith('_')] | 436 if not isinstance(explicit, (Tuple, List)): |
| 437 return default |
| 438 |
| 439 str_const = lambda node: (isinstance(node, Const) and |
| 440 isinstance(node.value, six.string_types)) |
| 441 for node in explicit.elts: |
| 442 if str_const(node): |
| 443 infered.append(node.value) |
| 444 else: |
| 445 try: |
| 446 infered_node = next(node.infer()) |
| 447 except InferenceError: |
| 448 continue |
| 449 if str_const(infered_node): |
| 450 infered.append(infered_node.value) |
| 451 return infered |
| 452 |
| 429 | 453 |
| 430 | 454 |
| 431 class ComprehensionScope(LocalsDictNodeNG): | 455 class ComprehensionScope(LocalsDictNodeNG): |
| 432 def frame(self): | 456 def frame(self): |
| 433 return self.parent.frame() | 457 return self.parent.frame() |
| 434 | 458 |
| 435 scope_lookup = LocalsDictNodeNG._scope_lookup | 459 scope_lookup = LocalsDictNodeNG._scope_lookup |
| 436 | 460 |
| 437 | 461 |
| 438 class GenExpr(ComprehensionScope): | 462 class GenExpr(ComprehensionScope): |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 # Function ################################################################### | 505 # Function ################################################################### |
| 482 | 506 |
| 483 def _infer_decorator_callchain(node): | 507 def _infer_decorator_callchain(node): |
| 484 """ Detect decorator call chaining and see if the | 508 """ Detect decorator call chaining and see if the |
| 485 end result is a static or a classmethod. | 509 end result is a static or a classmethod. |
| 486 """ | 510 """ |
| 487 current = node | 511 current = node |
| 488 while True: | 512 while True: |
| 489 if isinstance(current, CallFunc): | 513 if isinstance(current, CallFunc): |
| 490 try: | 514 try: |
| 491 current = current.func.infer().next() | 515 current = next(current.func.infer()) |
| 492 except InferenceError: | 516 except InferenceError: |
| 493 return | 517 return |
| 494 elif isinstance(current, Function): | 518 elif isinstance(current, Function): |
| 495 if not current.parent: | 519 if not current.parent: |
| 496 return | 520 return |
| 497 try: | 521 try: |
| 498 # TODO: We don't handle multiple inference results right now, | 522 # TODO: We don't handle multiple inference results right now, |
| 499 # because there's no flow to reason when the return | 523 # because there's no flow to reason when the return |
| 500 # is what we are looking for, a static or a class method. | 524 # is what we are looking for, a static or a class method. |
| 501 result = current.infer_call_result(current.parent).next() | 525 result = next(current.infer_call_result(current.parent)) |
| 526 if current is result: |
| 527 # This will lead to an infinite loop, where a decorator |
| 528 # returns itself. |
| 529 return |
| 502 except (StopIteration, InferenceError): | 530 except (StopIteration, InferenceError): |
| 503 return | 531 return |
| 504 if isinstance(result, (Function, CallFunc)): | 532 if isinstance(result, (Function, CallFunc)): |
| 505 current = result | 533 current = result |
| 506 else: | 534 else: |
| 507 if isinstance(result, Instance): | 535 if isinstance(result, Instance): |
| 508 result = result._proxied | 536 result = result._proxied |
| 509 if isinstance(result, Class): | 537 if isinstance(result, Class): |
| 510 if (result.name == 'classmethod' and | 538 if (result.name == 'classmethod' and |
| 511 result.root().name == BUILTINS): | 539 result.root().name == BUILTINS): |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 # attributes below are set by the builder module or by raw factories | 650 # attributes below are set by the builder module or by raw factories |
| 623 blockstart_tolineno = None | 651 blockstart_tolineno = None |
| 624 decorators = None | 652 decorators = None |
| 625 _type = "function" | 653 _type = "function" |
| 626 type = cachedproperty(_function_type) | 654 type = cachedproperty(_function_type) |
| 627 | 655 |
| 628 def __init__(self, name, doc): | 656 def __init__(self, name, doc): |
| 629 self.locals = {} | 657 self.locals = {} |
| 630 self.args = [] | 658 self.args = [] |
| 631 self.body = [] | 659 self.body = [] |
| 632 self.decorators = None | |
| 633 self.name = name | 660 self.name = name |
| 634 self.doc = doc | 661 self.doc = doc |
| 635 self.extra_decorators = [] | 662 self.extra_decorators = [] |
| 636 self.instance_attrs = {} | 663 self.instance_attrs = {} |
| 637 | 664 |
| 638 def set_line_info(self, lastchild): | 665 @cachedproperty |
| 639 self.fromlineno = self.lineno | 666 def fromlineno(self): |
| 640 # lineno is the line number of the first decorator, we want the def stat
ement lineno | 667 # lineno is the line number of the first decorator, we want the def |
| 668 # statement lineno |
| 669 lineno = self.lineno |
| 641 if self.decorators is not None: | 670 if self.decorators is not None: |
| 642 self.fromlineno += sum(node.tolineno - node.lineno + 1 | 671 lineno += sum(node.tolineno - node.lineno + 1 |
| 643 for node in self.decorators.nodes) | 672 for node in self.decorators.nodes) |
| 644 if self.args.fromlineno < self.fromlineno: | 673 |
| 645 self.args.fromlineno = self.fromlineno | 674 return lineno |
| 646 self.tolineno = lastchild.tolineno | 675 |
| 647 self.blockstart_tolineno = self.args.tolineno | 676 @cachedproperty |
| 677 def blockstart_tolineno(self): |
| 678 return self.args.tolineno |
| 648 | 679 |
| 649 def block_range(self, lineno): | 680 def block_range(self, lineno): |
| 650 """return block line numbers. | 681 """return block line numbers. |
| 651 | 682 |
| 652 start from the "def" position whatever the given lineno | 683 start from the "def" position whatever the given lineno |
| 653 """ | 684 """ |
| 654 return self.fromlineno, self.tolineno | 685 return self.fromlineno, self.tolineno |
| 655 | 686 |
| 656 def getattr(self, name, context=None): | 687 def getattr(self, name, context=None): |
| 657 """this method doesn't look in the instance_attrs dictionary since it's | 688 """this method doesn't look in the instance_attrs dictionary since it's |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 690 """Returns True if the method is abstract. | 721 """Returns True if the method is abstract. |
| 691 | 722 |
| 692 A method is considered abstract if | 723 A method is considered abstract if |
| 693 - the only statement is 'raise NotImplementedError', or | 724 - the only statement is 'raise NotImplementedError', or |
| 694 - the only statement is 'pass' and pass_is_abstract is True, or | 725 - the only statement is 'pass' and pass_is_abstract is True, or |
| 695 - the method is annotated with abc.astractproperty/abc.abstractmethod | 726 - the method is annotated with abc.astractproperty/abc.abstractmethod |
| 696 """ | 727 """ |
| 697 if self.decorators: | 728 if self.decorators: |
| 698 for node in self.decorators.nodes: | 729 for node in self.decorators.nodes: |
| 699 try: | 730 try: |
| 700 infered = node.infer().next() | 731 infered = next(node.infer()) |
| 701 except InferenceError: | 732 except InferenceError: |
| 702 continue | 733 continue |
| 703 if infered and infered.qname() in ('abc.abstractproperty', | 734 if infered and infered.qname() in ('abc.abstractproperty', |
| 704 'abc.abstractmethod'): | 735 'abc.abstractmethod'): |
| 705 return True | 736 return True |
| 706 | 737 |
| 707 for child_node in self.body: | 738 for child_node in self.body: |
| 708 if isinstance(child_node, Raise): | 739 if isinstance(child_node, Raise): |
| 709 if child_node.raises_not_implemented(): | 740 if child_node.raises_not_implemented(): |
| 710 return True | 741 return True |
| 711 if pass_is_abstract and isinstance(child_node, Pass): | 742 if pass_is_abstract and isinstance(child_node, Pass): |
| 712 return True | 743 return True |
| 713 return False | 744 return False |
| 714 # empty function is the same as function with a single "pass" statement | 745 # empty function is the same as function with a single "pass" statement |
| 715 if pass_is_abstract: | 746 if pass_is_abstract: |
| 716 return True | 747 return True |
| 717 | 748 |
| 718 def is_generator(self): | 749 def is_generator(self): |
| 719 """return true if this is a generator function""" | 750 """return true if this is a generator function""" |
| 720 # XXX should be flagged, not computed | 751 # XXX should be flagged, not computed |
| 721 try: | 752 return next(self.nodes_of_class((Yield, YieldFrom), |
| 722 return self.nodes_of_class((Yield, YieldFrom), | 753 skip_klass=(Function, Lambda)), False) |
| 723 skip_klass=(Function, Lambda)).next() | |
| 724 except StopIteration: | |
| 725 return False | |
| 726 | 754 |
| 727 def infer_call_result(self, caller, context=None): | 755 def infer_call_result(self, caller, context=None): |
| 728 """infer what a function is returning when called""" | 756 """infer what a function is returning when called""" |
| 729 if self.is_generator(): | 757 if self.is_generator(): |
| 730 yield Generator() | 758 yield Generator() |
| 731 return | 759 return |
| 760 # This is really a gigantic hack to work around metaclass generators |
| 761 # that return transient class-generating functions. Pylint's AST structu
re |
| 762 # cannot handle a base class object that is only used for calling __new_
_, |
| 763 # but does not contribute to the inheritance structure itself. We inject |
| 764 # a fake class into the hierarchy here for several well-known metaclass |
| 765 # generators, and filter it out later. |
| 766 if (self.name == 'with_metaclass' and |
| 767 len(self.args.args) == 1 and |
| 768 self.args.vararg is not None): |
| 769 metaclass = next(caller.args[0].infer(context)) |
| 770 if isinstance(metaclass, Class): |
| 771 c = Class('temporary_class', None) |
| 772 c.hide = True |
| 773 c.parent = self |
| 774 c.bases = [next(b.infer(context)) for b in caller.args[1:]] |
| 775 c._metaclass = metaclass |
| 776 yield c |
| 777 return |
| 732 returns = self.nodes_of_class(Return, skip_klass=Function) | 778 returns = self.nodes_of_class(Return, skip_klass=Function) |
| 733 for returnnode in returns: | 779 for returnnode in returns: |
| 734 if returnnode.value is None: | 780 if returnnode.value is None: |
| 735 yield Const(None) | 781 yield Const(None) |
| 736 else: | 782 else: |
| 737 try: | 783 try: |
| 738 for infered in returnnode.value.infer(context): | 784 for infered in returnnode.value.infer(context): |
| 739 yield infered | 785 yield infered |
| 740 except InferenceError: | 786 except InferenceError: |
| 741 yield YES | 787 yield YES |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 elif klass.name.endswith('Exception'): | 849 elif klass.name.endswith('Exception'): |
| 804 klass._type = 'exception' | 850 klass._type = 'exception' |
| 805 else: | 851 else: |
| 806 if ancestors is None: | 852 if ancestors is None: |
| 807 ancestors = set() | 853 ancestors = set() |
| 808 if klass in ancestors: | 854 if klass in ancestors: |
| 809 # XXX we are in loop ancestors, and have found no type | 855 # XXX we are in loop ancestors, and have found no type |
| 810 klass._type = 'class' | 856 klass._type = 'class' |
| 811 return 'class' | 857 return 'class' |
| 812 ancestors.add(klass) | 858 ancestors.add(klass) |
| 813 # print >> sys.stderr, '_class_type', repr(klass) | |
| 814 for base in klass.ancestors(recurs=False): | 859 for base in klass.ancestors(recurs=False): |
| 815 name = _class_type(base, ancestors) | 860 name = _class_type(base, ancestors) |
| 816 if name != 'class': | 861 if name != 'class': |
| 817 if name == 'metaclass' and not _is_metaclass(klass): | 862 if name == 'metaclass' and not _is_metaclass(klass): |
| 818 # don't propagate it if the current class | 863 # don't propagate it if the current class |
| 819 # can't be a metaclass | 864 # can't be a metaclass |
| 820 continue | 865 continue |
| 821 klass._type = base.type | 866 klass._type = base.type |
| 822 break | 867 break |
| 823 if klass._type is None: | 868 if klass._type is None: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 838 | 883 |
| 839 # a dictionary of class instances attributes | 884 # a dictionary of class instances attributes |
| 840 _astroid_fields = ('decorators', 'bases', 'body') # name | 885 _astroid_fields = ('decorators', 'bases', 'body') # name |
| 841 | 886 |
| 842 decorators = None | 887 decorators = None |
| 843 special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', | 888 special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', |
| 844 '__bases__', '__mro__', '__subclasses__')) | 889 '__bases__', '__mro__', '__subclasses__')) |
| 845 blockstart_tolineno = None | 890 blockstart_tolineno = None |
| 846 | 891 |
| 847 _type = None | 892 _type = None |
| 893 _metaclass_hack = False |
| 894 hide = False |
| 848 type = property(_class_type, | 895 type = property(_class_type, |
| 849 doc="class'type, possible values are 'class' | " | 896 doc="class'type, possible values are 'class' | " |
| 850 "'metaclass' | 'interface' | 'exception'") | 897 "'metaclass' | 'interface' | 'exception'") |
| 851 | 898 |
| 852 def __init__(self, name, doc): | 899 def __init__(self, name, doc): |
| 853 self.instance_attrs = {} | 900 self.instance_attrs = {} |
| 854 self.locals = {} | 901 self.locals = {} |
| 855 self.bases = [] | 902 self.bases = [] |
| 856 self.body = [] | 903 self.body = [] |
| 857 self.name = name | 904 self.name = name |
| (...skipping 15 matching lines...) Expand all Loading... |
| 873 self._newstyle = klass._newstyle_impl(context) | 920 self._newstyle = klass._newstyle_impl(context) |
| 874 if self._newstyle is None: | 921 if self._newstyle is None: |
| 875 self._newstyle = False | 922 self._newstyle = False |
| 876 return self._newstyle | 923 return self._newstyle |
| 877 | 924 |
| 878 _newstyle = None | 925 _newstyle = None |
| 879 newstyle = property(_newstyle_impl, | 926 newstyle = property(_newstyle_impl, |
| 880 doc="boolean indicating if it's a new style class" | 927 doc="boolean indicating if it's a new style class" |
| 881 "or not") | 928 "or not") |
| 882 | 929 |
| 883 def set_line_info(self, lastchild): | 930 @cachedproperty |
| 884 self.fromlineno = self.lineno | 931 def blockstart_tolineno(self): |
| 885 self.blockstart_tolineno = self.bases and self.bases[-1].tolineno or sel
f.fromlineno | 932 if self.bases: |
| 886 if lastchild is not None: | 933 return self.bases[-1].tolineno |
| 887 self.tolineno = lastchild.tolineno | 934 else: |
| 888 # else this is a class with only a docstring, then tolineno is (should b
e) already ok | 935 return self.fromlineno |
| 889 | 936 |
| 890 def block_range(self, lineno): | 937 def block_range(self, lineno): |
| 891 """return block line numbers. | 938 """return block line numbers. |
| 892 | 939 |
| 893 start from the "class" position whatever the given lineno | 940 start from the "class" position whatever the given lineno |
| 894 """ | 941 """ |
| 895 return self.fromlineno, self.tolineno | 942 return self.fromlineno, self.tolineno |
| 896 | 943 |
| 897 def pytype(self): | 944 def pytype(self): |
| 898 if self.newstyle: | 945 if self.newstyle: |
| 899 return '%s.type' % BUILTINS | 946 return '%s.type' % BUILTINS |
| 900 return '%s.classobj' % BUILTINS | 947 return '%s.classobj' % BUILTINS |
| 901 | 948 |
| 902 def display_type(self): | 949 def display_type(self): |
| 903 return 'Class' | 950 return 'Class' |
| 904 | 951 |
| 905 def callable(self): | 952 def callable(self): |
| 906 return True | 953 return True |
| 907 | 954 |
| 908 def _is_subtype_of(self, type_name): | 955 def is_subtype_of(self, type_name, context=None): |
| 909 if self.qname() == type_name: | 956 if self.qname() == type_name: |
| 910 return True | 957 return True |
| 911 for anc in self.ancestors(): | 958 for anc in self.ancestors(context=context): |
| 912 if anc.qname() == type_name: | 959 if anc.qname() == type_name: |
| 913 return True | 960 return True |
| 914 | 961 |
| 915 def infer_call_result(self, caller, context=None): | 962 def infer_call_result(self, caller, context=None): |
| 916 """infer what a class is returning when called""" | 963 """infer what a class is returning when called""" |
| 917 if self._is_subtype_of('%s.type' % (BUILTINS,)) and len(caller.args) ==
3: | 964 if self.is_subtype_of('%s.type' % (BUILTINS,), context) and len(caller.a
rgs) == 3: |
| 918 name_node = caller.args[0].infer().next() | 965 name_node = next(caller.args[0].infer(context)) |
| 919 if isinstance(name_node, Const) and isinstance(name_node.value, base
string): | 966 if (isinstance(name_node, Const) and |
| 967 isinstance(name_node.value, six.string_types)): |
| 920 name = name_node.value | 968 name = name_node.value |
| 921 else: | 969 else: |
| 922 yield YES | 970 yield YES |
| 923 return | 971 return |
| 924 result = Class(name, None) | 972 result = Class(name, None) |
| 925 bases = caller.args[1].infer().next() | 973 bases = next(caller.args[1].infer(context)) |
| 926 if isinstance(bases, (Tuple, List)): | 974 if isinstance(bases, (Tuple, List)): |
| 927 result.bases = bases.itered() | 975 result.bases = bases.itered() |
| 928 else: | 976 else: |
| 929 # There is currently no AST node that can represent an 'unknown' | 977 # There is currently no AST node that can represent an 'unknown' |
| 930 # node (YES is not an AST node), therefore we simply return YES
here | 978 # node (YES is not an AST node), therefore we simply return YES
here |
| 931 # although we know at least the name of the class. | 979 # although we know at least the name of the class. |
| 932 yield YES | 980 yield YES |
| 933 return | 981 return |
| 934 result.parent = caller.parent | 982 result.parent = caller.parent |
| 935 yield result | 983 yield result |
| (...skipping 18 matching lines...) Expand all Loading... |
| 954 | 1002 |
| 955 def ancestors(self, recurs=True, context=None): | 1003 def ancestors(self, recurs=True, context=None): |
| 956 """return an iterator on the node base classes in a prefixed | 1004 """return an iterator on the node base classes in a prefixed |
| 957 depth first order | 1005 depth first order |
| 958 | 1006 |
| 959 :param recurs: | 1007 :param recurs: |
| 960 boolean indicating if it should recurse or return direct | 1008 boolean indicating if it should recurse or return direct |
| 961 ancestors only | 1009 ancestors only |
| 962 """ | 1010 """ |
| 963 # FIXME: should be possible to choose the resolution order | 1011 # FIXME: should be possible to choose the resolution order |
| 964 # XXX inference make infinite loops possible here (see BaseTransformer | 1012 # FIXME: inference make infinite loops possible here |
| 965 # manipulation in the builder module for instance) | |
| 966 yielded = set([self]) | 1013 yielded = set([self]) |
| 967 if context is None: | 1014 if context is None: |
| 968 context = InferenceContext() | 1015 context = InferenceContext() |
| 1016 if sys.version_info[0] >= 3: |
| 1017 if not self.bases and self.qname() != 'builtins.object': |
| 1018 yield builtin_lookup("object")[1][0] |
| 1019 return |
| 1020 |
| 969 for stmt in self.bases: | 1021 for stmt in self.bases: |
| 970 with context.restore_path(): | 1022 try: |
| 971 try: | 1023 for baseobj in stmt.infer(context): |
| 972 for baseobj in stmt.infer(context): | 1024 if not isinstance(baseobj, Class): |
| 973 if not isinstance(baseobj, Class): | 1025 if isinstance(baseobj, Instance): |
| 974 if isinstance(baseobj, Instance): | 1026 baseobj = baseobj._proxied |
| 975 baseobj = baseobj._proxied | 1027 else: |
| 976 else: | 1028 # duh ? |
| 977 # duh ? | 1029 continue |
| 978 continue | 1030 if not baseobj.hide: |
| 979 if baseobj in yielded: | 1031 if baseobj in yielded: |
| 980 continue # cf xxx above | 1032 continue # cf xxx above |
| 981 yielded.add(baseobj) | 1033 yielded.add(baseobj) |
| 982 yield baseobj | 1034 yield baseobj |
| 983 if recurs: | 1035 if recurs: |
| 984 for grandpa in baseobj.ancestors(True, context): | 1036 for grandpa in baseobj.ancestors(recurs=True, |
| 985 if grandpa in yielded: | 1037 context=context): |
| 986 continue # cf xxx above | 1038 if grandpa in yielded: |
| 987 yielded.add(grandpa) | 1039 continue # cf xxx above |
| 988 yield grandpa | 1040 yielded.add(grandpa) |
| 989 except InferenceError: | 1041 yield grandpa |
| 990 # XXX log error ? | 1042 except InferenceError: |
| 991 continue | 1043 # XXX log error ? |
| 1044 continue |
| 992 | 1045 |
| 993 def local_attr_ancestors(self, name, context=None): | 1046 def local_attr_ancestors(self, name, context=None): |
| 994 """return an iterator on astroid representation of parent classes | 1047 """return an iterator on astroid representation of parent classes |
| 995 which have <name> defined in their locals | 1048 which have <name> defined in their locals |
| 996 """ | 1049 """ |
| 997 for astroid in self.ancestors(context=context): | 1050 for astroid in self.ancestors(context=context): |
| 998 if name in astroid: | 1051 if name in astroid: |
| 999 yield astroid | 1052 yield astroid |
| 1000 | 1053 |
| 1001 def instance_attr_ancestors(self, name, context=None): | 1054 def instance_attr_ancestors(self, name, context=None): |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1076 if not values: | 1129 if not values: |
| 1077 raise NotFoundError(name) | 1130 raise NotFoundError(name) |
| 1078 return values | 1131 return values |
| 1079 | 1132 |
| 1080 def igetattr(self, name, context=None): | 1133 def igetattr(self, name, context=None): |
| 1081 """inferred getattr, need special treatment in class to handle | 1134 """inferred getattr, need special treatment in class to handle |
| 1082 descriptors | 1135 descriptors |
| 1083 """ | 1136 """ |
| 1084 # set lookup name since this is necessary to infer on import nodes for | 1137 # set lookup name since this is necessary to infer on import nodes for |
| 1085 # instance | 1138 # instance |
| 1086 context = copy_context(context) | 1139 if not context: |
| 1087 context.lookupname = name | 1140 context = InferenceContext() |
| 1088 try: | 1141 try: |
| 1089 for infered in _infer_stmts(self.getattr(name, context), context, | 1142 for infered in _infer_stmts(self.getattr(name, context), context, |
| 1090 frame=self): | 1143 frame=self, lookupname=name): |
| 1091 # yield YES object instead of descriptors when necessary | 1144 # yield YES object instead of descriptors when necessary |
| 1092 if not isinstance(infered, Const) and isinstance(infered, Instan
ce): | 1145 if not isinstance(infered, Const) and isinstance(infered, Instan
ce): |
| 1093 try: | 1146 try: |
| 1094 infered._proxied.getattr('__get__', context) | 1147 infered._proxied.getattr('__get__', context) |
| 1095 except NotFoundError: | 1148 except NotFoundError: |
| 1096 yield infered | 1149 yield infered |
| 1097 else: | 1150 else: |
| 1098 yield YES | 1151 yield YES |
| 1099 else: | 1152 else: |
| 1100 yield function_to_method(infered, self) | 1153 yield function_to_method(infered, self) |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1171 def _explicit_metaclass(self): | 1224 def _explicit_metaclass(self): |
| 1172 """ Return the explicit defined metaclass | 1225 """ Return the explicit defined metaclass |
| 1173 for the current class. | 1226 for the current class. |
| 1174 | 1227 |
| 1175 An explicit defined metaclass is defined | 1228 An explicit defined metaclass is defined |
| 1176 either by passing the ``metaclass`` keyword argument | 1229 either by passing the ``metaclass`` keyword argument |
| 1177 in the class definition line (Python 3) or (Python 2) by | 1230 in the class definition line (Python 3) or (Python 2) by |
| 1178 having a ``__metaclass__`` class attribute, or if there are | 1231 having a ``__metaclass__`` class attribute, or if there are |
| 1179 no explicit bases but there is a global ``__metaclass__`` variable. | 1232 no explicit bases but there is a global ``__metaclass__`` variable. |
| 1180 """ | 1233 """ |
| 1234 for base in self.bases: |
| 1235 try: |
| 1236 for baseobj in base.infer(): |
| 1237 if isinstance(baseobj, Class) and baseobj.hide: |
| 1238 self._metaclass = baseobj._metaclass |
| 1239 self._metaclass_hack = True |
| 1240 break |
| 1241 except InferenceError: |
| 1242 pass |
| 1243 |
| 1181 if self._metaclass: | 1244 if self._metaclass: |
| 1182 # Expects this from Py3k TreeRebuilder | 1245 # Expects this from Py3k TreeRebuilder |
| 1183 try: | 1246 try: |
| 1184 return next(node for node in self._metaclass.infer() | 1247 return next(node for node in self._metaclass.infer() |
| 1185 if node is not YES) | 1248 if node is not YES) |
| 1186 except (InferenceError, StopIteration): | 1249 except (InferenceError, StopIteration): |
| 1187 return None | 1250 return None |
| 1188 if sys.version_info >= (3, ): | 1251 if sys.version_info >= (3, ): |
| 1189 return None | 1252 return None |
| 1190 | 1253 |
| 1191 if '__metaclass__' in self.locals: | 1254 if '__metaclass__' in self.locals: |
| 1192 assignment = self.locals['__metaclass__'][-1] | 1255 assignment = self.locals['__metaclass__'][-1] |
| 1193 elif self.bases: | 1256 elif self.bases: |
| 1194 return None | 1257 return None |
| 1195 elif '__metaclass__' in self.root().locals: | 1258 elif '__metaclass__' in self.root().locals: |
| 1196 assignments = [ass for ass in self.root().locals['__metaclass__'] | 1259 assignments = [ass for ass in self.root().locals['__metaclass__'] |
| 1197 if ass.lineno < self.lineno] | 1260 if ass.lineno < self.lineno] |
| 1198 if not assignments: | 1261 if not assignments: |
| 1199 return None | 1262 return None |
| 1200 assignment = assignments[-1] | 1263 assignment = assignments[-1] |
| 1201 else: | 1264 else: |
| 1202 return None | 1265 return None |
| 1203 | 1266 |
| 1204 try: | 1267 try: |
| 1205 infered = assignment.infer().next() | 1268 infered = next(assignment.infer()) |
| 1206 except InferenceError: | 1269 except InferenceError: |
| 1207 return | 1270 return |
| 1208 if infered is YES: # don't expose this | 1271 if infered is YES: # don't expose this |
| 1209 return None | 1272 return None |
| 1210 return infered | 1273 return infered |
| 1211 | 1274 |
| 1212 def metaclass(self): | 1275 def metaclass(self): |
| 1213 """ Return the metaclass of this class. | 1276 """ Return the metaclass of this class. |
| 1214 | 1277 |
| 1215 If this class does not define explicitly a metaclass, | 1278 If this class does not define explicitly a metaclass, |
| 1216 then the first defined metaclass in ancestors will be used | 1279 then the first defined metaclass in ancestors will be used |
| 1217 instead. | 1280 instead. |
| 1218 """ | 1281 """ |
| 1219 klass = self._explicit_metaclass() | 1282 klass = self._explicit_metaclass() |
| 1220 if klass is None: | 1283 if klass is None: |
| 1221 for parent in self.ancestors(): | 1284 for parent in self.ancestors(): |
| 1222 klass = parent.metaclass() | 1285 klass = parent.metaclass() |
| 1223 if klass is not None: | 1286 if klass is not None: |
| 1224 break | 1287 break |
| 1225 return klass | 1288 return klass |
| 1226 | 1289 |
| 1290 def has_metaclass_hack(self): |
| 1291 return self._metaclass_hack |
| 1292 |
| 1227 def _islots(self): | 1293 def _islots(self): |
| 1228 """ Return an iterator with the inferred slots. """ | 1294 """ Return an iterator with the inferred slots. """ |
| 1229 if '__slots__' not in self.locals: | 1295 if '__slots__' not in self.locals: |
| 1230 return | 1296 return |
| 1231 for slots in self.igetattr('__slots__'): | 1297 for slots in self.igetattr('__slots__'): |
| 1232 # check if __slots__ is a valid type | 1298 # check if __slots__ is a valid type |
| 1233 for meth in ITER_METHODS: | 1299 for meth in ITER_METHODS: |
| 1234 try: | 1300 try: |
| 1235 slots.getattr(meth) | 1301 slots.getattr(meth) |
| 1236 break | 1302 break |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1268 continue | 1334 continue |
| 1269 yield infered | 1335 yield infered |
| 1270 except InferenceError: | 1336 except InferenceError: |
| 1271 continue | 1337 continue |
| 1272 | 1338 |
| 1273 # Cached, because inferring them all the time is expensive | 1339 # Cached, because inferring them all the time is expensive |
| 1274 @cached | 1340 @cached |
| 1275 def slots(self): | 1341 def slots(self): |
| 1276 """ Return all the slots for this node. """ | 1342 """ Return all the slots for this node. """ |
| 1277 return list(self._islots()) | 1343 return list(self._islots()) |
| OLD | NEW |