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

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

Issue 1920403002: [content/test/gpu] Run pylint check of gpu tests in unittest instead of PRESUBMIT (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update path to LICENSE.txt of logilab/README.chromium Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 #
4 # This file is part of astroid.
5 #
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
8 # Free Software Foundation, either version 2.1 of the License, or (at your
9 # option) any later version.
10 #
11 # astroid is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 # for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License along
17 # with astroid. If not, see <http://www.gnu.org/licenses/>.
18 """This module contains the classes for "scoped" node, i.e. which are opening a
19 new local scope in the language definition : Module, Class, Function (and
20 Lambda, GenExpr, DictComp and SetComp to some extent).
21 """
22 from __future__ import with_statement
23
24 __doctype__ = "restructuredtext en"
25
26 import sys
27 import warnings
28 from itertools import chain
29 try:
30 from io import BytesIO
31 except ImportError:
32 from cStringIO import StringIO as BytesIO
33
34 import six
35 from logilab.common.compat import builtins
36 from logilab.common.decorators import cached, cachedproperty
37
38 from astroid.exceptions import NotFoundError, \
39 AstroidBuildingException, InferenceError, ResolveError
40 from astroid.node_classes import Const, DelName, DelAttr, \
41 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \
42 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc
43 from astroid.bases import NodeNG, InferenceContext, Instance,\
44 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, \
45 BUILTINS
46 from astroid.mixins import FilterStmtsMixin
47 from astroid.bases import Statement
48 from astroid.manager import AstroidManager
49
50 ITER_METHODS = ('__iter__', '__getitem__')
51 PY3K = sys.version_info >= (3, 0)
52
53 def _c3_merge(sequences):
54 """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
55
56 Adapted from http://www.python.org/download/releases/2.3/mro/.
57
58 """
59 result = []
60 while True:
61 sequences = [s for s in sequences if s] # purge empty sequences
62 if not sequences:
63 return result
64 for s1 in sequences: # find merge candidates among seq heads
65 candidate = s1[0]
66 for s2 in sequences:
67 if candidate in s2[1:]:
68 candidate = None
69 break # reject the current head, it appears later
70 else:
71 break
72 if not candidate:
73 # Show all the remaining bases, which were considered as
74 # candidates for the next mro sequence.
75 bases = ["({})".format(", ".join(base.name
76 for base in subsequence))
77 for subsequence in sequences]
78 raise ResolveError("Cannot create a consistent method resolution "
79 "order for bases %s" % ", ".join(bases))
80 result.append(candidate)
81 # remove the chosen candidate
82 for seq in sequences:
83 if seq[0] == candidate:
84 del seq[0]
85
86
87 def _verify_duplicates_mro(sequences):
88 for sequence in sequences:
89 names = [node.qname() for node in sequence]
90 if len(names) != len(set(names)):
91 raise ResolveError('Duplicates found in the mro.')
92
93
94 def remove_nodes(func, cls):
95 def wrapper(*args, **kwargs):
96 nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)]
97 if not nodes:
98 raise NotFoundError()
99 return nodes
100 return wrapper
101
102
103 def function_to_method(n, klass):
104 if isinstance(n, Function):
105 if n.type == 'classmethod':
106 return BoundMethod(n, klass)
107 if n.type != 'staticmethod':
108 return UnboundMethod(n)
109 return n
110
111 def std_special_attributes(self, name, add_locals=True):
112 if add_locals:
113 locals = self.locals
114 else:
115 locals = {}
116 if name == '__name__':
117 return [cf(self.name)] + locals.get(name, [])
118 if name == '__doc__':
119 return [cf(self.doc)] + locals.get(name, [])
120 if name == '__dict__':
121 return [Dict()] + locals.get(name, [])
122 raise NotFoundError(name)
123
124 MANAGER = AstroidManager()
125 def builtin_lookup(name):
126 """lookup a name into the builtin module
127 return the list of matching statements and the astroid for the builtin
128 module
129 """
130 builtin_astroid = MANAGER.ast_from_module(builtins)
131 if name == '__dict__':
132 return builtin_astroid, ()
133 try:
134 stmts = builtin_astroid.locals[name]
135 except KeyError:
136 stmts = ()
137 return builtin_astroid, stmts
138
139
140 # TODO move this Mixin to mixins.py; problem: 'Function' in _scope_lookup
141 class LocalsDictNodeNG(LookupMixIn, NodeNG):
142 """ this class provides locals handling common to Module, Function
143 and Class nodes, including a dict like interface for direct access
144 to locals information
145 """
146
147 # attributes below are set by the builder module or by raw factories
148
149 # dictionary of locals with name as key and node defining the local as
150 # value
151
152 def qname(self):
153 """return the 'qualified' name of the node, eg module.name,
154 module.class.name ...
155 """
156 if self.parent is None:
157 return self.name
158 return '%s.%s' % (self.parent.frame().qname(), self.name)
159
160 def frame(self):
161 """return the first parent frame node (i.e. Module, Function or Class)
162 """
163 return self
164
165 def scope(self):
166 """return the first node defining a new scope (i.e. Module,
167 Function, Class, Lambda but also GenExpr, DictComp and SetComp)
168 """
169 return self
170
171
172 def _scope_lookup(self, node, name, offset=0):
173 """XXX method for interfacing the scope lookup"""
174 try:
175 stmts = node._filter_stmts(self.locals[name], self, offset)
176 except KeyError:
177 stmts = ()
178 if stmts:
179 return self, stmts
180 if self.parent: # i.e. not Module
181 # nested scope: if parent scope is a function, that's fine
182 # else jump to the module
183 pscope = self.parent.scope()
184 if not pscope.is_function:
185 pscope = pscope.root()
186 return pscope.scope_lookup(node, name)
187 return builtin_lookup(name) # Module
188
189
190
191 def set_local(self, name, stmt):
192 """define <name> in locals (<stmt> is the node defining the name)
193 if the node is a Module node (i.e. has globals), add the name to
194 globals
195
196 if the name is already defined, ignore it
197 """
198 #assert not stmt in self.locals.get(name, ()), (self, stmt)
199 self.locals.setdefault(name, []).append(stmt)
200
201 __setitem__ = set_local
202
203 def _append_node(self, child):
204 """append a child, linking it in the tree"""
205 self.body.append(child)
206 child.parent = self
207
208 def add_local_node(self, child_node, name=None):
209 """append a child which should alter locals to the given node"""
210 if name != '__class__':
211 # add __class__ node as a child will cause infinite recursion later!
212 self._append_node(child_node)
213 self.set_local(name or child_node.name, child_node)
214
215
216 def __getitem__(self, item):
217 """method from the `dict` interface returning the first node
218 associated with the given name in the locals dictionary
219
220 :type item: str
221 :param item: the name of the locally defined object
222 :raises KeyError: if the name is not defined
223 """
224 return self.locals[item][0]
225
226 def __iter__(self):
227 """method from the `dict` interface returning an iterator on
228 `self.keys()`
229 """
230 return iter(self.keys())
231
232 def keys(self):
233 """method from the `dict` interface returning a tuple containing
234 locally defined names
235 """
236 return list(self.locals.keys())
237
238 def values(self):
239 """method from the `dict` interface returning a tuple containing
240 locally defined nodes which are instance of `Function` or `Class`
241 """
242 return [self[key] for key in self.keys()]
243
244 def items(self):
245 """method from the `dict` interface returning a list of tuple
246 containing each locally defined name with its associated node,
247 which is an instance of `Function` or `Class`
248 """
249 return list(zip(self.keys(), self.values()))
250
251
252 def __contains__(self, name):
253 return name in self.locals
254 has_key = __contains__
255
256 # Module #####################################################################
257
258 class Module(LocalsDictNodeNG):
259 _astroid_fields = ('body',)
260
261 fromlineno = 0
262 lineno = 0
263
264 # attributes below are set by the builder module or by raw factories
265
266 # the file from which as been extracted the astroid representation. It may
267 # be None if the representation has been built from a built-in module
268 file = None
269 # Alternatively, if built from a string/bytes, this can be set
270 file_bytes = None
271 # encoding of python source file, so we can get unicode out of it (python2
272 # only)
273 file_encoding = None
274 # the module name
275 name = None
276 # boolean for astroid built from source (i.e. ast)
277 pure_python = None
278 # boolean for package module
279 package = None
280 # dictionary of globals with name as key and node defining the global
281 # as value
282 globals = None
283
284 # Future imports
285 future_imports = None
286
287 # names of python special attributes (handled by getattr impl.)
288 special_attributes = set(('__name__', '__doc__', '__file__', '__path__',
289 '__dict__'))
290 # names of module attributes available through the global scope
291 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__'))
292
293 def __init__(self, name, doc, pure_python=True):
294 self.name = name
295 self.doc = doc
296 self.pure_python = pure_python
297 self.locals = self.globals = {}
298 self.body = []
299 self.future_imports = set()
300
301 def _get_stream(self):
302 if self.file_bytes is not None:
303 return BytesIO(self.file_bytes)
304 if self.file is not None:
305 stream = open(self.file, 'rb')
306 return stream
307 return None
308
309 @property
310 def file_stream(self):
311 warnings.warn("file_stream property is deprecated and "
312 "it is slated for removal in astroid 1.6."
313 "Use the new method 'stream' instead.",
314 PendingDeprecationWarning,
315 stacklevel=2)
316 return self._get_stream()
317
318 def stream(self):
319 """Get a stream to the underlying file or bytes."""
320 return self._get_stream()
321
322 def close(self):
323 """Close the underlying file streams."""
324 warnings.warn("close method is deprecated and it is "
325 "slated for removal in astroid 1.6, along "
326 "with 'file_stream' property. "
327 "Its behaviour is replaced by managing each "
328 "file stream returned by the 'stream' method.",
329 PendingDeprecationWarning,
330 stacklevel=2)
331
332 def block_range(self, lineno):
333 """return block line numbers.
334
335 start from the beginning whatever the given lineno
336 """
337 return self.fromlineno, self.tolineno
338
339 def scope_lookup(self, node, name, offset=0):
340 if name in self.scope_attrs and not name in self.locals:
341 try:
342 return self, self.getattr(name)
343 except NotFoundError:
344 return self, ()
345 return self._scope_lookup(node, name, offset)
346
347 def pytype(self):
348 return '%s.module' % BUILTINS
349
350 def display_type(self):
351 return 'Module'
352
353 def getattr(self, name, context=None, ignore_locals=False):
354 if name in self.special_attributes:
355 if name == '__file__':
356 return [cf(self.file)] + self.locals.get(name, [])
357 if name == '__path__' and self.package:
358 return [List()] + self.locals.get(name, [])
359 return std_special_attributes(self, name)
360 if not ignore_locals and name in self.locals:
361 return self.locals[name]
362 if self.package:
363 try:
364 return [self.import_module(name, relative_only=True)]
365 except AstroidBuildingException:
366 raise NotFoundError(name)
367 except SyntaxError:
368 raise NotFoundError(name)
369 except Exception:# XXX pylint tests never pass here; do we need it?
370 import traceback
371 traceback.print_exc()
372 raise NotFoundError(name)
373 getattr = remove_nodes(getattr, DelName)
374
375 def igetattr(self, name, context=None):
376 """inferred getattr"""
377 # set lookup name since this is necessary to infer on import nodes for
378 # instance
379 if not context:
380 context = InferenceContext()
381 try:
382 return _infer_stmts(self.getattr(name, context), context, frame=self , lookupname=name)
383 except NotFoundError:
384 raise InferenceError(name)
385
386 def fully_defined(self):
387 """return True if this module has been built from a .py file
388 and so contains a complete representation including the code
389 """
390 return self.file is not None and self.file.endswith('.py')
391
392 def statement(self):
393 """return the first parent node marked as statement node
394 consider a module as a statement...
395 """
396 return self
397
398 def previous_sibling(self):
399 """module has no sibling"""
400 return
401
402 def next_sibling(self):
403 """module has no sibling"""
404 return
405
406 if sys.version_info < (2, 8):
407 @cachedproperty
408 def _absolute_import_activated(self):
409 for stmt in self.locals.get('absolute_import', ()):
410 if isinstance(stmt, From) and stmt.modname == '__future__':
411 return True
412 return False
413 else:
414 _absolute_import_activated = True
415
416 def absolute_import_activated(self):
417 return self._absolute_import_activated
418
419 def import_module(self, modname, relative_only=False, level=None):
420 """import the given module considering self as context"""
421 if relative_only and level is None:
422 level = 0
423 absmodname = self.relative_to_absolute_name(modname, level)
424 try:
425 return MANAGER.ast_from_module_name(absmodname)
426 except AstroidBuildingException:
427 # we only want to import a sub module or package of this module,
428 # skip here
429 if relative_only:
430 raise
431 return MANAGER.ast_from_module_name(modname)
432
433 def relative_to_absolute_name(self, modname, level):
434 """return the absolute module name for a relative import.
435
436 The relative import can be implicit or explicit.
437 """
438 # XXX this returns non sens when called on an absolute import
439 # like 'pylint.checkers.astroid.utils'
440 # XXX doesn't return absolute name if self.name isn't absolute name
441 if self.absolute_import_activated() and level is None:
442 return modname
443 if level:
444 if self.package:
445 level = level - 1
446 package_name = self.name.rsplit('.', level)[0]
447 elif self.package:
448 package_name = self.name
449 else:
450 package_name = self.name.rsplit('.', 1)[0]
451 if package_name:
452 if not modname:
453 return package_name
454 return '%s.%s' % (package_name, modname)
455 return modname
456
457
458 def wildcard_import_names(self):
459 """return the list of imported names when this module is 'wildcard
460 imported'
461
462 It doesn't include the '__builtins__' name which is added by the
463 current CPython implementation of wildcard imports.
464 """
465 # take advantage of a living module if it exists
466 try:
467 living = sys.modules[self.name]
468 except KeyError:
469 pass
470 else:
471 try:
472 return living.__all__
473 except AttributeError:
474 return [name for name in living.__dict__.keys()
475 if not name.startswith('_')]
476 # else lookup the astroid
477 #
478 # We separate the different steps of lookup in try/excepts
479 # to avoid catching too many Exceptions
480 default = [name for name in self.keys() if not name.startswith('_')]
481 try:
482 all = self['__all__']
483 except KeyError:
484 return default
485 try:
486 explicit = next(all.assigned_stmts())
487 except InferenceError:
488 return default
489 except AttributeError:
490 # not an assignment node
491 # XXX infer?
492 return default
493
494 # Try our best to detect the exported name.
495 infered = []
496 try:
497 explicit = next(explicit.infer())
498 except InferenceError:
499 return default
500 if not isinstance(explicit, (Tuple, List)):
501 return default
502
503 str_const = lambda node: (isinstance(node, Const) and
504 isinstance(node.value, six.string_types))
505 for node in explicit.elts:
506 if str_const(node):
507 infered.append(node.value)
508 else:
509 try:
510 infered_node = next(node.infer())
511 except InferenceError:
512 continue
513 if str_const(infered_node):
514 infered.append(infered_node.value)
515 return infered
516
517
518
519 class ComprehensionScope(LocalsDictNodeNG):
520 def frame(self):
521 return self.parent.frame()
522
523 scope_lookup = LocalsDictNodeNG._scope_lookup
524
525
526 class GenExpr(ComprehensionScope):
527 _astroid_fields = ('elt', 'generators')
528
529 def __init__(self):
530 self.locals = {}
531 self.elt = None
532 self.generators = []
533
534
535 class DictComp(ComprehensionScope):
536 _astroid_fields = ('key', 'value', 'generators')
537
538 def __init__(self):
539 self.locals = {}
540 self.key = None
541 self.value = None
542 self.generators = []
543
544
545 class SetComp(ComprehensionScope):
546 _astroid_fields = ('elt', 'generators')
547
548 def __init__(self):
549 self.locals = {}
550 self.elt = None
551 self.generators = []
552
553
554 class _ListComp(NodeNG):
555 """class representing a ListComp node"""
556 _astroid_fields = ('elt', 'generators')
557 elt = None
558 generators = None
559
560 if sys.version_info >= (3, 0):
561 class ListComp(_ListComp, ComprehensionScope):
562 """class representing a ListComp node"""
563 def __init__(self):
564 self.locals = {}
565 else:
566 class ListComp(_ListComp):
567 """class representing a ListComp node"""
568
569 # Function ###################################################################
570
571 def _infer_decorator_callchain(node):
572 """Detect decorator call chaining and see if the end result is a
573 static or a classmethod.
574 """
575 if not isinstance(node, Function):
576 return
577 if not node.parent:
578 return
579 try:
580 # TODO: We don't handle multiple inference results right now,
581 # because there's no flow to reason when the return
582 # is what we are looking for, a static or a class method.
583 result = next(node.infer_call_result(node.parent))
584 except (StopIteration, InferenceError):
585 return
586 if isinstance(result, Instance):
587 result = result._proxied
588 if isinstance(result, Class):
589 if result.is_subtype_of('%s.classmethod' % BUILTINS):
590 return 'classmethod'
591 if result.is_subtype_of('%s.staticmethod' % BUILTINS):
592 return 'staticmethod'
593
594
595 def _function_type(self):
596 """
597 Function type, possible values are:
598 method, function, staticmethod, classmethod.
599 """
600 # Can't infer that this node is decorated
601 # with a subclass of `classmethod` where `type` is first set,
602 # so do it here.
603 if self.decorators:
604 for node in self.decorators.nodes:
605 if isinstance(node, CallFunc):
606 # Handle the following case:
607 # @some_decorator(arg1, arg2)
608 # def func(...)
609 #
610 try:
611 current = next(node.func.infer())
612 except InferenceError:
613 continue
614 _type = _infer_decorator_callchain(current)
615 if _type is not None:
616 return _type
617
618 try:
619 for infered in node.infer():
620 # Check to see if this returns a static or a class method.
621 _type = _infer_decorator_callchain(infered)
622 if _type is not None:
623 return _type
624
625 if not isinstance(infered, Class):
626 continue
627 for ancestor in infered.ancestors():
628 if not isinstance(ancestor, Class):
629 continue
630 if ancestor.is_subtype_of('%s.classmethod' % BUILTINS):
631 return 'classmethod'
632 elif ancestor.is_subtype_of('%s.staticmethod' % BUILTINS ):
633 return 'staticmethod'
634 except InferenceError:
635 pass
636 return self._type
637
638
639 class Lambda(LocalsDictNodeNG, FilterStmtsMixin):
640 _astroid_fields = ('args', 'body',)
641 name = '<lambda>'
642
643 # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod'
644 type = 'function'
645
646 def __init__(self):
647 self.locals = {}
648 self.args = []
649 self.body = []
650
651 def pytype(self):
652 if 'method' in self.type:
653 return '%s.instancemethod' % BUILTINS
654 return '%s.function' % BUILTINS
655
656 def display_type(self):
657 if 'method' in self.type:
658 return 'Method'
659 return 'Function'
660
661 def callable(self):
662 return True
663
664 def argnames(self):
665 """return a list of argument names"""
666 if self.args.args: # maybe None with builtin functions
667 names = _rec_get_names(self.args.args)
668 else:
669 names = []
670 if self.args.vararg:
671 names.append(self.args.vararg)
672 if self.args.kwarg:
673 names.append(self.args.kwarg)
674 return names
675
676 def infer_call_result(self, caller, context=None):
677 """infer what a function is returning when called"""
678 return self.body.infer(context)
679
680 def scope_lookup(self, node, name, offset=0):
681 if node in self.args.defaults or node in self.args.kw_defaults:
682 frame = self.parent.frame()
683 # line offset to avoid that def func(f=func) resolve the default
684 # value to the defined function
685 offset = -1
686 else:
687 # check this is not used in function decorators
688 frame = self
689 return frame._scope_lookup(node, name, offset)
690
691
692 class Function(Statement, Lambda):
693 if PY3K:
694 _astroid_fields = ('decorators', 'args', 'body', 'returns')
695 returns = None
696 else:
697 _astroid_fields = ('decorators', 'args', 'body')
698
699 special_attributes = set(('__name__', '__doc__', '__dict__'))
700 is_function = True
701 # attributes below are set by the builder module or by raw factories
702 blockstart_tolineno = None
703 decorators = None
704 _type = "function"
705 type = cachedproperty(_function_type)
706
707 def __init__(self, name, doc):
708 self.locals = {}
709 self.args = []
710 self.body = []
711 self.name = name
712 self.doc = doc
713 self.extra_decorators = []
714 self.instance_attrs = {}
715
716 @cachedproperty
717 def fromlineno(self):
718 # lineno is the line number of the first decorator, we want the def
719 # statement lineno
720 lineno = self.lineno
721 if self.decorators is not None:
722 lineno += sum(node.tolineno - node.lineno + 1
723 for node in self.decorators.nodes)
724
725 return lineno
726
727 @cachedproperty
728 def blockstart_tolineno(self):
729 return self.args.tolineno
730
731 def block_range(self, lineno):
732 """return block line numbers.
733
734 start from the "def" position whatever the given lineno
735 """
736 return self.fromlineno, self.tolineno
737
738 def getattr(self, name, context=None):
739 """this method doesn't look in the instance_attrs dictionary since it's
740 done by an Instance proxy at inference time.
741 """
742 if name == '__module__':
743 return [cf(self.root().qname())]
744 if name in self.instance_attrs:
745 return self.instance_attrs[name]
746 return std_special_attributes(self, name, False)
747
748 def is_method(self):
749 """return true if the function node should be considered as a method"""
750 # check we are defined in a Class, because this is usually expected
751 # (e.g. pylint...) when is_method() return True
752 return self.type != 'function' and isinstance(self.parent.frame(), Class )
753
754 def decoratornames(self):
755 """return a list of decorator qualified names"""
756 result = set()
757 decoratornodes = []
758 if self.decorators is not None:
759 decoratornodes += self.decorators.nodes
760 decoratornodes += self.extra_decorators
761 for decnode in decoratornodes:
762 for infnode in decnode.infer():
763 result.add(infnode.qname())
764 return result
765 decoratornames = cached(decoratornames)
766
767 def is_bound(self):
768 """return true if the function is bound to an Instance or a class"""
769 return self.type == 'classmethod'
770
771 def is_abstract(self, pass_is_abstract=True):
772 """Returns True if the method is abstract.
773
774 A method is considered abstract if
775 - the only statement is 'raise NotImplementedError', or
776 - the only statement is 'pass' and pass_is_abstract is True, or
777 - the method is annotated with abc.astractproperty/abc.abstractmethod
778 """
779 if self.decorators:
780 for node in self.decorators.nodes:
781 try:
782 infered = next(node.infer())
783 except InferenceError:
784 continue
785 if infered and infered.qname() in ('abc.abstractproperty',
786 'abc.abstractmethod'):
787 return True
788
789 for child_node in self.body:
790 if isinstance(child_node, Raise):
791 if child_node.raises_not_implemented():
792 return True
793 if pass_is_abstract and isinstance(child_node, Pass):
794 return True
795 return False
796 # empty function is the same as function with a single "pass" statement
797 if pass_is_abstract:
798 return True
799
800 def is_generator(self):
801 """return true if this is a generator function"""
802 # XXX should be flagged, not computed
803 return next(self.nodes_of_class((Yield, YieldFrom),
804 skip_klass=(Function, Lambda)), False)
805
806 def infer_call_result(self, caller, context=None):
807 """infer what a function is returning when called"""
808 if self.is_generator():
809 yield Generator()
810 return
811 # This is really a gigantic hack to work around metaclass generators
812 # that return transient class-generating functions. Pylint's AST structu re
813 # cannot handle a base class object that is only used for calling __new_ _,
814 # but does not contribute to the inheritance structure itself. We inject
815 # a fake class into the hierarchy here for several well-known metaclass
816 # generators, and filter it out later.
817 if (self.name == 'with_metaclass' and
818 len(self.args.args) == 1 and
819 self.args.vararg is not None):
820 metaclass = next(caller.args[0].infer(context))
821 if isinstance(metaclass, Class):
822 c = Class('temporary_class', None)
823 c.hide = True
824 c.parent = self
825 c.bases = [next(b.infer(context)) for b in caller.args[1:]]
826 c._metaclass = metaclass
827 yield c
828 return
829 returns = self.nodes_of_class(Return, skip_klass=Function)
830 for returnnode in returns:
831 if returnnode.value is None:
832 yield Const(None)
833 else:
834 try:
835 for infered in returnnode.value.infer(context):
836 yield infered
837 except InferenceError:
838 yield YES
839
840
841 def _rec_get_names(args, names=None):
842 """return a list of all argument names"""
843 if names is None:
844 names = []
845 for arg in args:
846 if isinstance(arg, Tuple):
847 _rec_get_names(arg.elts, names)
848 else:
849 names.append(arg.name)
850 return names
851
852
853 # Class ######################################################################
854
855
856 def _is_metaclass(klass, seen=None):
857 """ Return if the given class can be
858 used as a metaclass.
859 """
860 if klass.name == 'type':
861 return True
862 if seen is None:
863 seen = set()
864 for base in klass.bases:
865 try:
866 for baseobj in base.infer():
867 if baseobj in seen:
868 continue
869 else:
870 seen.add(baseobj)
871 if isinstance(baseobj, Instance):
872 # not abstract
873 return False
874 if baseobj is YES:
875 continue
876 if baseobj is klass:
877 continue
878 if not isinstance(baseobj, Class):
879 continue
880 if baseobj._type == 'metaclass':
881 return True
882 if _is_metaclass(baseobj, seen):
883 return True
884 except InferenceError:
885 continue
886 return False
887
888
889 def _class_type(klass, ancestors=None):
890 """return a Class node type to differ metaclass, interface and exception
891 from 'regular' classes
892 """
893 # XXX we have to store ancestors in case we have a ancestor loop
894 if klass._type is not None:
895 return klass._type
896 if _is_metaclass(klass):
897 klass._type = 'metaclass'
898 elif klass.name.endswith('Interface'):
899 klass._type = 'interface'
900 elif klass.name.endswith('Exception'):
901 klass._type = 'exception'
902 else:
903 if ancestors is None:
904 ancestors = set()
905 if klass in ancestors:
906 # XXX we are in loop ancestors, and have found no type
907 klass._type = 'class'
908 return 'class'
909 ancestors.add(klass)
910 for base in klass.ancestors(recurs=False):
911 name = _class_type(base, ancestors)
912 if name != 'class':
913 if name == 'metaclass' and not _is_metaclass(klass):
914 # don't propagate it if the current class
915 # can't be a metaclass
916 continue
917 klass._type = base.type
918 break
919 if klass._type is None:
920 klass._type = 'class'
921 return klass._type
922
923 def _iface_hdlr(iface_node):
924 """a handler function used by interfaces to handle suspicious
925 interface nodes
926 """
927 return True
928
929
930 class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin):
931
932 # some of the attributes below are set by the builder module or
933 # by a raw factories
934
935 # a dictionary of class instances attributes
936 _astroid_fields = ('decorators', 'bases', 'body') # name
937
938 decorators = None
939 special_attributes = set(('__name__', '__doc__', '__dict__', '__module__',
940 '__bases__', '__mro__', '__subclasses__'))
941 blockstart_tolineno = None
942
943 _type = None
944 _metaclass_hack = False
945 hide = False
946 type = property(_class_type,
947 doc="class'type, possible values are 'class' | "
948 "'metaclass' | 'interface' | 'exception'")
949
950 def __init__(self, name, doc):
951 self.instance_attrs = {}
952 self.locals = {}
953 self.bases = []
954 self.body = []
955 self.name = name
956 self.doc = doc
957
958 def _newstyle_impl(self, context=None):
959 if context is None:
960 context = InferenceContext()
961 if self._newstyle is not None:
962 return self._newstyle
963 for base in self.ancestors(recurs=False, context=context):
964 if base._newstyle_impl(context):
965 self._newstyle = True
966 break
967 klass = self._explicit_metaclass()
968 # could be any callable, we'd need to infer the result of klass(name,
969 # bases, dict). punt if it's not a class node.
970 if klass is not None and isinstance(klass, Class):
971 self._newstyle = klass._newstyle_impl(context)
972 if self._newstyle is None:
973 self._newstyle = False
974 return self._newstyle
975
976 _newstyle = None
977 newstyle = property(_newstyle_impl,
978 doc="boolean indicating if it's a new style class"
979 "or not")
980
981 @cachedproperty
982 def blockstart_tolineno(self):
983 if self.bases:
984 return self.bases[-1].tolineno
985 else:
986 return self.fromlineno
987
988 def block_range(self, lineno):
989 """return block line numbers.
990
991 start from the "class" position whatever the given lineno
992 """
993 return self.fromlineno, self.tolineno
994
995 def pytype(self):
996 if self.newstyle:
997 return '%s.type' % BUILTINS
998 return '%s.classobj' % BUILTINS
999
1000 def display_type(self):
1001 return 'Class'
1002
1003 def callable(self):
1004 return True
1005
1006 def is_subtype_of(self, type_name, context=None):
1007 if self.qname() == type_name:
1008 return True
1009 for anc in self.ancestors(context=context):
1010 if anc.qname() == type_name:
1011 return True
1012
1013 def infer_call_result(self, caller, context=None):
1014 """infer what a class is returning when called"""
1015 if self.is_subtype_of('%s.type' % (BUILTINS,), context) and len(caller.a rgs) == 3:
1016 name_node = next(caller.args[0].infer(context))
1017 if (isinstance(name_node, Const) and
1018 isinstance(name_node.value, six.string_types)):
1019 name = name_node.value
1020 else:
1021 yield YES
1022 return
1023 result = Class(name, None)
1024 bases = next(caller.args[1].infer(context))
1025 if isinstance(bases, (Tuple, List)):
1026 result.bases = bases.itered()
1027 else:
1028 # There is currently no AST node that can represent an 'unknown'
1029 # node (YES is not an AST node), therefore we simply return YES here
1030 # although we know at least the name of the class.
1031 yield YES
1032 return
1033 result.parent = caller.parent
1034 yield result
1035 else:
1036 yield Instance(self)
1037
1038 def scope_lookup(self, node, name, offset=0):
1039 if node in self.bases:
1040 frame = self.parent.frame()
1041 # line offset to avoid that class A(A) resolve the ancestor to
1042 # the defined class
1043 offset = -1
1044 else:
1045 frame = self
1046 return frame._scope_lookup(node, name, offset)
1047
1048 # list of parent class as a list of string (i.e. names as they appear
1049 # in the class definition) XXX bw compat
1050 def basenames(self):
1051 return [bnode.as_string() for bnode in self.bases]
1052 basenames = property(basenames)
1053
1054 def ancestors(self, recurs=True, context=None):
1055 """return an iterator on the node base classes in a prefixed
1056 depth first order
1057
1058 :param recurs:
1059 boolean indicating if it should recurse or return direct
1060 ancestors only
1061 """
1062 # FIXME: should be possible to choose the resolution order
1063 # FIXME: inference make infinite loops possible here
1064 yielded = set([self])
1065 if context is None:
1066 context = InferenceContext()
1067 if sys.version_info[0] >= 3:
1068 if not self.bases and self.qname() != 'builtins.object':
1069 yield builtin_lookup("object")[1][0]
1070 return
1071
1072 for stmt in self.bases:
1073 try:
1074 for baseobj in stmt.infer(context):
1075 if not isinstance(baseobj, Class):
1076 if isinstance(baseobj, Instance):
1077 baseobj = baseobj._proxied
1078 else:
1079 # duh ?
1080 continue
1081 if not baseobj.hide:
1082 if baseobj in yielded:
1083 continue # cf xxx above
1084 yielded.add(baseobj)
1085 yield baseobj
1086 if recurs:
1087 for grandpa in baseobj.ancestors(recurs=True,
1088 context=context):
1089 if grandpa in yielded:
1090 continue # cf xxx above
1091 yielded.add(grandpa)
1092 yield grandpa
1093 except InferenceError:
1094 # XXX log error ?
1095 continue
1096
1097 def local_attr_ancestors(self, name, context=None):
1098 """return an iterator on astroid representation of parent classes
1099 which have <name> defined in their locals
1100 """
1101 for astroid in self.ancestors(context=context):
1102 if name in astroid:
1103 yield astroid
1104
1105 def instance_attr_ancestors(self, name, context=None):
1106 """return an iterator on astroid representation of parent classes
1107 which have <name> defined in their instance attribute dictionary
1108 """
1109 for astroid in self.ancestors(context=context):
1110 if name in astroid.instance_attrs:
1111 yield astroid
1112
1113 def has_base(self, node):
1114 return node in self.bases
1115
1116 def local_attr(self, name, context=None):
1117 """return the list of assign node associated to name in this class
1118 locals or in its parents
1119
1120 :raises `NotFoundError`:
1121 if no attribute with this name has been find in this class or
1122 its parent classes
1123 """
1124 try:
1125 return self.locals[name]
1126 except KeyError:
1127 # get if from the first parent implementing it if any
1128 for class_node in self.local_attr_ancestors(name, context):
1129 return class_node.locals[name]
1130 raise NotFoundError(name)
1131 local_attr = remove_nodes(local_attr, DelAttr)
1132
1133 def instance_attr(self, name, context=None):
1134 """return the astroid nodes associated to name in this class instance
1135 attributes dictionary and in its parents
1136
1137 :raises `NotFoundError`:
1138 if no attribute with this name has been find in this class or
1139 its parent classes
1140 """
1141 # Return a copy, so we don't modify self.instance_attrs,
1142 # which could lead to infinite loop.
1143 values = list(self.instance_attrs.get(name, []))
1144 # get all values from parents
1145 for class_node in self.instance_attr_ancestors(name, context):
1146 values += class_node.instance_attrs[name]
1147 if not values:
1148 raise NotFoundError(name)
1149 return values
1150 instance_attr = remove_nodes(instance_attr, DelAttr)
1151
1152 def instanciate_class(self):
1153 """return Instance of Class node, else return self"""
1154 return Instance(self)
1155
1156 def getattr(self, name, context=None):
1157 """this method doesn't look in the instance_attrs dictionary since it's
1158 done by an Instance proxy at inference time.
1159
1160 It may return a YES object if the attribute has not been actually
1161 found but a __getattr__ or __getattribute__ method is defined
1162 """
1163 values = self.locals.get(name, [])
1164 if name in self.special_attributes:
1165 if name == '__module__':
1166 return [cf(self.root().qname())] + values
1167 # FIXME: do we really need the actual list of ancestors?
1168 # returning [Tuple()] + values don't break any test
1169 # this is ticket http://www.logilab.org/ticket/52785
1170 # XXX need proper meta class handling + MRO implementation
1171 if name == '__bases__' or (name == '__mro__' and self.newstyle):
1172 node = Tuple()
1173 node.items = self.ancestors(recurs=True, context=context)
1174 return [node] + values
1175 return std_special_attributes(self, name)
1176 # don't modify the list in self.locals!
1177 values = list(values)
1178 for classnode in self.ancestors(recurs=True, context=context):
1179 values += classnode.locals.get(name, [])
1180 if not values:
1181 raise NotFoundError(name)
1182 return values
1183
1184 def igetattr(self, name, context=None):
1185 """inferred getattr, need special treatment in class to handle
1186 descriptors
1187 """
1188 # set lookup name since this is necessary to infer on import nodes for
1189 # instance
1190 if not context:
1191 context = InferenceContext()
1192 try:
1193 for infered in _infer_stmts(self.getattr(name, context), context,
1194 frame=self, lookupname=name):
1195 # yield YES object instead of descriptors when necessary
1196 if not isinstance(infered, Const) and isinstance(infered, Instan ce):
1197 try:
1198 infered._proxied.getattr('__get__', context)
1199 except NotFoundError:
1200 yield infered
1201 else:
1202 yield YES
1203 else:
1204 yield function_to_method(infered, self)
1205 except NotFoundError:
1206 if not name.startswith('__') and self.has_dynamic_getattr(context):
1207 # class handle some dynamic attributes, return a YES object
1208 yield YES
1209 else:
1210 raise InferenceError(name)
1211
1212 def has_dynamic_getattr(self, context=None):
1213 """return True if the class has a custom __getattr__ or
1214 __getattribute__ method
1215 """
1216 # need to explicitly handle optparse.Values (setattr is not detected)
1217 if self.name == 'Values' and self.root().name == 'optparse':
1218 return True
1219 try:
1220 self.getattr('__getattr__', context)
1221 return True
1222 except NotFoundError:
1223 #if self.newstyle: XXX cause an infinite recursion error
1224 try:
1225 getattribute = self.getattr('__getattribute__', context)[0]
1226 if getattribute.root().name != BUILTINS:
1227 # class has a custom __getattribute__ defined
1228 return True
1229 except NotFoundError:
1230 pass
1231 return False
1232
1233 def methods(self):
1234 """return an iterator on all methods defined in the class and
1235 its ancestors
1236 """
1237 done = {}
1238 for astroid in chain(iter((self,)), self.ancestors()):
1239 for meth in astroid.mymethods():
1240 if meth.name in done:
1241 continue
1242 done[meth.name] = None
1243 yield meth
1244
1245 def mymethods(self):
1246 """return an iterator on all methods defined in the class"""
1247 for member in self.values():
1248 if isinstance(member, Function):
1249 yield member
1250
1251 def interfaces(self, herited=True, handler_func=_iface_hdlr):
1252 """return an iterator on interfaces implemented by the given
1253 class node
1254 """
1255 # FIXME: what if __implements__ = (MyIFace, MyParent.__implements__)...
1256 try:
1257 implements = Instance(self).getattr('__implements__')[0]
1258 except NotFoundError:
1259 return
1260 if not herited and not implements.frame() is self:
1261 return
1262 found = set()
1263 missing = False
1264 for iface in unpack_infer(implements):
1265 if iface is YES:
1266 missing = True
1267 continue
1268 if not iface in found and handler_func(iface):
1269 found.add(iface)
1270 yield iface
1271 if missing:
1272 raise InferenceError()
1273
1274 _metaclass = None
1275 def _explicit_metaclass(self):
1276 """ Return the explicit defined metaclass
1277 for the current class.
1278
1279 An explicit defined metaclass is defined
1280 either by passing the ``metaclass`` keyword argument
1281 in the class definition line (Python 3) or (Python 2) by
1282 having a ``__metaclass__`` class attribute, or if there are
1283 no explicit bases but there is a global ``__metaclass__`` variable.
1284 """
1285 for base in self.bases:
1286 try:
1287 for baseobj in base.infer():
1288 if isinstance(baseobj, Class) and baseobj.hide:
1289 self._metaclass = baseobj._metaclass
1290 self._metaclass_hack = True
1291 break
1292 except InferenceError:
1293 pass
1294
1295 if self._metaclass:
1296 # Expects this from Py3k TreeRebuilder
1297 try:
1298 return next(node for node in self._metaclass.infer()
1299 if node is not YES)
1300 except (InferenceError, StopIteration):
1301 return None
1302 if sys.version_info >= (3, ):
1303 return None
1304
1305 if '__metaclass__' in self.locals:
1306 assignment = self.locals['__metaclass__'][-1]
1307 elif self.bases:
1308 return None
1309 elif '__metaclass__' in self.root().locals:
1310 assignments = [ass for ass in self.root().locals['__metaclass__']
1311 if ass.lineno < self.lineno]
1312 if not assignments:
1313 return None
1314 assignment = assignments[-1]
1315 else:
1316 return None
1317
1318 try:
1319 infered = next(assignment.infer())
1320 except InferenceError:
1321 return
1322 if infered is YES: # don't expose this
1323 return None
1324 return infered
1325
1326 def metaclass(self):
1327 """ Return the metaclass of this class.
1328
1329 If this class does not define explicitly a metaclass,
1330 then the first defined metaclass in ancestors will be used
1331 instead.
1332 """
1333 klass = self._explicit_metaclass()
1334 if klass is None:
1335 for parent in self.ancestors():
1336 klass = parent.metaclass()
1337 if klass is not None:
1338 break
1339 return klass
1340
1341 def has_metaclass_hack(self):
1342 return self._metaclass_hack
1343
1344 def _islots(self):
1345 """ Return an iterator with the inferred slots. """
1346 if '__slots__' not in self.locals:
1347 return
1348 for slots in self.igetattr('__slots__'):
1349 # check if __slots__ is a valid type
1350 for meth in ITER_METHODS:
1351 try:
1352 slots.getattr(meth)
1353 break
1354 except NotFoundError:
1355 continue
1356 else:
1357 continue
1358
1359 if isinstance(slots, Const):
1360 # a string. Ignore the following checks,
1361 # but yield the node, only if it has a value
1362 if slots.value:
1363 yield slots
1364 continue
1365 if not hasattr(slots, 'itered'):
1366 # we can't obtain the values, maybe a .deque?
1367 continue
1368
1369 if isinstance(slots, Dict):
1370 values = [item[0] for item in slots.items]
1371 else:
1372 values = slots.itered()
1373 if values is YES:
1374 continue
1375
1376 for elt in values:
1377 try:
1378 for infered in elt.infer():
1379 if infered is YES:
1380 continue
1381 if (not isinstance(infered, Const) or
1382 not isinstance(infered.value,
1383 six.string_types)):
1384 continue
1385 if not infered.value:
1386 continue
1387 yield infered
1388 except InferenceError:
1389 continue
1390
1391 # Cached, because inferring them all the time is expensive
1392 @cached
1393 def slots(self):
1394 """Get all the slots for this node.
1395
1396 If the class doesn't define any slot, through `__slots__`
1397 variable, then this function will return a None.
1398 Also, it will return None in the case the slots weren't inferred.
1399 Otherwise, it will return a list of slot names.
1400 """
1401 slots = self._islots()
1402 try:
1403 first = next(slots)
1404 except StopIteration:
1405 # The class doesn't have a __slots__ definition.
1406 return None
1407 return [first] + list(slots)
1408
1409 def _inferred_bases(self, recurs=True, context=None):
1410 # TODO(cpopa): really similar with .ancestors,
1411 # but the difference is when one base is inferred,
1412 # only the first object is wanted. That's because
1413 # we aren't interested in superclasses, as in the following
1414 # example:
1415 #
1416 # class SomeSuperClass(object): pass
1417 # class SomeClass(SomeSuperClass): pass
1418 # class Test(SomeClass): pass
1419 #
1420 # Inferring SomeClass from the Test's bases will give
1421 # us both SomeClass and SomeSuperClass, but we are interested
1422 # only in SomeClass.
1423
1424 if context is None:
1425 context = InferenceContext()
1426 if sys.version_info[0] >= 3:
1427 if not self.bases and self.qname() != 'builtins.object':
1428 yield builtin_lookup("object")[1][0]
1429 return
1430
1431 for stmt in self.bases:
1432 try:
1433 baseobj = next(stmt.infer(context=context))
1434 except InferenceError:
1435 # XXX log error ?
1436 continue
1437 if isinstance(baseobj, Instance):
1438 baseobj = baseobj._proxied
1439 if not isinstance(baseobj, Class):
1440 continue
1441 if not baseobj.hide:
1442 yield baseobj
1443
1444 def mro(self, context=None):
1445 """Get the method resolution order, using C3 linearization.
1446
1447 It returns the list of ancestors sorted by the mro.
1448 This will raise `NotImplementedError` for old-style classes, since
1449 they don't have the concept of MRO.
1450 """
1451 if not self.newstyle:
1452 raise NotImplementedError(
1453 "Could not obtain mro for old-style classes.")
1454
1455 bases = list(self._inferred_bases(context=context))
1456 unmerged_mro = [[self]] + [base.mro() for base in bases] + [bases]
1457
1458 _verify_duplicates_mro(unmerged_mro)
1459 return _c3_merge(unmerged_mro)
OLDNEW
« no previous file with comments | « third_party/logilab/logilab/astroid/rebuilder.py ('k') | third_party/logilab/logilab/astroid/test_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698