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

Side by Side Diff: third_party/logilab/logilab/astroid/node_classes.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 """Module for some node classes. More nodes in scoped_nodes.py
19 """
20
21 import sys
22
23 import six
24 import logilab
25 from logilab.common.decorators import cachedproperty
26
27 from astroid.exceptions import NoDefault
28 from astroid.bases import (NodeNG, Statement, Instance, InferenceContext,
29 _infer_stmts, YES, BUILTINS)
30 from astroid.mixins import (BlockRangeMixIn, AssignTypeMixin,
31 ParentAssignTypeMixin, FromImportMixIn)
32
33 PY3K = sys.version_info >= (3, 0)
34
35
36 def unpack_infer(stmt, context=None):
37 """recursively generate nodes inferred by the given statement.
38 If the inferred value is a list or a tuple, recurse on the elements
39 """
40 if isinstance(stmt, (List, Tuple)):
41 for elt in stmt.elts:
42 for infered_elt in unpack_infer(elt, context):
43 yield infered_elt
44 return
45 # if infered is a final node, return it and stop
46 infered = next(stmt.infer(context))
47 if infered is stmt:
48 yield infered
49 return
50 # else, infer recursivly, except YES object that should be returned as is
51 for infered in stmt.infer(context):
52 if infered is YES:
53 yield infered
54 else:
55 for inf_inf in unpack_infer(infered, context):
56 yield inf_inf
57
58
59 def are_exclusive(stmt1, stmt2, exceptions=None):
60 """return true if the two given statements are mutually exclusive
61
62 `exceptions` may be a list of exception names. If specified, discard If
63 branches and check one of the statement is in an exception handler catching
64 one of the given exceptions.
65
66 algorithm :
67 1) index stmt1's parents
68 2) climb among stmt2's parents until we find a common parent
69 3) if the common parent is a If or TryExcept statement, look if nodes are
70 in exclusive branches
71 """
72 # index stmt1's parents
73 stmt1_parents = {}
74 children = {}
75 node = stmt1.parent
76 previous = stmt1
77 while node:
78 stmt1_parents[node] = 1
79 children[node] = previous
80 previous = node
81 node = node.parent
82 # climb among stmt2's parents until we find a common parent
83 node = stmt2.parent
84 previous = stmt2
85 while node:
86 if node in stmt1_parents:
87 # if the common parent is a If or TryExcept statement, look if
88 # nodes are in exclusive branches
89 if isinstance(node, If) and exceptions is None:
90 if (node.locate_child(previous)[1]
91 is not node.locate_child(children[node])[1]):
92 return True
93 elif isinstance(node, TryExcept):
94 c2attr, c2node = node.locate_child(previous)
95 c1attr, c1node = node.locate_child(children[node])
96 if c1node is not c2node:
97 if ((c2attr == 'body' and c1attr == 'handlers' and children[ node].catch(exceptions)) or
98 (c2attr == 'handlers' and c1attr == 'body' and previ ous.catch(exceptions)) or
99 (c2attr == 'handlers' and c1attr == 'orelse') or
100 (c2attr == 'orelse' and c1attr == 'handlers')):
101 return True
102 elif c2attr == 'handlers' and c1attr == 'handlers':
103 return previous is not children[node]
104 return False
105 previous = node
106 node = node.parent
107 return False
108
109
110 class LookupMixIn(object):
111 """Mixin looking up a name in the right scope
112 """
113
114 def lookup(self, name):
115 """lookup a variable name
116
117 return the scope node and the list of assignments associated to the
118 given name according to the scope where it has been found (locals,
119 globals or builtin)
120
121 The lookup is starting from self's scope. If self is not a frame itself
122 and the name is found in the inner frame locals, statements will be
123 filtered to remove ignorable statements according to self's location
124 """
125 return self.scope().scope_lookup(self, name)
126
127 def ilookup(self, name):
128 """infered lookup
129
130 return an iterator on infered values of the statements returned by
131 the lookup method
132 """
133 frame, stmts = self.lookup(name)
134 return _infer_stmts(stmts, None, frame)
135
136 def _filter_stmts(self, stmts, frame, offset):
137 """filter statements to remove ignorable statements.
138
139 If self is not a frame itself and the name is found in the inner
140 frame locals, statements will be filtered to remove ignorable
141 statements according to self's location
142 """
143 # if offset == -1, my actual frame is not the inner frame but its parent
144 #
145 # class A(B): pass
146 #
147 # we need this to resolve B correctly
148 if offset == -1:
149 myframe = self.frame().parent.frame()
150 else:
151 myframe = self.frame()
152 # If the frame of this node is the same as the statement
153 # of this node, then the node is part of a class or
154 # a function definition and the frame of this node should be the
155 # the upper frame, not the frame of the definition.
156 # For more information why this is important,
157 # see Pylint issue #295.
158 # For example, for 'b', the statement is the same
159 # as the frame / scope:
160 #
161 # def test(b=1):
162 # ...
163
164 if self.statement() is myframe and myframe.parent:
165 myframe = myframe.parent.frame()
166 if not myframe is frame or self is frame:
167 return stmts
168 mystmt = self.statement()
169 # line filtering if we are in the same frame
170 #
171 # take care node may be missing lineno information (this is the case for
172 # nodes inserted for living objects)
173 if myframe is frame and mystmt.fromlineno is not None:
174 assert mystmt.fromlineno is not None, mystmt
175 mylineno = mystmt.fromlineno + offset
176 else:
177 # disabling lineno filtering
178 mylineno = 0
179 _stmts = []
180 _stmt_parents = []
181 for node in stmts:
182 stmt = node.statement()
183 # line filtering is on and we have reached our location, break
184 if mylineno > 0 and stmt.fromlineno > mylineno:
185 break
186 assert hasattr(node, 'ass_type'), (node, node.scope(),
187 node.scope().locals)
188 ass_type = node.ass_type()
189
190 if node.has_base(self):
191 break
192
193 _stmts, done = ass_type._get_filtered_stmts(self, node, _stmts, myst mt)
194 if done:
195 break
196
197 optional_assign = ass_type.optional_assign
198 if optional_assign and ass_type.parent_of(self):
199 # we are inside a loop, loop var assigment is hidding previous
200 # assigment
201 _stmts = [node]
202 _stmt_parents = [stmt.parent]
203 continue
204
205 # XXX comment various branches below!!!
206 try:
207 pindex = _stmt_parents.index(stmt.parent)
208 except ValueError:
209 pass
210 else:
211 # we got a parent index, this means the currently visited node
212 # is at the same block level as a previously visited node
213 if _stmts[pindex].ass_type().parent_of(ass_type):
214 # both statements are not at the same block level
215 continue
216 # if currently visited node is following previously considered
217 # assignement and both are not exclusive, we can drop the
218 # previous one. For instance in the following code ::
219 #
220 # if a:
221 # x = 1
222 # else:
223 # x = 2
224 # print x
225 #
226 # we can't remove neither x = 1 nor x = 2 when looking for 'x'
227 # of 'print x'; while in the following ::
228 #
229 # x = 1
230 # x = 2
231 # print x
232 #
233 # we can remove x = 1 when we see x = 2
234 #
235 # moreover, on loop assignment types, assignment won't
236 # necessarily be done if the loop has no iteration, so we don't
237 # want to clear previous assigments if any (hence the test on
238 # optional_assign)
239 if not (optional_assign or are_exclusive(_stmts[pindex], node)):
240 del _stmt_parents[pindex]
241 del _stmts[pindex]
242 if isinstance(node, AssName):
243 if not optional_assign and stmt.parent is mystmt.parent:
244 _stmts = []
245 _stmt_parents = []
246 elif isinstance(node, DelName):
247 _stmts = []
248 _stmt_parents = []
249 continue
250 if not are_exclusive(self, node):
251 _stmts.append(node)
252 _stmt_parents.append(stmt.parent)
253 return _stmts
254
255 # Name classes
256
257 class AssName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
258 """class representing an AssName node"""
259
260
261 class DelName(LookupMixIn, ParentAssignTypeMixin, NodeNG):
262 """class representing a DelName node"""
263
264
265 class Name(LookupMixIn, NodeNG):
266 """class representing a Name node"""
267
268
269
270
271 ##################### node classes ########################################
272
273 class Arguments(NodeNG, AssignTypeMixin):
274 """class representing an Arguments node"""
275 if PY3K:
276 # Python 3.4+ uses a different approach regarding annotations,
277 # each argument is a new class, _ast.arg, which exposes an
278 # 'annotation' attribute. In astroid though, arguments are exposed
279 # as is in the Arguments node and the only way to expose annotations
280 # is by using something similar with Python 3.3:
281 # - we expose 'varargannotation' and 'kwargannotation' of annotations
282 # of varargs and kwargs.
283 # - we expose 'annotation', a list with annotations for
284 # for each normal argument. If an argument doesn't have an
285 # annotation, its value will be None.
286
287 _astroid_fields = ('args', 'defaults', 'kwonlyargs',
288 'kw_defaults', 'annotations',
289 'varargannotation', 'kwargannotation')
290 annotations = None
291 varargannotation = None
292 kwargannotation = None
293 else:
294 _astroid_fields = ('args', 'defaults', 'kwonlyargs', 'kw_defaults')
295 args = None
296 defaults = None
297 kwonlyargs = None
298 kw_defaults = None
299
300 def __init__(self, vararg=None, kwarg=None):
301 self.vararg = vararg
302 self.kwarg = kwarg
303
304 def _infer_name(self, frame, name):
305 if self.parent is frame:
306 return name
307 return None
308
309 @cachedproperty
310 def fromlineno(self):
311 lineno = super(Arguments, self).fromlineno
312 return max(lineno, self.parent.fromlineno)
313
314 def format_args(self):
315 """return arguments formatted as string"""
316 result = []
317 if self.args:
318 result.append(_format_args(self.args, self.defaults))
319 if self.vararg:
320 result.append('*%s' % self.vararg)
321 if self.kwarg:
322 result.append('**%s' % self.kwarg)
323 if self.kwonlyargs:
324 if not self.vararg:
325 result.append('*')
326 result.append(_format_args(self.kwonlyargs, self.kw_defaults))
327 return ', '.join(result)
328
329 def default_value(self, argname):
330 """return the default value for an argument
331
332 :raise `NoDefault`: if there is no default value defined
333 """
334 i = _find_arg(argname, self.args)[0]
335 if i is not None:
336 idx = i - (len(self.args) - len(self.defaults))
337 if idx >= 0:
338 return self.defaults[idx]
339 i = _find_arg(argname, self.kwonlyargs)[0]
340 if i is not None and self.kw_defaults[i] is not None:
341 return self.kw_defaults[i]
342 raise NoDefault()
343
344 def is_argument(self, name):
345 """return True if the name is defined in arguments"""
346 if name == self.vararg:
347 return True
348 if name == self.kwarg:
349 return True
350 return self.find_argname(name, True)[1] is not None
351
352 def find_argname(self, argname, rec=False):
353 """return index and Name node with given name"""
354 if self.args: # self.args may be None in some cases (builtin function)
355 return _find_arg(argname, self.args, rec)
356 return None, None
357
358 def get_children(self):
359 """override get_children to skip over None elements in kw_defaults"""
360 for child in super(Arguments, self).get_children():
361 if child is not None:
362 yield child
363
364
365 def _find_arg(argname, args, rec=False):
366 for i, arg in enumerate(args):
367 if isinstance(arg, Tuple):
368 if rec:
369 found = _find_arg(argname, arg.elts)
370 if found[0] is not None:
371 return found
372 elif arg.name == argname:
373 return i, arg
374 return None, None
375
376
377 def _format_args(args, defaults=None):
378 values = []
379 if args is None:
380 return ''
381 if defaults is not None:
382 default_offset = len(args) - len(defaults)
383 for i, arg in enumerate(args):
384 if isinstance(arg, Tuple):
385 values.append('(%s)' % _format_args(arg.elts))
386 else:
387 values.append(arg.name)
388 if defaults is not None and i >= default_offset:
389 if defaults[i-default_offset] is not None:
390 values[-1] += '=' + defaults[i-default_offset].as_string()
391 return ', '.join(values)
392
393
394 class AssAttr(NodeNG, ParentAssignTypeMixin):
395 """class representing an AssAttr node"""
396 _astroid_fields = ('expr',)
397 expr = None
398
399 class Assert(Statement):
400 """class representing an Assert node"""
401 _astroid_fields = ('test', 'fail',)
402 test = None
403 fail = None
404
405 class Assign(Statement, AssignTypeMixin):
406 """class representing an Assign node"""
407 _astroid_fields = ('targets', 'value',)
408 targets = None
409 value = None
410
411 class AugAssign(Statement, AssignTypeMixin):
412 """class representing an AugAssign node"""
413 _astroid_fields = ('target', 'value',)
414 target = None
415 value = None
416
417 class Backquote(NodeNG):
418 """class representing a Backquote node"""
419 _astroid_fields = ('value',)
420 value = None
421
422 class BinOp(NodeNG):
423 """class representing a BinOp node"""
424 _astroid_fields = ('left', 'right',)
425 left = None
426 right = None
427
428 class BoolOp(NodeNG):
429 """class representing a BoolOp node"""
430 _astroid_fields = ('values',)
431 values = None
432
433 class Break(Statement):
434 """class representing a Break node"""
435
436
437 class CallFunc(NodeNG):
438 """class representing a CallFunc node"""
439 _astroid_fields = ('func', 'args', 'starargs', 'kwargs')
440 func = None
441 args = None
442 starargs = None
443 kwargs = None
444
445 def __init__(self):
446 self.starargs = None
447 self.kwargs = None
448
449 class Compare(NodeNG):
450 """class representing a Compare node"""
451 _astroid_fields = ('left', 'ops',)
452 left = None
453 ops = None
454
455 def get_children(self):
456 """override get_children for tuple fields"""
457 yield self.left
458 for _, comparator in self.ops:
459 yield comparator # we don't want the 'op'
460
461 def last_child(self):
462 """override last_child"""
463 # XXX maybe if self.ops:
464 return self.ops[-1][1]
465 #return self.left
466
467 class Comprehension(NodeNG):
468 """class representing a Comprehension node"""
469 _astroid_fields = ('target', 'iter', 'ifs')
470 target = None
471 iter = None
472 ifs = None
473
474 optional_assign = True
475 def ass_type(self):
476 return self
477
478 def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt):
479 """method used in filter_stmts"""
480 if self is mystmt:
481 if isinstance(lookup_node, (Const, Name)):
482 return [lookup_node], True
483
484 elif self.statement() is mystmt:
485 # original node's statement is the assignment, only keeps
486 # current node (gen exp, list comp)
487
488 return [node], True
489
490 return stmts, False
491
492
493 class Const(NodeNG, Instance):
494 """represent a constant node like num, str, bool, None, bytes"""
495
496 def __init__(self, value=None):
497 self.value = value
498
499 def getitem(self, index, context=None):
500 if isinstance(self.value, six.string_types):
501 return Const(self.value[index])
502 raise TypeError('%r (value=%s)' % (self, self.value))
503
504 def has_dynamic_getattr(self):
505 return False
506
507 def itered(self):
508 if isinstance(self.value, six.string_types):
509 return self.value
510 raise TypeError()
511
512 def pytype(self):
513 return self._proxied.qname()
514
515
516 class Continue(Statement):
517 """class representing a Continue node"""
518
519
520 class Decorators(NodeNG):
521 """class representing a Decorators node"""
522 _astroid_fields = ('nodes',)
523 nodes = None
524
525 def __init__(self, nodes=None):
526 self.nodes = nodes
527
528 def scope(self):
529 # skip the function node to go directly to the upper level scope
530 return self.parent.parent.scope()
531
532 class DelAttr(NodeNG, ParentAssignTypeMixin):
533 """class representing a DelAttr node"""
534 _astroid_fields = ('expr',)
535 expr = None
536
537
538 class Delete(Statement, AssignTypeMixin):
539 """class representing a Delete node"""
540 _astroid_fields = ('targets',)
541 targets = None
542
543
544 class Dict(NodeNG, Instance):
545 """class representing a Dict node"""
546 _astroid_fields = ('items',)
547
548 def __init__(self, items=None):
549 if items is None:
550 self.items = []
551 else:
552 self.items = [(const_factory(k), const_factory(v))
553 for k, v in items.items()]
554
555 def pytype(self):
556 return '%s.dict' % BUILTINS
557
558 def get_children(self):
559 """get children of a Dict node"""
560 # overrides get_children
561 for key, value in self.items:
562 yield key
563 yield value
564
565 def last_child(self):
566 """override last_child"""
567 if self.items:
568 return self.items[-1][1]
569 return None
570
571 def itered(self):
572 return self.items[::2]
573
574 def getitem(self, lookup_key, context=None):
575 for key, value in self.items:
576 for inferedkey in key.infer(context):
577 if inferedkey is YES:
578 continue
579 if isinstance(inferedkey, Const) \
580 and inferedkey.value == lookup_key:
581 return value
582 # This should raise KeyError, but all call sites only catch
583 # IndexError. Let's leave it like that for now.
584 raise IndexError(lookup_key)
585
586
587 class Discard(Statement):
588 """class representing a Discard node"""
589 _astroid_fields = ('value',)
590 value = None
591
592
593 class Ellipsis(NodeNG):
594 """class representing an Ellipsis node"""
595
596
597 class EmptyNode(NodeNG):
598 """class representing an EmptyNode node"""
599
600
601 class ExceptHandler(Statement, AssignTypeMixin):
602 """class representing an ExceptHandler node"""
603 _astroid_fields = ('type', 'name', 'body',)
604 type = None
605 name = None
606 body = None
607
608 @cachedproperty
609 def blockstart_tolineno(self):
610 if self.name:
611 return self.name.tolineno
612 elif self.type:
613 return self.type.tolineno
614 else:
615 return self.lineno
616
617 def catch(self, exceptions):
618 if self.type is None or exceptions is None:
619 return True
620 for node in self.type.nodes_of_class(Name):
621 if node.name in exceptions:
622 return True
623
624
625 class Exec(Statement):
626 """class representing an Exec node"""
627 _astroid_fields = ('expr', 'globals', 'locals',)
628 expr = None
629 globals = None
630 locals = None
631
632
633 class ExtSlice(NodeNG):
634 """class representing an ExtSlice node"""
635 _astroid_fields = ('dims',)
636 dims = None
637
638 class For(BlockRangeMixIn, AssignTypeMixin, Statement):
639 """class representing a For node"""
640 _astroid_fields = ('target', 'iter', 'body', 'orelse',)
641 target = None
642 iter = None
643 body = None
644 orelse = None
645
646 optional_assign = True
647 @cachedproperty
648 def blockstart_tolineno(self):
649 return self.iter.tolineno
650
651
652 class From(FromImportMixIn, Statement):
653 """class representing a From node"""
654
655 def __init__(self, fromname, names, level=0):
656 self.modname = fromname
657 self.names = names
658 self.level = level
659
660 class Getattr(NodeNG):
661 """class representing a Getattr node"""
662 _astroid_fields = ('expr',)
663 expr = None
664
665
666 class Global(Statement):
667 """class representing a Global node"""
668
669 def __init__(self, names):
670 self.names = names
671
672 def _infer_name(self, frame, name):
673 return name
674
675
676 class If(BlockRangeMixIn, Statement):
677 """class representing an If node"""
678 _astroid_fields = ('test', 'body', 'orelse')
679 test = None
680 body = None
681 orelse = None
682
683 @cachedproperty
684 def blockstart_tolineno(self):
685 return self.test.tolineno
686
687 def block_range(self, lineno):
688 """handle block line numbers range for if statements"""
689 if lineno == self.body[0].fromlineno:
690 return lineno, lineno
691 if lineno <= self.body[-1].tolineno:
692 return lineno, self.body[-1].tolineno
693 return self._elsed_block_range(lineno, self.orelse,
694 self.body[0].fromlineno - 1)
695
696
697 class IfExp(NodeNG):
698 """class representing an IfExp node"""
699 _astroid_fields = ('test', 'body', 'orelse')
700 test = None
701 body = None
702 orelse = None
703
704
705 class Import(FromImportMixIn, Statement):
706 """class representing an Import node"""
707
708
709 class Index(NodeNG):
710 """class representing an Index node"""
711 _astroid_fields = ('value',)
712 value = None
713
714
715 class Keyword(NodeNG):
716 """class representing a Keyword node"""
717 _astroid_fields = ('value',)
718 value = None
719
720
721 class List(NodeNG, Instance, ParentAssignTypeMixin):
722 """class representing a List node"""
723 _astroid_fields = ('elts',)
724
725 def __init__(self, elts=None):
726 if elts is None:
727 self.elts = []
728 else:
729 self.elts = [const_factory(e) for e in elts]
730
731 def pytype(self):
732 return '%s.list' % BUILTINS
733
734 def getitem(self, index, context=None):
735 return self.elts[index]
736
737 def itered(self):
738 return self.elts
739
740
741 class Nonlocal(Statement):
742 """class representing a Nonlocal node"""
743
744 def __init__(self, names):
745 self.names = names
746
747 def _infer_name(self, frame, name):
748 return name
749
750
751 class Pass(Statement):
752 """class representing a Pass node"""
753
754
755 class Print(Statement):
756 """class representing a Print node"""
757 _astroid_fields = ('dest', 'values',)
758 dest = None
759 values = None
760
761
762 class Raise(Statement):
763 """class representing a Raise node"""
764 exc = None
765 if sys.version_info < (3, 0):
766 _astroid_fields = ('exc', 'inst', 'tback')
767 inst = None
768 tback = None
769 else:
770 _astroid_fields = ('exc', 'cause')
771 exc = None
772 cause = None
773
774 def raises_not_implemented(self):
775 if not self.exc:
776 return
777 for name in self.exc.nodes_of_class(Name):
778 if name.name == 'NotImplementedError':
779 return True
780
781
782 class Return(Statement):
783 """class representing a Return node"""
784 _astroid_fields = ('value',)
785 value = None
786
787
788 class Set(NodeNG, Instance, ParentAssignTypeMixin):
789 """class representing a Set node"""
790 _astroid_fields = ('elts',)
791
792 def __init__(self, elts=None):
793 if elts is None:
794 self.elts = []
795 else:
796 self.elts = [const_factory(e) for e in elts]
797
798 def pytype(self):
799 return '%s.set' % BUILTINS
800
801 def itered(self):
802 return self.elts
803
804
805 class Slice(NodeNG):
806 """class representing a Slice node"""
807 _astroid_fields = ('lower', 'upper', 'step')
808 lower = None
809 upper = None
810 step = None
811
812 class Starred(NodeNG, ParentAssignTypeMixin):
813 """class representing a Starred node"""
814 _astroid_fields = ('value',)
815 value = None
816
817
818 class Subscript(NodeNG):
819 """class representing a Subscript node"""
820 _astroid_fields = ('value', 'slice')
821 value = None
822 slice = None
823
824
825 class TryExcept(BlockRangeMixIn, Statement):
826 """class representing a TryExcept node"""
827 _astroid_fields = ('body', 'handlers', 'orelse',)
828 body = None
829 handlers = None
830 orelse = None
831
832 def _infer_name(self, frame, name):
833 return name
834
835 def block_range(self, lineno):
836 """handle block line numbers range for try/except statements"""
837 last = None
838 for exhandler in self.handlers:
839 if exhandler.type and lineno == exhandler.type.fromlineno:
840 return lineno, lineno
841 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].toli neno:
842 return lineno, exhandler.body[-1].tolineno
843 if last is None:
844 last = exhandler.body[0].fromlineno - 1
845 return self._elsed_block_range(lineno, self.orelse, last)
846
847
848 class TryFinally(BlockRangeMixIn, Statement):
849 """class representing a TryFinally node"""
850 _astroid_fields = ('body', 'finalbody',)
851 body = None
852 finalbody = None
853
854 def block_range(self, lineno):
855 """handle block line numbers range for try/finally statements"""
856 child = self.body[0]
857 # py2.5 try: except: finally:
858 if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno
859 and lineno > self.fromlineno and lineno <= child.tolineno):
860 return child.block_range(lineno)
861 return self._elsed_block_range(lineno, self.finalbody)
862
863
864 class Tuple(NodeNG, Instance, ParentAssignTypeMixin):
865 """class representing a Tuple node"""
866 _astroid_fields = ('elts',)
867
868 def __init__(self, elts=None):
869 if elts is None:
870 self.elts = []
871 else:
872 self.elts = [const_factory(e) for e in elts]
873
874 def pytype(self):
875 return '%s.tuple' % BUILTINS
876
877 def getitem(self, index, context=None):
878 return self.elts[index]
879
880 def itered(self):
881 return self.elts
882
883
884 class UnaryOp(NodeNG):
885 """class representing an UnaryOp node"""
886 _astroid_fields = ('operand',)
887 operand = None
888
889
890 class While(BlockRangeMixIn, Statement):
891 """class representing a While node"""
892 _astroid_fields = ('test', 'body', 'orelse',)
893 test = None
894 body = None
895 orelse = None
896
897 @cachedproperty
898 def blockstart_tolineno(self):
899 return self.test.tolineno
900
901 def block_range(self, lineno):
902 """handle block line numbers range for for and while statements"""
903 return self. _elsed_block_range(lineno, self.orelse)
904
905
906 class With(BlockRangeMixIn, AssignTypeMixin, Statement):
907 """class representing a With node"""
908 _astroid_fields = ('items', 'body')
909 items = None
910 body = None
911
912 @cachedproperty
913 def blockstart_tolineno(self):
914 return self.items[-1][0].tolineno
915
916 def get_children(self):
917 for expr, var in self.items:
918 yield expr
919 if var:
920 yield var
921 for elt in self.body:
922 yield elt
923
924 class Yield(NodeNG):
925 """class representing a Yield node"""
926 _astroid_fields = ('value',)
927 value = None
928
929 class YieldFrom(Yield):
930 """ Class representing a YieldFrom node. """
931
932 # constants ##############################################################
933
934 CONST_CLS = {
935 list: List,
936 tuple: Tuple,
937 dict: Dict,
938 set: Set,
939 type(None): Const,
940 }
941
942 def _update_const_classes():
943 """update constant classes, so the keys of CONST_CLS can be reused"""
944 klasses = (bool, int, float, complex, str)
945 if sys.version_info < (3, 0):
946 klasses += (unicode, long)
947 if sys.version_info >= (2, 6):
948 klasses += (bytes,)
949 for kls in klasses:
950 CONST_CLS[kls] = Const
951 _update_const_classes()
952
953 def const_factory(value):
954 """return an astroid node for a python value"""
955 # XXX we should probably be stricter here and only consider stuff in
956 # CONST_CLS or do better treatment: in case where value is not in CONST_CLS,
957 # we should rather recall the builder on this value than returning an empty
958 # node (another option being that const_factory shouldn't be called with som ething
959 # not in CONST_CLS)
960 assert not isinstance(value, NodeNG)
961 try:
962 return CONST_CLS[value.__class__](value)
963 except (KeyError, AttributeError):
964 node = EmptyNode()
965 node.object = value
966 return node
OLDNEW
« no previous file with comments | « third_party/logilab/logilab/astroid/modutils.py ('k') | third_party/logilab/logilab/astroid/nodes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698