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

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

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

Powered by Google App Engine
This is Rietveld 408576698