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 |