OLD | NEW |
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
| 3 # copyright 2003-2010 Sylvain Thenault, all rights reserved. |
| 4 # contact mailto:thenault@gmail.com |
3 # | 5 # |
4 # This file is part of astroid. | 6 # This file is part of logilab-astng. |
5 # | 7 # |
6 # astroid is free software: you can redistribute it and/or modify it | 8 # logilab-astng 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 | 9 # 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 | 10 # Free Software Foundation, either version 2.1 of the License, or (at your |
9 # option) any later version. | 11 # option) any later version. |
10 # | 12 # |
11 # astroid is distributed in the hope that it will be useful, but | 13 # logilab-astng is distributed in the hope that it will be useful, but |
12 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 14 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | 15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License |
14 # for more details. | 16 # for more details. |
15 # | 17 # |
16 # You should have received a copy of the GNU Lesser General Public License along | 18 # 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/>. | 19 # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. |
18 """Module for some node classes. More nodes in scoped_nodes.py | 20 """Module for some node classes. More nodes in scoped_nodes.py |
19 """ | 21 """ |
20 | 22 |
21 import sys | 23 import sys |
22 | 24 |
23 from astroid.exceptions import NoDefault | 25 from logilab.astng import BUILTINS_MODULE |
24 from astroid.bases import (NodeNG, Statement, Instance, InferenceContext, | 26 from logilab.astng.exceptions import NoDefault |
25 _infer_stmts, YES, BUILTINS) | 27 from logilab.astng.bases import (NodeNG, Statement, Instance, InferenceContext, |
26 from astroid.mixins import (BlockRangeMixIn, AssignTypeMixin, | 28 _infer_stmts, YES) |
27 ParentAssignTypeMixin, FromImportMixIn) | 29 from logilab.astng.mixins import BlockRangeMixIn, AssignTypeMixin, \ |
28 | 30 ParentAssignTypeMixin, FromImportMixIn |
29 PY3K = sys.version_info >= (3, 0) | |
30 | 31 |
31 | 32 |
32 def unpack_infer(stmt, context=None): | 33 def unpack_infer(stmt, context=None): |
33 """recursively generate nodes inferred by the given statement. | 34 """recursively generate nodes inferred by the given statement. |
34 If the inferred value is a list or a tuple, recurse on the elements | 35 If the inferred value is a list or a tuple, recurse on the elements |
35 """ | 36 """ |
36 if isinstance(stmt, (List, Tuple)): | 37 if isinstance(stmt, (List, Tuple)): |
37 for elt in stmt.elts: | 38 for elt in stmt.elts: |
38 for infered_elt in unpack_infer(elt, context): | 39 for infered_elt in unpack_infer(elt, context): |
39 yield infered_elt | 40 yield infered_elt |
40 return | 41 return |
41 # if infered is a final node, return it and stop | |
42 infered = stmt.infer(context).next() | 42 infered = stmt.infer(context).next() |
43 if infered is stmt: | 43 if infered is stmt or infered is YES: |
44 yield infered | 44 yield infered |
45 return | 45 return |
46 # else, infer recursivly, except YES object that should be returned as is | |
47 for infered in stmt.infer(context): | 46 for infered in stmt.infer(context): |
48 if infered is YES: | 47 for inf_inf in unpack_infer(infered, context): |
49 yield infered | 48 yield inf_inf |
50 else: | |
51 for inf_inf in unpack_infer(infered, context): | |
52 yield inf_inf | |
53 | 49 |
54 | 50 |
55 def are_exclusive(stmt1, stmt2, exceptions=None): | 51 def are_exclusive(stmt1, stmt2, exceptions=None): |
56 """return true if the two given statements are mutually exclusive | 52 """return true if the two given statements are mutually exclusive |
57 | 53 |
58 `exceptions` may be a list of exception names. If specified, discard If | 54 `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 | 55 branches and check one of the statement is in an exception handler catching |
60 one of the given exceptions. | 56 one of the given exceptions. |
61 | 57 |
62 algorithm : | 58 algorithm : |
(...skipping 14 matching lines...) Expand all Loading... |
77 node = node.parent | 73 node = node.parent |
78 # climb among stmt2's parents until we find a common parent | 74 # climb among stmt2's parents until we find a common parent |
79 node = stmt2.parent | 75 node = stmt2.parent |
80 previous = stmt2 | 76 previous = stmt2 |
81 while node: | 77 while node: |
82 if node in stmt1_parents: | 78 if node in stmt1_parents: |
83 # if the common parent is a If or TryExcept statement, look if | 79 # if the common parent is a If or TryExcept statement, look if |
84 # nodes are in exclusive branches | 80 # nodes are in exclusive branches |
85 if isinstance(node, If) and exceptions is None: | 81 if isinstance(node, If) and exceptions is None: |
86 if (node.locate_child(previous)[1] | 82 if (node.locate_child(previous)[1] |
87 is not node.locate_child(children[node])[1]): | 83 is not node.locate_child(children[node])[1]): |
88 return True | 84 return True |
89 elif isinstance(node, TryExcept): | 85 elif isinstance(node, TryExcept): |
90 c2attr, c2node = node.locate_child(previous) | 86 c2attr, c2node = node.locate_child(previous) |
91 c1attr, c1node = node.locate_child(children[node]) | 87 c1attr, c1node = node.locate_child(children[node]) |
92 if c1node is not c2node: | 88 if c1node is not c2node: |
93 if ((c2attr == 'body' and c1attr == 'handlers' and children[
node].catch(exceptions)) or | 89 if ((c2attr == 'body' and c1attr == 'handlers' and children[
node].catch(exceptions)) or |
94 (c2attr == 'handlers' and c1attr == 'body' and previ
ous.catch(exceptions)) or | 90 (c2attr == 'handlers' and c1attr == 'body' and previous.
catch(exceptions)) or |
95 (c2attr == 'handlers' and c1attr == 'orelse') or | 91 (c2attr == 'handlers' and c1attr == 'orelse') or |
96 (c2attr == 'orelse' and c1attr == 'handlers')): | 92 (c2attr == 'orelse' and c1attr == 'handlers')): |
97 return True | 93 return True |
98 elif c2attr == 'handlers' and c1attr == 'handlers': | 94 elif c2attr == 'handlers' and c1attr == 'handlers': |
99 return previous is not children[node] | 95 return previous is not children[node] |
100 return False | 96 return False |
101 previous = node | 97 previous = node |
102 node = node.parent | 98 node = node.parent |
103 return False | 99 return False |
104 | 100 |
105 | 101 |
106 class LookupMixIn(object): | 102 class LookupMixIn(object): |
107 """Mixin looking up a name in the right scope | 103 """Mixin looking up a name in the right scope |
108 """ | 104 """ |
109 | 105 |
110 def lookup(self, name): | 106 def lookup(self, name): |
111 """lookup a variable name | 107 """lookup a variable name |
112 | 108 |
113 return the scope node and the list of assignments associated to the | 109 return the scope node and the list of assignments associated to the give
n |
114 given name according to the scope where it has been found (locals, | 110 name according to the scope where it has been found (locals, globals or |
115 globals or builtin) | 111 builtin) |
116 | 112 |
117 The lookup is starting from self's scope. If self is not a frame itself | 113 The lookup is starting from self's scope. If self is not a frame itself
and |
118 and the name is found in the inner frame locals, statements will be | 114 the name is found in the inner frame locals, statements will be filtered |
119 filtered to remove ignorable statements according to self's location | 115 to remove ignorable statements according to self's location |
120 """ | 116 """ |
121 return self.scope().scope_lookup(self, name) | 117 return self.scope().scope_lookup(self, name) |
122 | 118 |
123 def ilookup(self, name): | 119 def ilookup(self, name): |
124 """infered lookup | 120 """infered lookup |
125 | 121 |
126 return an iterator on infered values of the statements returned by | 122 return an iterator on infered values of the statements returned by |
127 the lookup method | 123 the lookup method |
128 """ | 124 """ |
129 frame, stmts = self.lookup(name) | 125 frame, stmts = self.lookup(name) |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 class Name(LookupMixIn, NodeNG): | 244 class Name(LookupMixIn, NodeNG): |
249 """class representing a Name node""" | 245 """class representing a Name node""" |
250 | 246 |
251 | 247 |
252 | 248 |
253 | 249 |
254 ##################### node classes ######################################## | 250 ##################### node classes ######################################## |
255 | 251 |
256 class Arguments(NodeNG, AssignTypeMixin): | 252 class Arguments(NodeNG, AssignTypeMixin): |
257 """class representing an Arguments node""" | 253 """class representing an Arguments node""" |
258 if PY3K: | 254 _astng_fields = ('args', 'defaults') |
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 | 255 args = None |
279 defaults = None | 256 defaults = None |
280 kwonlyargs = None | |
281 kw_defaults = None | |
282 | 257 |
283 def __init__(self, vararg=None, kwarg=None): | 258 def __init__(self, vararg=None, kwarg=None): |
284 self.vararg = vararg | 259 self.vararg = vararg |
285 self.kwarg = kwarg | 260 self.kwarg = kwarg |
286 | 261 |
287 def _infer_name(self, frame, name): | 262 def _infer_name(self, frame, name): |
288 if self.parent is frame: | 263 if self.parent is frame: |
289 return name | 264 return name |
290 return None | 265 return None |
291 | 266 |
292 def format_args(self): | 267 def format_args(self): |
293 """return arguments formatted as string""" | 268 """return arguments formatted as string""" |
294 result = [] | 269 result = [_format_args(self.args, self.defaults)] |
295 if self.args: | |
296 result.append(_format_args(self.args, self.defaults)) | |
297 if self.vararg: | 270 if self.vararg: |
298 result.append('*%s' % self.vararg) | 271 result.append('*%s' % self.vararg) |
299 if self.kwarg: | 272 if self.kwarg: |
300 result.append('**%s' % self.kwarg) | 273 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) | 274 return ', '.join(result) |
306 | 275 |
307 def default_value(self, argname): | 276 def default_value(self, argname): |
308 """return the default value for an argument | 277 """return the default value for an argument |
309 | 278 |
310 :raise `NoDefault`: if there is no default value defined | 279 :raise `NoDefault`: if there is no default value defined |
311 """ | 280 """ |
312 i = _find_arg(argname, self.args)[0] | 281 i = _find_arg(argname, self.args)[0] |
313 if i is not None: | 282 if i is not None: |
314 idx = i - (len(self.args) - len(self.defaults)) | 283 idx = i - (len(self.args) - len(self.defaults)) |
315 if idx >= 0: | 284 if idx >= 0: |
316 return self.defaults[idx] | 285 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() | 286 raise NoDefault() |
321 | 287 |
322 def is_argument(self, name): | 288 def is_argument(self, name): |
323 """return True if the name is defined in arguments""" | 289 """return True if the name is defined in arguments""" |
324 if name == self.vararg: | 290 if name == self.vararg: |
325 return True | 291 return True |
326 if name == self.kwarg: | 292 if name == self.kwarg: |
327 return True | 293 return True |
328 return self.find_argname(name, True)[1] is not None | 294 return self.find_argname(name, True)[1] is not None |
329 | 295 |
330 def find_argname(self, argname, rec=False): | 296 def find_argname(self, argname, rec=False): |
331 """return index and Name node with given name""" | 297 """return index and Name node with given name""" |
332 if self.args: # self.args may be None in some cases (builtin function) | 298 if self.args: # self.args may be None in some cases (builtin function) |
333 return _find_arg(argname, self.args, rec) | 299 return _find_arg(argname, self.args, rec) |
334 return None, None | 300 return None, None |
335 | 301 |
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 | 302 |
343 def _find_arg(argname, args, rec=False): | 303 def _find_arg(argname, args, rec=False): |
344 for i, arg in enumerate(args): | 304 for i, arg in enumerate(args): |
345 if isinstance(arg, Tuple): | 305 if isinstance(arg, Tuple): |
346 if rec: | 306 if rec: |
347 found = _find_arg(argname, arg.elts) | 307 found = _find_arg(argname, arg.elts) |
348 if found[0] is not None: | 308 if found[0] is not None: |
349 return found | 309 return found |
350 elif arg.name == argname: | 310 elif arg.name == argname: |
351 return i, arg | 311 return i, arg |
352 return None, None | 312 return None, None |
353 | 313 |
354 | 314 |
355 def _format_args(args, defaults=None): | 315 def _format_args(args, defaults=None): |
356 values = [] | 316 values = [] |
357 if args is None: | 317 if args is None: |
358 return '' | 318 return '' |
359 if defaults is not None: | 319 if defaults is not None: |
360 default_offset = len(args) - len(defaults) | 320 default_offset = len(args) - len(defaults) |
361 for i, arg in enumerate(args): | 321 for i, arg in enumerate(args): |
362 if isinstance(arg, Tuple): | 322 if isinstance(arg, Tuple): |
363 values.append('(%s)' % _format_args(arg.elts)) | 323 values.append('(%s)' % _format_args(arg.elts)) |
364 else: | 324 else: |
365 values.append(arg.name) | 325 values.append(arg.name) |
366 if defaults is not None and i >= default_offset: | 326 if defaults is not None and i >= default_offset: |
367 if defaults[i-default_offset] is not None: | 327 values[-1] += '=' + defaults[i-default_offset].as_string() |
368 values[-1] += '=' + defaults[i-default_offset].as_string() | |
369 return ', '.join(values) | 328 return ', '.join(values) |
370 | 329 |
371 | 330 |
372 class AssAttr(NodeNG, ParentAssignTypeMixin): | 331 class AssAttr(NodeNG, ParentAssignTypeMixin): |
373 """class representing an AssAttr node""" | 332 """class representing an AssAttr node""" |
374 _astroid_fields = ('expr',) | 333 _astng_fields = ('expr',) |
375 expr = None | 334 expr = None |
376 | 335 |
377 class Assert(Statement): | 336 class Assert(Statement): |
378 """class representing an Assert node""" | 337 """class representing an Assert node""" |
379 _astroid_fields = ('test', 'fail',) | 338 _astng_fields = ('test', 'fail',) |
380 test = None | 339 test = None |
381 fail = None | 340 fail = None |
382 | 341 |
383 class Assign(Statement, AssignTypeMixin): | 342 class Assign(Statement, AssignTypeMixin): |
384 """class representing an Assign node""" | 343 """class representing an Assign node""" |
385 _astroid_fields = ('targets', 'value',) | 344 _astng_fields = ('targets', 'value',) |
386 targets = None | 345 targets = None |
387 value = None | 346 value = None |
388 | 347 |
389 class AugAssign(Statement, AssignTypeMixin): | 348 class AugAssign(Statement, AssignTypeMixin): |
390 """class representing an AugAssign node""" | 349 """class representing an AugAssign node""" |
391 _astroid_fields = ('target', 'value',) | 350 _astng_fields = ('target', 'value',) |
392 target = None | 351 target = None |
393 value = None | 352 value = None |
394 | 353 |
395 class Backquote(NodeNG): | 354 class Backquote(NodeNG): |
396 """class representing a Backquote node""" | 355 """class representing a Backquote node""" |
397 _astroid_fields = ('value',) | 356 _astng_fields = ('value',) |
398 value = None | 357 value = None |
399 | 358 |
400 class BinOp(NodeNG): | 359 class BinOp(NodeNG): |
401 """class representing a BinOp node""" | 360 """class representing a BinOp node""" |
402 _astroid_fields = ('left', 'right',) | 361 _astng_fields = ('left', 'right',) |
403 left = None | 362 left = None |
404 right = None | 363 right = None |
405 | 364 |
406 class BoolOp(NodeNG): | 365 class BoolOp(NodeNG): |
407 """class representing a BoolOp node""" | 366 """class representing a BoolOp node""" |
408 _astroid_fields = ('values',) | 367 _astng_fields = ('values',) |
409 values = None | 368 values = None |
410 | 369 |
411 class Break(Statement): | 370 class Break(Statement): |
412 """class representing a Break node""" | 371 """class representing a Break node""" |
413 | 372 |
414 | 373 |
415 class CallFunc(NodeNG): | 374 class CallFunc(NodeNG): |
416 """class representing a CallFunc node""" | 375 """class representing a CallFunc node""" |
417 _astroid_fields = ('func', 'args', 'starargs', 'kwargs') | 376 _astng_fields = ('func', 'args', 'starargs', 'kwargs') |
418 func = None | 377 func = None |
419 args = None | 378 args = None |
420 starargs = None | 379 starargs = None |
421 kwargs = None | 380 kwargs = None |
422 | 381 |
423 def __init__(self): | 382 def __init__(self): |
424 self.starargs = None | 383 self.starargs = None |
425 self.kwargs = None | 384 self.kwargs = None |
426 | 385 |
427 class Compare(NodeNG): | 386 class Compare(NodeNG): |
428 """class representing a Compare node""" | 387 """class representing a Compare node""" |
429 _astroid_fields = ('left', 'ops',) | 388 _astng_fields = ('left', 'ops',) |
430 left = None | 389 left = None |
431 ops = None | 390 ops = None |
432 | 391 |
433 def get_children(self): | 392 def get_children(self): |
434 """override get_children for tuple fields""" | 393 """override get_children for tuple fields""" |
435 yield self.left | 394 yield self.left |
436 for _, comparator in self.ops: | 395 for _, comparator in self.ops: |
437 yield comparator # we don't want the 'op' | 396 yield comparator # we don't want the 'op' |
438 | 397 |
439 def last_child(self): | 398 def last_child(self): |
440 """override last_child""" | 399 """override last_child""" |
441 # XXX maybe if self.ops: | 400 # XXX maybe if self.ops: |
442 return self.ops[-1][1] | 401 return self.ops[-1][1] |
443 #return self.left | 402 #return self.left |
444 | 403 |
445 class Comprehension(NodeNG): | 404 class Comprehension(NodeNG): |
446 """class representing a Comprehension node""" | 405 """class representing a Comprehension node""" |
447 _astroid_fields = ('target', 'iter', 'ifs') | 406 _astng_fields = ('target', 'iter' ,'ifs') |
448 target = None | 407 target = None |
449 iter = None | 408 iter = None |
450 ifs = None | 409 ifs = None |
451 | 410 |
452 optional_assign = True | 411 optional_assign = True |
453 def ass_type(self): | 412 def ass_type(self): |
454 return self | 413 return self |
455 | 414 |
456 def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): | 415 def _get_filtered_stmts(self, lookup_node, node, stmts, mystmt): |
457 """method used in filter_stmts""" | 416 """method used in filter_stmts""" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 def pytype(self): | 449 def pytype(self): |
491 return self._proxied.qname() | 450 return self._proxied.qname() |
492 | 451 |
493 | 452 |
494 class Continue(Statement): | 453 class Continue(Statement): |
495 """class representing a Continue node""" | 454 """class representing a Continue node""" |
496 | 455 |
497 | 456 |
498 class Decorators(NodeNG): | 457 class Decorators(NodeNG): |
499 """class representing a Decorators node""" | 458 """class representing a Decorators node""" |
500 _astroid_fields = ('nodes',) | 459 _astng_fields = ('nodes',) |
501 nodes = None | 460 nodes = None |
502 | 461 |
503 def __init__(self, nodes=None): | 462 def __init__(self, nodes=None): |
504 self.nodes = nodes | 463 self.nodes = nodes |
505 | 464 |
506 def scope(self): | 465 def scope(self): |
507 # skip the function node to go directly to the upper level scope | 466 # skip the function node to go directly to the upper level scope |
508 return self.parent.parent.scope() | 467 return self.parent.parent.scope() |
509 | 468 |
510 class DelAttr(NodeNG, ParentAssignTypeMixin): | 469 class DelAttr(NodeNG, ParentAssignTypeMixin): |
511 """class representing a DelAttr node""" | 470 """class representing a DelAttr node""" |
512 _astroid_fields = ('expr',) | 471 _astng_fields = ('expr',) |
513 expr = None | 472 expr = None |
514 | 473 |
515 | 474 |
516 class Delete(Statement, AssignTypeMixin): | 475 class Delete(Statement, AssignTypeMixin): |
517 """class representing a Delete node""" | 476 """class representing a Delete node""" |
518 _astroid_fields = ('targets',) | 477 _astng_fields = ('targets',) |
519 targets = None | 478 targets = None |
520 | 479 |
521 | 480 |
522 class Dict(NodeNG, Instance): | 481 class Dict(NodeNG, Instance): |
523 """class representing a Dict node""" | 482 """class representing a Dict node""" |
524 _astroid_fields = ('items',) | 483 _astng_fields = ('items',) |
525 | 484 |
526 def __init__(self, items=None): | 485 def __init__(self, items=None): |
527 if items is None: | 486 if items is None: |
528 self.items = [] | 487 self.items = [] |
529 else: | 488 else: |
530 self.items = [(const_factory(k), const_factory(v)) | 489 self.items = [(const_factory(k), const_factory(v)) |
531 for k, v in items.iteritems()] | 490 for k,v in items.iteritems()] |
532 | 491 |
533 def pytype(self): | 492 def pytype(self): |
534 return '%s.dict' % BUILTINS | 493 return '%s.dict' % BUILTINS_MODULE |
535 | 494 |
536 def get_children(self): | 495 def get_children(self): |
537 """get children of a Dict node""" | 496 """get children of a Dict node""" |
538 # overrides get_children | 497 # overrides get_children |
539 for key, value in self.items: | 498 for key, value in self.items: |
540 yield key | 499 yield key |
541 yield value | 500 yield value |
542 | 501 |
543 def last_child(self): | 502 def last_child(self): |
544 """override last_child""" | 503 """override last_child""" |
545 if self.items: | 504 if self.items: |
546 return self.items[-1][1] | 505 return self.items[-1][1] |
547 return None | 506 return None |
548 | 507 |
549 def itered(self): | 508 def itered(self): |
550 return self.items[::2] | 509 return self.items[::2] |
551 | 510 |
552 def getitem(self, lookup_key, context=None): | 511 def getitem(self, key, context=None): |
553 for key, value in self.items: | 512 for i in xrange(0, len(self.items), 2): |
554 for inferedkey in key.infer(context): | 513 for inferedkey in self.items[i].infer(context): |
555 if inferedkey is YES: | 514 if inferedkey is YES: |
556 continue | 515 continue |
557 if isinstance(inferedkey, Const) \ | 516 if isinstance(inferedkey, Const) and inferedkey.value == key: |
558 and inferedkey.value == lookup_key: | 517 return self.items[i+1] |
559 return value | 518 raise IndexError(key) |
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 | 519 |
564 | 520 |
565 class Discard(Statement): | 521 class Discard(Statement): |
566 """class representing a Discard node""" | 522 """class representing a Discard node""" |
567 _astroid_fields = ('value',) | 523 _astng_fields = ('value',) |
568 value = None | 524 value = None |
569 | 525 |
570 | 526 |
571 class Ellipsis(NodeNG): | 527 class Ellipsis(NodeNG): |
572 """class representing an Ellipsis node""" | 528 """class representing an Ellipsis node""" |
573 | 529 |
574 | 530 |
575 class EmptyNode(NodeNG): | 531 class EmptyNode(NodeNG): |
576 """class representing an EmptyNode node""" | 532 """class representing an EmptyNode node""" |
577 | 533 |
578 | 534 |
579 class ExceptHandler(Statement, AssignTypeMixin): | 535 class ExceptHandler(Statement, AssignTypeMixin): |
580 """class representing an ExceptHandler node""" | 536 """class representing an ExceptHandler node""" |
581 _astroid_fields = ('type', 'name', 'body',) | 537 _astng_fields = ('type', 'name', 'body',) |
582 type = None | 538 type = None |
583 name = None | 539 name = None |
584 body = None | 540 body = None |
585 | 541 |
586 def _blockstart_toline(self): | 542 def _blockstart_toline(self): |
587 if self.name: | 543 if self.name: |
588 return self.name.tolineno | 544 return self.name.tolineno |
589 elif self.type: | 545 elif self.type: |
590 return self.type.tolineno | 546 return self.type.tolineno |
591 else: | 547 else: |
592 return self.lineno | 548 return self.lineno |
593 | 549 |
594 def set_line_info(self, lastchild): | 550 def set_line_info(self, lastchild): |
595 self.fromlineno = self.lineno | 551 self.fromlineno = self.lineno |
596 self.tolineno = lastchild.tolineno | 552 self.tolineno = lastchild.tolineno |
597 self.blockstart_tolineno = self._blockstart_toline() | 553 self.blockstart_tolineno = self._blockstart_toline() |
598 | 554 |
599 def catch(self, exceptions): | 555 def catch(self, exceptions): |
600 if self.type is None or exceptions is None: | 556 if self.type is None or exceptions is None: |
601 return True | 557 return True |
602 for node in self.type.nodes_of_class(Name): | 558 for node in self.type.nodes_of_class(Name): |
603 if node.name in exceptions: | 559 if node.name in exceptions: |
604 return True | 560 return True |
605 | 561 |
606 | 562 |
607 class Exec(Statement): | 563 class Exec(Statement): |
608 """class representing an Exec node""" | 564 """class representing an Exec node""" |
609 _astroid_fields = ('expr', 'globals', 'locals',) | 565 _astng_fields = ('expr', 'globals', 'locals',) |
610 expr = None | 566 expr = None |
611 globals = None | 567 globals = None |
612 locals = None | 568 locals = None |
613 | 569 |
614 | 570 |
615 class ExtSlice(NodeNG): | 571 class ExtSlice(NodeNG): |
616 """class representing an ExtSlice node""" | 572 """class representing an ExtSlice node""" |
617 _astroid_fields = ('dims',) | 573 _astng_fields = ('dims',) |
618 dims = None | 574 dims = None |
619 | 575 |
620 class For(BlockRangeMixIn, AssignTypeMixin, Statement): | 576 class For(BlockRangeMixIn, AssignTypeMixin, Statement): |
621 """class representing a For node""" | 577 """class representing a For node""" |
622 _astroid_fields = ('target', 'iter', 'body', 'orelse',) | 578 _astng_fields = ('target', 'iter', 'body', 'orelse',) |
623 target = None | 579 target = None |
624 iter = None | 580 iter = None |
625 body = None | 581 body = None |
626 orelse = None | 582 orelse = None |
627 | 583 |
628 optional_assign = True | 584 optional_assign = True |
629 def _blockstart_toline(self): | 585 def _blockstart_toline(self): |
630 return self.iter.tolineno | 586 return self.iter.tolineno |
631 | 587 |
632 | 588 |
633 class From(FromImportMixIn, Statement): | 589 class From(FromImportMixIn, Statement): |
634 """class representing a From node""" | 590 """class representing a From node""" |
635 | 591 |
636 def __init__(self, fromname, names, level=0): | 592 def __init__(self, fromname, names, level=0): |
637 self.modname = fromname | 593 self.modname = fromname |
638 self.names = names | 594 self.names = names |
639 self.level = level | 595 self.level = level |
640 | 596 |
641 class Getattr(NodeNG): | 597 class Getattr(NodeNG): |
642 """class representing a Getattr node""" | 598 """class representing a Getattr node""" |
643 _astroid_fields = ('expr',) | 599 _astng_fields = ('expr',) |
644 expr = None | 600 expr = None |
645 | 601 |
646 | 602 |
647 class Global(Statement): | 603 class Global(Statement): |
648 """class representing a Global node""" | 604 """class representing a Global node""" |
649 | 605 |
650 def __init__(self, names): | 606 def __init__(self, names): |
651 self.names = names | 607 self.names = names |
652 | 608 |
653 def _infer_name(self, frame, name): | 609 def _infer_name(self, frame, name): |
654 return name | 610 return name |
655 | 611 |
656 | 612 |
657 class If(BlockRangeMixIn, Statement): | 613 class If(BlockRangeMixIn, Statement): |
658 """class representing an If node""" | 614 """class representing an If node""" |
659 _astroid_fields = ('test', 'body', 'orelse') | 615 _astng_fields = ('test', 'body', 'orelse') |
660 test = None | 616 test = None |
661 body = None | 617 body = None |
662 orelse = None | 618 orelse = None |
663 | 619 |
664 def _blockstart_toline(self): | 620 def _blockstart_toline(self): |
665 return self.test.tolineno | 621 return self.test.tolineno |
666 | 622 |
667 def block_range(self, lineno): | 623 def block_range(self, lineno): |
668 """handle block line numbers range for if statements""" | 624 """handle block line numbers range for if statements""" |
669 if lineno == self.body[0].fromlineno: | 625 if lineno == self.body[0].fromlineno: |
670 return lineno, lineno | 626 return lineno, lineno |
671 if lineno <= self.body[-1].tolineno: | 627 if lineno <= self.body[-1].tolineno: |
672 return lineno, self.body[-1].tolineno | 628 return lineno, self.body[-1].tolineno |
673 return self._elsed_block_range(lineno, self.orelse, | 629 return self._elsed_block_range(lineno, self.orelse, |
674 self.body[0].fromlineno - 1) | 630 self.body[0].fromlineno - 1) |
675 | 631 |
676 | 632 |
677 class IfExp(NodeNG): | 633 class IfExp(NodeNG): |
678 """class representing an IfExp node""" | 634 """class representing an IfExp node""" |
679 _astroid_fields = ('test', 'body', 'orelse') | 635 _astng_fields = ('test', 'body', 'orelse') |
680 test = None | 636 test = None |
681 body = None | 637 body = None |
682 orelse = None | 638 orelse = None |
683 | 639 |
684 | 640 |
685 class Import(FromImportMixIn, Statement): | 641 class Import(FromImportMixIn, Statement): |
686 """class representing an Import node""" | 642 """class representing an Import node""" |
687 | 643 |
688 | 644 |
689 class Index(NodeNG): | 645 class Index(NodeNG): |
690 """class representing an Index node""" | 646 """class representing an Index node""" |
691 _astroid_fields = ('value',) | 647 _astng_fields = ('value',) |
692 value = None | 648 value = None |
693 | 649 |
694 | 650 |
695 class Keyword(NodeNG): | 651 class Keyword(NodeNG): |
696 """class representing a Keyword node""" | 652 """class representing a Keyword node""" |
697 _astroid_fields = ('value',) | 653 _astng_fields = ('value',) |
698 value = None | 654 value = None |
699 | 655 |
700 | 656 |
701 class List(NodeNG, Instance, ParentAssignTypeMixin): | 657 class List(NodeNG, Instance, ParentAssignTypeMixin): |
702 """class representing a List node""" | 658 """class representing a List node""" |
703 _astroid_fields = ('elts',) | 659 _astng_fields = ('elts',) |
704 | 660 |
705 def __init__(self, elts=None): | 661 def __init__(self, elts=None): |
706 if elts is None: | 662 if elts is None: |
707 self.elts = [] | 663 self.elts = [] |
708 else: | 664 else: |
709 self.elts = [const_factory(e) for e in elts] | 665 self.elts = [const_factory(e) for e in elts] |
710 | 666 |
711 def pytype(self): | 667 def pytype(self): |
712 return '%s.list' % BUILTINS | 668 return '%s.list' % BUILTINS_MODULE |
713 | 669 |
714 def getitem(self, index, context=None): | 670 def getitem(self, index, context=None): |
715 return self.elts[index] | 671 return self.elts[index] |
716 | 672 |
717 def itered(self): | 673 def itered(self): |
718 return self.elts | 674 return self.elts |
719 | 675 |
720 | 676 |
721 class Nonlocal(Statement): | 677 class Nonlocal(Statement): |
722 """class representing a Nonlocal node""" | 678 """class representing a Nonlocal node""" |
723 | 679 |
724 def __init__(self, names): | 680 def __init__(self, names): |
725 self.names = names | 681 self.names = names |
726 | 682 |
727 def _infer_name(self, frame, name): | 683 def _infer_name(self, frame, name): |
728 return name | 684 return name |
729 | 685 |
730 | 686 |
731 class Pass(Statement): | 687 class Pass(Statement): |
732 """class representing a Pass node""" | 688 """class representing a Pass node""" |
733 | 689 |
734 | 690 |
735 class Print(Statement): | 691 class Print(Statement): |
736 """class representing a Print node""" | 692 """class representing a Print node""" |
737 _astroid_fields = ('dest', 'values',) | 693 _astng_fields = ('dest', 'values',) |
738 dest = None | 694 dest = None |
739 values = None | 695 values = None |
740 | 696 |
741 | 697 |
742 class Raise(Statement): | 698 class Raise(Statement): |
743 """class representing a Raise node""" | 699 """class representing a Raise node""" |
744 exc = None | 700 exc = None |
745 if sys.version_info < (3, 0): | 701 if sys.version_info < (3, 0): |
746 _astroid_fields = ('exc', 'inst', 'tback') | 702 _astng_fields = ('exc', 'inst', 'tback') |
747 inst = None | 703 inst = None |
748 tback = None | 704 tback = None |
749 else: | 705 else: |
750 _astroid_fields = ('exc', 'cause') | 706 _astng_fields = ('exc', 'cause') |
751 exc = None | 707 exc = None |
752 cause = None | 708 cause = None |
753 | 709 |
754 def raises_not_implemented(self): | 710 def raises_not_implemented(self): |
755 if not self.exc: | 711 if not self.exc: |
756 return | 712 return |
757 for name in self.exc.nodes_of_class(Name): | 713 for name in self.exc.nodes_of_class(Name): |
758 if name.name == 'NotImplementedError': | 714 if name.name == 'NotImplementedError': |
759 return True | 715 return True |
760 | 716 |
761 | 717 |
762 class Return(Statement): | 718 class Return(Statement): |
763 """class representing a Return node""" | 719 """class representing a Return node""" |
764 _astroid_fields = ('value',) | 720 _astng_fields = ('value',) |
765 value = None | 721 value = None |
766 | 722 |
767 | 723 |
768 class Set(NodeNG, Instance, ParentAssignTypeMixin): | 724 class Set(NodeNG, Instance, ParentAssignTypeMixin): |
769 """class representing a Set node""" | 725 """class representing a Set node""" |
770 _astroid_fields = ('elts',) | 726 _astng_fields = ('elts',) |
771 | 727 |
772 def __init__(self, elts=None): | 728 def __init__(self, elts=None): |
773 if elts is None: | 729 if elts is None: |
774 self.elts = [] | 730 self.elts = [] |
775 else: | 731 else: |
776 self.elts = [const_factory(e) for e in elts] | 732 self.elts = [const_factory(e) for e in elts] |
777 | 733 |
778 def pytype(self): | 734 def pytype(self): |
779 return '%s.set' % BUILTINS | 735 return '%s.set' % BUILTINS_MODULE |
780 | 736 |
781 def itered(self): | 737 def itered(self): |
782 return self.elts | 738 return self.elts |
783 | 739 |
784 | 740 |
785 class Slice(NodeNG): | 741 class Slice(NodeNG): |
786 """class representing a Slice node""" | 742 """class representing a Slice node""" |
787 _astroid_fields = ('lower', 'upper', 'step') | 743 _astng_fields = ('lower', 'upper', 'step') |
788 lower = None | 744 lower = None |
789 upper = None | 745 upper = None |
790 step = None | 746 step = None |
791 | 747 |
792 class Starred(NodeNG, ParentAssignTypeMixin): | 748 class Starred(NodeNG): |
793 """class representing a Starred node""" | 749 """class representing a Starred node""" |
794 _astroid_fields = ('value',) | 750 _astng_fields = ('value',) |
795 value = None | 751 value = None |
796 | 752 |
797 | 753 |
798 class Subscript(NodeNG): | 754 class Subscript(NodeNG): |
799 """class representing a Subscript node""" | 755 """class representing a Subscript node""" |
800 _astroid_fields = ('value', 'slice') | 756 _astng_fields = ('value', 'slice') |
801 value = None | 757 value = None |
802 slice = None | 758 slice = None |
803 | 759 |
804 | 760 |
805 class TryExcept(BlockRangeMixIn, Statement): | 761 class TryExcept(BlockRangeMixIn, Statement): |
806 """class representing a TryExcept node""" | 762 """class representing a TryExcept node""" |
807 _astroid_fields = ('body', 'handlers', 'orelse',) | 763 _astng_fields = ('body', 'handlers', 'orelse',) |
808 body = None | 764 body = None |
809 handlers = None | 765 handlers = None |
810 orelse = None | 766 orelse = None |
811 | 767 |
812 def _infer_name(self, frame, name): | 768 def _infer_name(self, frame, name): |
813 return name | 769 return name |
814 | 770 |
815 def _blockstart_toline(self): | 771 def _blockstart_toline(self): |
816 return self.lineno | 772 return self.lineno |
817 | 773 |
818 def block_range(self, lineno): | 774 def block_range(self, lineno): |
819 """handle block line numbers range for try/except statements""" | 775 """handle block line numbers range for try/except statements""" |
820 last = None | 776 last = None |
821 for exhandler in self.handlers: | 777 for exhandler in self.handlers: |
822 if exhandler.type and lineno == exhandler.type.fromlineno: | 778 if exhandler.type and lineno == exhandler.type.fromlineno: |
823 return lineno, lineno | 779 return lineno, lineno |
824 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].toli
neno: | 780 if exhandler.body[0].fromlineno <= lineno <= exhandler.body[-1].toli
neno: |
825 return lineno, exhandler.body[-1].tolineno | 781 return lineno, exhandler.body[-1].tolineno |
826 if last is None: | 782 if last is None: |
827 last = exhandler.body[0].fromlineno - 1 | 783 last = exhandler.body[0].fromlineno - 1 |
828 return self._elsed_block_range(lineno, self.orelse, last) | 784 return self._elsed_block_range(lineno, self.orelse, last) |
829 | 785 |
830 | 786 |
831 class TryFinally(BlockRangeMixIn, Statement): | 787 class TryFinally(BlockRangeMixIn, Statement): |
832 """class representing a TryFinally node""" | 788 """class representing a TryFinally node""" |
833 _astroid_fields = ('body', 'finalbody',) | 789 _astng_fields = ('body', 'finalbody',) |
834 body = None | 790 body = None |
835 finalbody = None | 791 finalbody = None |
836 | 792 |
837 def _blockstart_toline(self): | 793 def _blockstart_toline(self): |
838 return self.lineno | 794 return self.lineno |
839 | 795 |
840 def block_range(self, lineno): | 796 def block_range(self, lineno): |
841 """handle block line numbers range for try/finally statements""" | 797 """handle block line numbers range for try/finally statements""" |
842 child = self.body[0] | 798 child = self.body[0] |
843 # py2.5 try: except: finally: | 799 # py2.5 try: except: finally: |
844 if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno | 800 if (isinstance(child, TryExcept) and child.fromlineno == self.fromlineno |
845 and lineno > self.fromlineno and lineno <= child.tolineno): | 801 and lineno > self.fromlineno and lineno <= child.tolineno): |
846 return child.block_range(lineno) | 802 return child.block_range(lineno) |
847 return self._elsed_block_range(lineno, self.finalbody) | 803 return self._elsed_block_range(lineno, self.finalbody) |
848 | 804 |
849 | 805 |
850 class Tuple(NodeNG, Instance, ParentAssignTypeMixin): | 806 class Tuple(NodeNG, Instance, ParentAssignTypeMixin): |
851 """class representing a Tuple node""" | 807 """class representing a Tuple node""" |
852 _astroid_fields = ('elts',) | 808 _astng_fields = ('elts',) |
853 | 809 |
854 def __init__(self, elts=None): | 810 def __init__(self, elts=None): |
855 if elts is None: | 811 if elts is None: |
856 self.elts = [] | 812 self.elts = [] |
857 else: | 813 else: |
858 self.elts = [const_factory(e) for e in elts] | 814 self.elts = [const_factory(e) for e in elts] |
859 | 815 |
860 def pytype(self): | 816 def pytype(self): |
861 return '%s.tuple' % BUILTINS | 817 return '%s.tuple' % BUILTINS_MODULE |
862 | 818 |
863 def getitem(self, index, context=None): | 819 def getitem(self, index, context=None): |
864 return self.elts[index] | 820 return self.elts[index] |
865 | 821 |
866 def itered(self): | 822 def itered(self): |
867 return self.elts | 823 return self.elts |
868 | 824 |
869 | 825 |
870 class UnaryOp(NodeNG): | 826 class UnaryOp(NodeNG): |
871 """class representing an UnaryOp node""" | 827 """class representing an UnaryOp node""" |
872 _astroid_fields = ('operand',) | 828 _astng_fields = ('operand',) |
873 operand = None | 829 operand = None |
874 | 830 |
875 | 831 |
876 class While(BlockRangeMixIn, Statement): | 832 class While(BlockRangeMixIn, Statement): |
877 """class representing a While node""" | 833 """class representing a While node""" |
878 _astroid_fields = ('test', 'body', 'orelse',) | 834 _astng_fields = ('test', 'body', 'orelse',) |
879 test = None | 835 test = None |
880 body = None | 836 body = None |
881 orelse = None | 837 orelse = None |
882 | 838 |
883 def _blockstart_toline(self): | 839 def _blockstart_toline(self): |
884 return self.test.tolineno | 840 return self.test.tolineno |
885 | 841 |
886 def block_range(self, lineno): | 842 def block_range(self, lineno): |
887 """handle block line numbers range for for and while statements""" | 843 """handle block line numbers range for for and while statements""" |
888 return self. _elsed_block_range(lineno, self.orelse) | 844 return self. _elsed_block_range(lineno, self.orelse) |
889 | 845 |
890 | 846 |
891 class With(BlockRangeMixIn, AssignTypeMixin, Statement): | 847 class With(BlockRangeMixIn, AssignTypeMixin, Statement): |
892 """class representing a With node""" | 848 """class representing a With node""" |
893 _astroid_fields = ('items', 'body') | 849 _astng_fields = ('expr', 'vars', 'body') |
894 items = None | 850 expr = None |
| 851 vars = None |
895 body = None | 852 body = None |
896 | 853 |
897 def _blockstart_toline(self): | 854 def _blockstart_toline(self): |
898 return self.items[-1][0].tolineno | 855 if self.vars: |
| 856 return self.vars.tolineno |
| 857 else: |
| 858 return self.expr.tolineno |
899 | 859 |
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 | 860 |
908 class Yield(NodeNG): | 861 class Yield(NodeNG): |
909 """class representing a Yield node""" | 862 """class representing a Yield node""" |
910 _astroid_fields = ('value',) | 863 _astng_fields = ('value',) |
911 value = None | 864 value = None |
912 | 865 |
913 class YieldFrom(Yield): | |
914 """ Class representing a YieldFrom node. """ | |
915 | |
916 # constants ############################################################## | 866 # constants ############################################################## |
917 | 867 |
918 CONST_CLS = { | 868 CONST_CLS = { |
919 list: List, | 869 list: List, |
920 tuple: Tuple, | 870 tuple: Tuple, |
921 dict: Dict, | 871 dict: Dict, |
922 set: Set, | 872 set: Set, |
923 type(None): Const, | 873 type(None): Const, |
924 } | 874 } |
925 | 875 |
926 def _update_const_classes(): | 876 def _update_const_classes(): |
927 """update constant classes, so the keys of CONST_CLS can be reused""" | 877 """update constant classes, so the keys of CONST_CLS can be reused""" |
928 klasses = (bool, int, float, complex, str) | 878 klasses = (bool, int, float, complex, str) |
929 if sys.version_info < (3, 0): | 879 if sys.version_info < (3, 0): |
930 klasses += (unicode, long) | 880 klasses += (unicode, long) |
931 if sys.version_info >= (2, 6): | 881 if sys.version_info >= (2, 6): |
932 klasses += (bytes,) | 882 klasses += (bytes,) |
933 for kls in klasses: | 883 for kls in klasses: |
934 CONST_CLS[kls] = Const | 884 CONST_CLS[kls] = Const |
935 _update_const_classes() | 885 _update_const_classes() |
936 | 886 |
937 def const_factory(value): | 887 def const_factory(value): |
938 """return an astroid node for a python value""" | 888 """return an astng node for a python value""" |
939 # XXX we should probably be stricter here and only consider stuff in | 889 # since const_factory is called to evaluate content of container (eg list, |
940 # CONST_CLS or do better treatment: in case where value is not in CONST_CLS, | 890 # tuple), it may be called with some node as argument that should be left |
941 # we should rather recall the builder on this value than returning an empty | 891 # untouched |
942 # node (another option being that const_factory shouldn't be called with som
ething | 892 if isinstance(value, NodeNG): |
943 # not in CONST_CLS) | 893 return value |
944 assert not isinstance(value, NodeNG) | |
945 try: | 894 try: |
946 return CONST_CLS[value.__class__](value) | 895 return CONST_CLS[value.__class__](value) |
947 except (KeyError, AttributeError): | 896 except (KeyError, AttributeError): |
| 897 # some constants (like from gtk._gtk) don't have their class in |
| 898 # CONST_CLS, though we can "assert isinstance(value, tuple(CONST_CLS))" |
| 899 if isinstance(value, tuple(CONST_CLS)): |
| 900 return Const(value) |
948 node = EmptyNode() | 901 node = EmptyNode() |
949 node.object = value | 902 node.object = value |
950 return node | 903 return node |
OLD | NEW |