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

Side by Side Diff: third_party/logilab/astroid/scoped_nodes.py

Issue 753543006: pylint: upgrade to 1.4.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/logilab/astroid/rebuilder.py ('k') | third_party/logilab/astroid/utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # copyright 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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())
OLDNEW
« no previous file with comments | « third_party/logilab/astroid/rebuilder.py ('k') | third_party/logilab/astroid/utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698