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 """This module contains the classes for "scoped" node, i.e. which are opening a | 20 """This module contains the classes for "scoped" node, i.e. which are opening a |
19 new local scope in the language definition : Module, Class, Function (and | 21 new local scope in the language definition : Module, Class, Function (and |
20 Lambda, GenExpr, DictComp and SetComp to some extent). | 22 Lambda, GenExpr, DictComp and SetComp to some extent). |
21 """ | 23 """ |
22 from __future__ import with_statement | 24 from __future__ import with_statement |
23 | 25 |
24 __doctype__ = "restructuredtext en" | 26 __doctype__ = "restructuredtext en" |
25 | 27 |
26 import sys | 28 import sys |
27 from itertools import chain | 29 from itertools import chain |
28 try: | |
29 from io import BytesIO | |
30 except ImportError: | |
31 from cStringIO import StringIO as BytesIO | |
32 | 30 |
33 from logilab.common.compat import builtins | 31 from logilab.common.compat import builtins |
34 from logilab.common.decorators import cached, cachedproperty | 32 from logilab.common.decorators import cached |
35 | 33 |
36 from astroid.exceptions import NotFoundError, \ | 34 from logilab.astng import BUILTINS_MODULE |
37 AstroidBuildingException, InferenceError | 35 from logilab.astng.exceptions import NotFoundError, NoDefault, \ |
38 from astroid.node_classes import Const, DelName, DelAttr, \ | 36 ASTNGBuildingException, InferenceError |
39 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ | 37 from logilab.astng.node_classes import Const, DelName, DelAttr, \ |
40 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc | 38 Dict, From, List, Name, Pass, Raise, Return, Tuple, Yield, \ |
41 from astroid.bases import NodeNG, InferenceContext, Instance,\ | 39 are_exclusive, LookupMixIn, const_factory as cf, unpack_infer |
| 40 from logilab.astng.bases import NodeNG, InferenceContext, Instance,\ |
42 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \ | 41 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, copy_context, \ |
43 BUILTINS | 42 BUILTINS_NAME |
44 from astroid.mixins import FilterStmtsMixin | 43 from logilab.astng.mixins import FilterStmtsMixin |
45 from astroid.bases import Statement | 44 from logilab.astng.bases import Statement |
46 from astroid.manager import AstroidManager | 45 from logilab.astng.manager import ASTNGManager |
47 | |
48 ITER_METHODS = ('__iter__', '__getitem__') | |
49 PY3K = sys.version_info >= (3, 0) | |
50 | 46 |
51 | 47 |
52 def remove_nodes(func, cls): | 48 def remove_nodes(func, cls): |
53 def wrapper(*args, **kwargs): | 49 def wrapper(*args, **kwargs): |
54 nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] | 50 nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] |
55 if not nodes: | 51 if not nodes: |
56 raise NotFoundError() | 52 raise NotFoundError() |
57 return nodes | 53 return nodes |
58 return wrapper | 54 return wrapper |
59 | 55 |
(...skipping 12 matching lines...) Expand all Loading... |
72 else: | 68 else: |
73 locals = {} | 69 locals = {} |
74 if name == '__name__': | 70 if name == '__name__': |
75 return [cf(self.name)] + locals.get(name, []) | 71 return [cf(self.name)] + locals.get(name, []) |
76 if name == '__doc__': | 72 if name == '__doc__': |
77 return [cf(self.doc)] + locals.get(name, []) | 73 return [cf(self.doc)] + locals.get(name, []) |
78 if name == '__dict__': | 74 if name == '__dict__': |
79 return [Dict()] + locals.get(name, []) | 75 return [Dict()] + locals.get(name, []) |
80 raise NotFoundError(name) | 76 raise NotFoundError(name) |
81 | 77 |
82 MANAGER = AstroidManager() | 78 MANAGER = ASTNGManager() |
83 def builtin_lookup(name): | 79 def builtin_lookup(name): |
84 """lookup a name into the builtin module | 80 """lookup a name into the builtin module |
85 return the list of matching statements and the astroid for the builtin | 81 return the list of matching statements and the astng for the builtin |
86 module | 82 module |
87 """ | 83 """ |
88 builtin_astroid = MANAGER.ast_from_module(builtins) | 84 builtin_astng = MANAGER.astng_from_module(builtins) |
89 if name == '__dict__': | 85 if name == '__dict__': |
90 return builtin_astroid, () | 86 return builtin_astng, () |
91 try: | 87 try: |
92 stmts = builtin_astroid.locals[name] | 88 stmts = builtin_astng.locals[name] |
93 except KeyError: | 89 except KeyError: |
94 stmts = () | 90 stmts = () |
95 return builtin_astroid, stmts | 91 return builtin_astng, stmts |
96 | 92 |
97 | 93 |
98 # TODO move this Mixin to mixins.py; problem: 'Function' in _scope_lookup | 94 # TODO move this Mixin to mixins.py; problem: 'Function' in _scope_lookup |
99 class LocalsDictNodeNG(LookupMixIn, NodeNG): | 95 class LocalsDictNodeNG(LookupMixIn, NodeNG): |
100 """ this class provides locals handling common to Module, Function | 96 """ this class provides locals handling common to Module, Function |
101 and Class nodes, including a dict like interface for direct access | 97 and Class nodes, including a dict like interface for direct access |
102 to locals information | 98 to locals information |
103 """ | 99 """ |
104 | 100 |
105 # attributes below are set by the builder module or by raw factories | 101 # attributes below are set by the builder module or by raw factories |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 return zip(self.keys(), self.values()) | 203 return zip(self.keys(), self.values()) |
208 | 204 |
209 | 205 |
210 def __contains__(self, name): | 206 def __contains__(self, name): |
211 return name in self.locals | 207 return name in self.locals |
212 has_key = __contains__ | 208 has_key = __contains__ |
213 | 209 |
214 # Module ##################################################################### | 210 # Module ##################################################################### |
215 | 211 |
216 class Module(LocalsDictNodeNG): | 212 class Module(LocalsDictNodeNG): |
217 _astroid_fields = ('body',) | 213 _astng_fields = ('body',) |
218 | 214 |
219 fromlineno = 0 | 215 fromlineno = 0 |
220 lineno = 0 | 216 lineno = 0 |
221 | 217 |
222 # attributes below are set by the builder module or by raw factories | 218 # attributes below are set by the builder module or by raw factories |
223 | 219 |
224 # the file from which as been extracted the astroid representation. It may | 220 # the file from which as been extracted the astng representation. It may |
225 # be None if the representation has been built from a built-in module | 221 # be None if the representation has been built from a built-in module |
226 file = None | 222 file = None |
227 # Alternatively, if built from a string/bytes, this can be set | |
228 file_bytes = None | |
229 # encoding of python source file, so we can get unicode out of it (python2 | |
230 # only) | |
231 file_encoding = None | |
232 # the module name | 223 # the module name |
233 name = None | 224 name = None |
234 # boolean for astroid built from source (i.e. ast) | 225 # boolean for astng built from source (i.e. ast) |
235 pure_python = None | 226 pure_python = None |
236 # boolean for package module | 227 # boolean for package module |
237 package = None | 228 package = None |
238 # dictionary of globals with name as key and node defining the global | 229 # dictionary of globals with name as key and node defining the global |
239 # as value | 230 # as value |
240 globals = None | 231 globals = None |
241 | 232 |
242 # Future imports | |
243 future_imports = None | |
244 | |
245 # names of python special attributes (handled by getattr impl.) | 233 # names of python special attributes (handled by getattr impl.) |
246 special_attributes = set(('__name__', '__doc__', '__file__', '__path__', | 234 special_attributes = set(('__name__', '__doc__', '__file__', '__path__', |
247 '__dict__')) | 235 '__dict__')) |
248 # names of module attributes available through the global scope | 236 # names of module attributes available through the global scope |
249 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) | 237 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) |
250 | 238 |
251 def __init__(self, name, doc, pure_python=True): | 239 def __init__(self, name, doc, pure_python=True): |
252 self.name = name | 240 self.name = name |
253 self.doc = doc | 241 self.doc = doc |
254 self.pure_python = pure_python | 242 self.pure_python = pure_python |
255 self.locals = self.globals = {} | 243 self.locals = self.globals = {} |
256 self.body = [] | 244 self.body = [] |
257 self.future_imports = set() | |
258 | 245 |
259 @property | 246 @property |
260 def file_stream(self): | 247 def file_stream(self): |
261 if self.file_bytes is not None: | |
262 return BytesIO(self.file_bytes) | |
263 if self.file is not None: | 248 if self.file is not None: |
264 return open(self.file, 'rb') | 249 return file(self.file) |
265 return None | 250 return None |
266 | 251 |
267 def block_range(self, lineno): | 252 def block_range(self, lineno): |
268 """return block line numbers. | 253 """return block line numbers. |
269 | 254 |
270 start from the beginning whatever the given lineno | 255 start from the beginning whatever the given lineno |
271 """ | 256 """ |
272 return self.fromlineno, self.tolineno | 257 return self.fromlineno, self.tolineno |
273 | 258 |
274 def scope_lookup(self, node, name, offset=0): | 259 def scope_lookup(self, node, name, offset=0): |
275 if name in self.scope_attrs and not name in self.locals: | 260 if name in self.scope_attrs and not name in self.locals: |
276 try: | 261 try: |
277 return self, self.getattr(name) | 262 return self, self.getattr(name) |
278 except NotFoundError: | 263 except NotFoundError: |
279 return self, () | 264 return self, () |
280 return self._scope_lookup(node, name, offset) | 265 return self._scope_lookup(node, name, offset) |
281 | 266 |
282 def pytype(self): | 267 def pytype(self): |
283 return '%s.module' % BUILTINS | 268 return '%s.module' % BUILTINS_MODULE |
284 | 269 |
285 def display_type(self): | 270 def display_type(self): |
286 return 'Module' | 271 return 'Module' |
287 | 272 |
288 def getattr(self, name, context=None, ignore_locals=False): | 273 def getattr(self, name, context=None, ignore_locals=False): |
289 if name in self.special_attributes: | 274 if name in self.special_attributes: |
290 if name == '__file__': | 275 if name == '__file__': |
291 return [cf(self.file)] + self.locals.get(name, []) | 276 return [cf(self.file)] + self.locals.get(name, []) |
292 if name == '__path__' and self.package: | 277 if name == '__path__' and self.package: |
293 return [List()] + self.locals.get(name, []) | 278 return [List()] + self.locals.get(name, []) |
294 return std_special_attributes(self, name) | 279 return std_special_attributes(self, name) |
295 if not ignore_locals and name in self.locals: | 280 if not ignore_locals and name in self.locals: |
296 return self.locals[name] | 281 return self.locals[name] |
297 if self.package: | 282 if self.package: |
298 try: | 283 try: |
299 return [self.import_module(name, relative_only=True)] | 284 return [self.import_module(name, relative_only=True)] |
300 except AstroidBuildingException: | 285 except ASTNGBuildingException: |
301 raise NotFoundError(name) | |
302 except SyntaxError: | |
303 raise NotFoundError(name) | 286 raise NotFoundError(name) |
304 except Exception:# XXX pylint tests never pass here; do we need it? | 287 except Exception:# XXX pylint tests never pass here; do we need it? |
305 import traceback | 288 import traceback |
306 traceback.print_exc() | 289 traceback.print_exc() |
307 raise NotFoundError(name) | 290 raise NotFoundError(name) |
308 getattr = remove_nodes(getattr, DelName) | 291 getattr = remove_nodes(getattr, DelName) |
309 | 292 |
310 def igetattr(self, name, context=None): | 293 def igetattr(self, name, context=None): |
311 """inferred getattr""" | 294 """inferred getattr""" |
312 # set lookup name since this is necessary to infer on import nodes for | 295 # set lookup name since this is necessary to infer on import nodes for |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 return False | 329 return False |
347 else: | 330 else: |
348 absolute_import_activated = lambda self: True | 331 absolute_import_activated = lambda self: True |
349 | 332 |
350 def import_module(self, modname, relative_only=False, level=None): | 333 def import_module(self, modname, relative_only=False, level=None): |
351 """import the given module considering self as context""" | 334 """import the given module considering self as context""" |
352 if relative_only and level is None: | 335 if relative_only and level is None: |
353 level = 0 | 336 level = 0 |
354 absmodname = self.relative_to_absolute_name(modname, level) | 337 absmodname = self.relative_to_absolute_name(modname, level) |
355 try: | 338 try: |
356 return MANAGER.ast_from_module_name(absmodname) | 339 return MANAGER.astng_from_module_name(absmodname) |
357 except AstroidBuildingException: | 340 except ASTNGBuildingException: |
358 # we only want to import a sub module or package of this module, | 341 # we only want to import a sub module or package of this module, |
359 # skip here | 342 # skip here |
360 if relative_only: | 343 if relative_only: |
361 raise | 344 raise |
362 return MANAGER.ast_from_module_name(modname) | 345 return MANAGER.astng_from_module_name(modname) |
363 | 346 |
364 def relative_to_absolute_name(self, modname, level): | 347 def relative_to_absolute_name(self, modname, level): |
365 """return the absolute module name for a relative import. | 348 """return the absolute module name for a relative import. |
366 | 349 |
367 The relative import can be implicit or explicit. | 350 The relative import can be implicit or explicit. |
368 """ | 351 """ |
369 # XXX this returns non sens when called on an absolute import | 352 # XXX this returns non sens when called on an absolute import |
370 # like 'pylint.checkers.astroid.utils' | 353 # like 'pylint.checkers.logilab.astng.utils' |
371 # XXX doesn't return absolute name if self.name isn't absolute name | 354 # XXX doesn't return absolute name if self.name isn't absolute name |
372 if self.absolute_import_activated() and level is None: | 355 if self.absolute_import_activated() and level is None: |
373 return modname | 356 return modname |
374 if level: | 357 if level: |
375 if self.package: | 358 if self.package: |
376 level = level - 1 | 359 level = level - 1 |
377 package_name = self.name.rsplit('.', level)[0] | 360 package_name = self.name.rsplit('.', level)[0] |
378 elif self.package: | 361 elif self.package: |
379 package_name = self.name | 362 package_name = self.name |
380 else: | 363 else: |
(...skipping 16 matching lines...) Expand all Loading... |
397 try: | 380 try: |
398 living = sys.modules[self.name] | 381 living = sys.modules[self.name] |
399 except KeyError: | 382 except KeyError: |
400 pass | 383 pass |
401 else: | 384 else: |
402 try: | 385 try: |
403 return living.__all__ | 386 return living.__all__ |
404 except AttributeError: | 387 except AttributeError: |
405 return [name for name in living.__dict__.keys() | 388 return [name for name in living.__dict__.keys() |
406 if not name.startswith('_')] | 389 if not name.startswith('_')] |
407 # else lookup the astroid | 390 # else lookup the astng |
408 # | 391 # |
409 # We separate the different steps of lookup in try/excepts | 392 # We separate the different steps of lookup in try/excepts |
410 # to avoid catching too many Exceptions | 393 # to avoid catching too many Exceptions |
411 # However, we can not analyse dynamically constructed __all__ | 394 # However, we can not analyse dynamically constructed __all__ |
412 try: | 395 try: |
413 all = self['__all__'] | 396 all = self['__all__'] |
414 except KeyError: | 397 except KeyError: |
415 return [name for name in self.keys() if not name.startswith('_')] | 398 return [name for name in self.keys() if not name.startswith('_')] |
416 try: | 399 try: |
417 explicit = all.assigned_stmts().next() | 400 explicit = all.assigned_stmts().next() |
(...skipping 11 matching lines...) Expand all Loading... |
429 | 412 |
430 | 413 |
431 class ComprehensionScope(LocalsDictNodeNG): | 414 class ComprehensionScope(LocalsDictNodeNG): |
432 def frame(self): | 415 def frame(self): |
433 return self.parent.frame() | 416 return self.parent.frame() |
434 | 417 |
435 scope_lookup = LocalsDictNodeNG._scope_lookup | 418 scope_lookup = LocalsDictNodeNG._scope_lookup |
436 | 419 |
437 | 420 |
438 class GenExpr(ComprehensionScope): | 421 class GenExpr(ComprehensionScope): |
439 _astroid_fields = ('elt', 'generators') | 422 _astng_fields = ('elt', 'generators') |
440 | 423 |
441 def __init__(self): | 424 def __init__(self): |
442 self.locals = {} | 425 self.locals = {} |
443 self.elt = None | 426 self.elt = None |
444 self.generators = [] | 427 self.generators = [] |
445 | 428 |
446 | 429 |
447 class DictComp(ComprehensionScope): | 430 class DictComp(ComprehensionScope): |
448 _astroid_fields = ('key', 'value', 'generators') | 431 _astng_fields = ('key', 'value', 'generators') |
449 | 432 |
450 def __init__(self): | 433 def __init__(self): |
451 self.locals = {} | 434 self.locals = {} |
452 self.key = None | 435 self.key = None |
453 self.value = None | 436 self.value = None |
454 self.generators = [] | 437 self.generators = [] |
455 | 438 |
456 | 439 |
457 class SetComp(ComprehensionScope): | 440 class SetComp(ComprehensionScope): |
458 _astroid_fields = ('elt', 'generators') | 441 _astng_fields = ('elt', 'generators') |
459 | 442 |
460 def __init__(self): | 443 def __init__(self): |
461 self.locals = {} | 444 self.locals = {} |
462 self.elt = None | 445 self.elt = None |
463 self.generators = [] | 446 self.generators = [] |
464 | 447 |
465 | 448 |
466 class _ListComp(NodeNG): | 449 class _ListComp(NodeNG): |
467 """class representing a ListComp node""" | 450 """class representing a ListComp node""" |
468 _astroid_fields = ('elt', 'generators') | 451 _astng_fields = ('elt', 'generators') |
469 elt = None | 452 elt = None |
470 generators = None | 453 generators = None |
471 | 454 |
472 if sys.version_info >= (3, 0): | 455 if sys.version_info >= (3, 0): |
473 class ListComp(_ListComp, ComprehensionScope): | 456 class ListComp(_ListComp, ComprehensionScope): |
474 """class representing a ListComp node""" | 457 """class representing a ListComp node""" |
475 def __init__(self): | 458 def __init__(self): |
476 self.locals = {} | 459 self.locals = {} |
477 else: | 460 else: |
478 class ListComp(_ListComp): | 461 class ListComp(_ListComp): |
479 """class representing a ListComp node""" | 462 """class representing a ListComp node""" |
480 | 463 |
481 # Function ################################################################### | 464 # Function ################################################################### |
482 | 465 |
483 def _infer_decorator_callchain(node): | |
484 """ Detect decorator call chaining and see if the | |
485 end result is a static or a classmethod. | |
486 """ | |
487 current = node | |
488 while True: | |
489 if isinstance(current, CallFunc): | |
490 try: | |
491 current = current.func.infer().next() | |
492 except InferenceError: | |
493 return | |
494 elif isinstance(current, Function): | |
495 if not current.parent: | |
496 return | |
497 try: | |
498 # TODO: We don't handle multiple inference results right now, | |
499 # because there's no flow to reason when the return | |
500 # is what we are looking for, a static or a class method. | |
501 result = current.infer_call_result(current.parent).next() | |
502 except (StopIteration, InferenceError): | |
503 return | |
504 if isinstance(result, (Function, CallFunc)): | |
505 current = result | |
506 else: | |
507 if isinstance(result, Instance): | |
508 result = result._proxied | |
509 if isinstance(result, Class): | |
510 if (result.name == 'classmethod' and | |
511 result.root().name == BUILTINS): | |
512 return 'classmethod' | |
513 elif (result.name == 'staticmethod' and | |
514 result.root().name == BUILTINS): | |
515 return 'staticmethod' | |
516 else: | |
517 return | |
518 else: | |
519 # We aren't interested in anything else returned, | |
520 # so go back to the function type inference. | |
521 return | |
522 else: | |
523 return | |
524 | |
525 def _function_type(self): | |
526 """ | |
527 Function type, possible values are: | |
528 method, function, staticmethod, classmethod. | |
529 """ | |
530 # Can't infer that this node is decorated | |
531 # with a subclass of `classmethod` where `type` is first set, | |
532 # so do it here. | |
533 if self.decorators: | |
534 for node in self.decorators.nodes: | |
535 if isinstance(node, CallFunc): | |
536 _type = _infer_decorator_callchain(node) | |
537 if _type is None: | |
538 continue | |
539 else: | |
540 return _type | |
541 if not isinstance(node, Name): | |
542 continue | |
543 try: | |
544 for infered in node.infer(): | |
545 if not isinstance(infered, Class): | |
546 continue | |
547 for ancestor in infered.ancestors(): | |
548 if isinstance(ancestor, Class): | |
549 if (ancestor.name == 'classmethod' and | |
550 ancestor.root().name == BUILTINS): | |
551 return 'classmethod' | |
552 elif (ancestor.name == 'staticmethod' and | |
553 ancestor.root().name == BUILTINS): | |
554 return 'staticmethod' | |
555 except InferenceError: | |
556 pass | |
557 return self._type | |
558 | |
559 | 466 |
560 class Lambda(LocalsDictNodeNG, FilterStmtsMixin): | 467 class Lambda(LocalsDictNodeNG, FilterStmtsMixin): |
561 _astroid_fields = ('args', 'body',) | 468 _astng_fields = ('args', 'body',) |
562 name = '<lambda>' | 469 name = '<lambda>' |
563 | 470 |
564 # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' | 471 # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' |
565 type = 'function' | 472 type = 'function' |
566 | 473 |
567 def __init__(self): | 474 def __init__(self): |
568 self.locals = {} | 475 self.locals = {} |
569 self.args = [] | 476 self.args = [] |
570 self.body = [] | 477 self.body = [] |
571 | 478 |
572 def pytype(self): | 479 def pytype(self): |
573 if 'method' in self.type: | 480 if 'method' in self.type: |
574 return '%s.instancemethod' % BUILTINS | 481 return '%s.instancemethod' % BUILTINS_MODULE |
575 return '%s.function' % BUILTINS | 482 return '%s.function' % BUILTINS_MODULE |
576 | 483 |
577 def display_type(self): | 484 def display_type(self): |
578 if 'method' in self.type: | 485 if 'method' in self.type: |
579 return 'Method' | 486 return 'Method' |
580 return 'Function' | 487 return 'Function' |
581 | 488 |
582 def callable(self): | 489 def callable(self): |
583 return True | 490 return True |
584 | 491 |
585 def argnames(self): | 492 def argnames(self): |
586 """return a list of argument names""" | 493 """return a list of argument names""" |
587 if self.args.args: # maybe None with builtin functions | 494 if self.args.args: # maybe None with builtin functions |
588 names = _rec_get_names(self.args.args) | 495 names = _rec_get_names(self.args.args) |
589 else: | 496 else: |
590 names = [] | 497 names = [] |
591 if self.args.vararg: | 498 if self.args.vararg: |
592 names.append(self.args.vararg) | 499 names.append(self.args.vararg) |
593 if self.args.kwarg: | 500 if self.args.kwarg: |
594 names.append(self.args.kwarg) | 501 names.append(self.args.kwarg) |
595 return names | 502 return names |
596 | 503 |
597 def infer_call_result(self, caller, context=None): | 504 def infer_call_result(self, caller, context=None): |
598 """infer what a function is returning when called""" | 505 """infer what a function is returning when called""" |
599 return self.body.infer(context) | 506 return self.body.infer(context) |
600 | 507 |
601 def scope_lookup(self, node, name, offset=0): | 508 def scope_lookup(self, node, name, offset=0): |
602 if node in self.args.defaults or node in self.args.kw_defaults: | 509 if node in self.args.defaults: |
603 frame = self.parent.frame() | 510 frame = self.parent.frame() |
604 # line offset to avoid that def func(f=func) resolve the default | 511 # line offset to avoid that def func(f=func) resolve the default |
605 # value to the defined function | 512 # value to the defined function |
606 offset = -1 | 513 offset = -1 |
607 else: | 514 else: |
608 # check this is not used in function decorators | 515 # check this is not used in function decorators |
609 frame = self | 516 frame = self |
610 return frame._scope_lookup(node, name, offset) | 517 return frame._scope_lookup(node, name, offset) |
611 | 518 |
612 | 519 |
613 class Function(Statement, Lambda): | 520 class Function(Statement, Lambda): |
614 if PY3K: | 521 _astng_fields = ('decorators', 'args', 'body') |
615 _astroid_fields = ('decorators', 'args', 'body', 'returns') | |
616 returns = None | |
617 else: | |
618 _astroid_fields = ('decorators', 'args', 'body') | |
619 | 522 |
620 special_attributes = set(('__name__', '__doc__', '__dict__')) | 523 special_attributes = set(('__name__', '__doc__', '__dict__')) |
621 is_function = True | 524 is_function = True |
622 # attributes below are set by the builder module or by raw factories | 525 # attributes below are set by the builder module or by raw factories |
623 blockstart_tolineno = None | 526 blockstart_tolineno = None |
624 decorators = None | 527 decorators = None |
625 _type = "function" | |
626 type = cachedproperty(_function_type) | |
627 | 528 |
628 def __init__(self, name, doc): | 529 def __init__(self, name, doc): |
629 self.locals = {} | 530 self.locals = {} |
630 self.args = [] | 531 self.args = [] |
631 self.body = [] | 532 self.body = [] |
632 self.decorators = None | 533 self.decorators = None |
633 self.name = name | 534 self.name = name |
634 self.doc = doc | 535 self.doc = doc |
635 self.extra_decorators = [] | 536 self.extra_decorators = [] |
636 self.instance_attrs = {} | 537 self.instance_attrs = {} |
637 | 538 |
638 def set_line_info(self, lastchild): | 539 def set_line_info(self, lastchild): |
639 self.fromlineno = self.lineno | 540 self.fromlineno = self.lineno |
640 # lineno is the line number of the first decorator, we want the def stat
ement lineno | 541 # lineno is the line number of the first decorator, we want the def stat
ement lineno |
641 if self.decorators is not None: | 542 if self.decorators is not None: |
642 self.fromlineno += sum(node.tolineno - node.lineno + 1 | 543 self.fromlineno += len(self.decorators.nodes) |
643 for node in self.decorators.nodes) | |
644 if self.args.fromlineno < self.fromlineno: | |
645 self.args.fromlineno = self.fromlineno | |
646 self.tolineno = lastchild.tolineno | 544 self.tolineno = lastchild.tolineno |
647 self.blockstart_tolineno = self.args.tolineno | 545 self.blockstart_tolineno = self.args.tolineno |
648 | 546 |
649 def block_range(self, lineno): | 547 def block_range(self, lineno): |
650 """return block line numbers. | 548 """return block line numbers. |
651 | 549 |
652 start from the "def" position whatever the given lineno | 550 start from the "def" position whatever the given lineno |
653 """ | 551 """ |
654 return self.fromlineno, self.tolineno | 552 return self.fromlineno, self.tolineno |
655 | 553 |
(...skipping 24 matching lines...) Expand all Loading... |
680 for infnode in decnode.infer(): | 578 for infnode in decnode.infer(): |
681 result.add(infnode.qname()) | 579 result.add(infnode.qname()) |
682 return result | 580 return result |
683 decoratornames = cached(decoratornames) | 581 decoratornames = cached(decoratornames) |
684 | 582 |
685 def is_bound(self): | 583 def is_bound(self): |
686 """return true if the function is bound to an Instance or a class""" | 584 """return true if the function is bound to an Instance or a class""" |
687 return self.type == 'classmethod' | 585 return self.type == 'classmethod' |
688 | 586 |
689 def is_abstract(self, pass_is_abstract=True): | 587 def is_abstract(self, pass_is_abstract=True): |
690 """Returns True if the method is abstract. | 588 """return true if the method is abstract |
691 | 589 It's considered as abstract if the only statement is a raise of |
692 A method is considered abstract if | 590 NotImplementError, or, if pass_is_abstract, a pass statement |
693 - the only statement is 'raise NotImplementedError', or | |
694 - the only statement is 'pass' and pass_is_abstract is True, or | |
695 - the method is annotated with abc.astractproperty/abc.abstractmethod | |
696 """ | 591 """ |
697 if self.decorators: | |
698 for node in self.decorators.nodes: | |
699 try: | |
700 infered = node.infer().next() | |
701 except InferenceError: | |
702 continue | |
703 if infered and infered.qname() in ('abc.abstractproperty', | |
704 'abc.abstractmethod'): | |
705 return True | |
706 | |
707 for child_node in self.body: | 592 for child_node in self.body: |
708 if isinstance(child_node, Raise): | 593 if isinstance(child_node, Raise): |
709 if child_node.raises_not_implemented(): | 594 if child_node.raises_not_implemented(): |
710 return True | 595 return True |
711 if pass_is_abstract and isinstance(child_node, Pass): | 596 if pass_is_abstract and isinstance(child_node, Pass): |
712 return True | 597 return True |
713 return False | 598 return False |
714 # empty function is the same as function with a single "pass" statement | 599 # empty function is the same as function with a single "pass" statement |
715 if pass_is_abstract: | 600 if pass_is_abstract: |
716 return True | 601 return True |
717 | 602 |
718 def is_generator(self): | 603 def is_generator(self): |
719 """return true if this is a generator function""" | 604 """return true if this is a generator function""" |
720 # XXX should be flagged, not computed | 605 # XXX should be flagged, not computed |
721 try: | 606 try: |
722 return self.nodes_of_class((Yield, YieldFrom), | 607 return self.nodes_of_class(Yield, skip_klass=Function).next() |
723 skip_klass=(Function, Lambda)).next() | |
724 except StopIteration: | 608 except StopIteration: |
725 return False | 609 return False |
726 | 610 |
727 def infer_call_result(self, caller, context=None): | 611 def infer_call_result(self, caller, context=None): |
728 """infer what a function is returning when called""" | 612 """infer what a function is returning when called""" |
729 if self.is_generator(): | 613 if self.is_generator(): |
730 yield Generator() | 614 yield Generator(self) |
731 return | 615 return |
732 returns = self.nodes_of_class(Return, skip_klass=Function) | 616 returns = self.nodes_of_class(Return, skip_klass=Function) |
733 for returnnode in returns: | 617 for returnnode in returns: |
734 if returnnode.value is None: | 618 if returnnode.value is None: |
735 yield Const(None) | 619 yield Const(None) |
736 else: | 620 else: |
737 try: | 621 try: |
738 for infered in returnnode.value.infer(context): | 622 for infered in returnnode.value.infer(context): |
739 yield infered | 623 yield infered |
740 except InferenceError: | 624 except InferenceError: |
741 yield YES | 625 yield YES |
742 | 626 |
743 | 627 |
744 def _rec_get_names(args, names=None): | 628 def _rec_get_names(args, names=None): |
745 """return a list of all argument names""" | 629 """return a list of all argument names""" |
746 if names is None: | 630 if names is None: |
747 names = [] | 631 names = [] |
748 for arg in args: | 632 for arg in args: |
749 if isinstance(arg, Tuple): | 633 if isinstance(arg, Tuple): |
750 _rec_get_names(arg.elts, names) | 634 _rec_get_names(arg.elts, names) |
751 else: | 635 else: |
752 names.append(arg.name) | 636 names.append(arg.name) |
753 return names | 637 return names |
754 | 638 |
755 | 639 |
756 # Class ###################################################################### | 640 # Class ###################################################################### |
757 | 641 |
758 | |
759 def _is_metaclass(klass, seen=None): | |
760 """ Return if the given class can be | |
761 used as a metaclass. | |
762 """ | |
763 if klass.name == 'type': | |
764 return True | |
765 if seen is None: | |
766 seen = set() | |
767 for base in klass.bases: | |
768 try: | |
769 for baseobj in base.infer(): | |
770 if baseobj in seen: | |
771 continue | |
772 else: | |
773 seen.add(baseobj) | |
774 if isinstance(baseobj, Instance): | |
775 # not abstract | |
776 return False | |
777 if baseobj is YES: | |
778 continue | |
779 if baseobj is klass: | |
780 continue | |
781 if not isinstance(baseobj, Class): | |
782 continue | |
783 if baseobj._type == 'metaclass': | |
784 return True | |
785 if _is_metaclass(baseobj, seen): | |
786 return True | |
787 except InferenceError: | |
788 continue | |
789 return False | |
790 | |
791 | |
792 def _class_type(klass, ancestors=None): | 642 def _class_type(klass, ancestors=None): |
793 """return a Class node type to differ metaclass, interface and exception | 643 """return a Class node type to differ metaclass, interface and exception |
794 from 'regular' classes | 644 from 'regular' classes |
795 """ | 645 """ |
796 # XXX we have to store ancestors in case we have a ancestor loop | 646 # XXX we have to store ancestors in case we have a ancestor loop |
797 if klass._type is not None: | 647 if klass._type is not None: |
798 return klass._type | 648 return klass._type |
799 if _is_metaclass(klass): | 649 if klass.name == 'type': |
800 klass._type = 'metaclass' | 650 klass._type = 'metaclass' |
801 elif klass.name.endswith('Interface'): | 651 elif klass.name.endswith('Interface'): |
802 klass._type = 'interface' | 652 klass._type = 'interface' |
803 elif klass.name.endswith('Exception'): | 653 elif klass.name.endswith('Exception'): |
804 klass._type = 'exception' | 654 klass._type = 'exception' |
805 else: | 655 else: |
806 if ancestors is None: | 656 if ancestors is None: |
807 ancestors = set() | 657 ancestors = set() |
808 if klass in ancestors: | 658 if klass in ancestors: |
809 # XXX we are in loop ancestors, and have found no type | 659 # XXX we are in loop ancestors, and have found no type |
810 klass._type = 'class' | 660 klass._type = 'class' |
811 return 'class' | 661 return 'class' |
812 ancestors.add(klass) | 662 ancestors.add(klass) |
813 # print >> sys.stderr, '_class_type', repr(klass) | 663 # print >> sys.stderr, '_class_type', repr(klass) |
814 for base in klass.ancestors(recurs=False): | 664 for base in klass.ancestors(recurs=False): |
815 name = _class_type(base, ancestors) | 665 if _class_type(base, ancestors) != 'class': |
816 if name != 'class': | |
817 if name == 'metaclass' and not _is_metaclass(klass): | |
818 # don't propagate it if the current class | |
819 # can't be a metaclass | |
820 continue | |
821 klass._type = base.type | 666 klass._type = base.type |
822 break | 667 break |
823 if klass._type is None: | 668 if klass._type is None: |
824 klass._type = 'class' | 669 klass._type = 'class' |
825 return klass._type | 670 return klass._type |
826 | 671 |
827 def _iface_hdlr(iface_node): | 672 def _iface_hdlr(iface_node): |
828 """a handler function used by interfaces to handle suspicious | 673 """a handler function used by interfaces to handle suspicious |
829 interface nodes | 674 interface nodes |
830 """ | 675 """ |
831 return True | 676 return True |
832 | 677 |
833 | 678 |
834 class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): | 679 class Class(Statement, LocalsDictNodeNG, FilterStmtsMixin): |
835 | 680 |
836 # some of the attributes below are set by the builder module or | 681 # some of the attributes below are set by the builder module or |
837 # by a raw factories | 682 # by a raw factories |
838 | 683 |
839 # a dictionary of class instances attributes | 684 # a dictionary of class instances attributes |
840 _astroid_fields = ('decorators', 'bases', 'body') # name | 685 _astng_fields = ('decorators', 'bases', 'body') # name |
841 | 686 |
842 decorators = None | 687 decorators = None |
843 special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', | 688 special_attributes = set(('__name__', '__doc__', '__dict__', '__module__', |
844 '__bases__', '__mro__', '__subclasses__')) | 689 '__bases__', '__mro__', '__subclasses__')) |
845 blockstart_tolineno = None | 690 blockstart_tolineno = None |
846 | 691 |
847 _type = None | 692 _type = None |
848 type = property(_class_type, | 693 type = property(_class_type, |
849 doc="class'type, possible values are 'class' | " | 694 doc="class'type, possible values are 'class' | " |
850 "'metaclass' | 'interface' | 'exception'") | 695 "'metaclass' | 'interface' | 'exception'") |
851 | 696 |
852 def __init__(self, name, doc): | 697 def __init__(self, name, doc): |
853 self.instance_attrs = {} | 698 self.instance_attrs = {} |
854 self.locals = {} | 699 self.locals = {} |
855 self.bases = [] | 700 self.bases = [] |
856 self.body = [] | 701 self.body = [] |
857 self.name = name | 702 self.name = name |
858 self.doc = doc | 703 self.doc = doc |
859 | 704 |
860 def _newstyle_impl(self, context=None): | 705 def _newstyle_impl(self, context=None): |
861 if context is None: | 706 if context is None: |
862 context = InferenceContext() | 707 context = InferenceContext() |
863 if self._newstyle is not None: | 708 if self._newstyle is not None: |
864 return self._newstyle | 709 return self._newstyle |
865 for base in self.ancestors(recurs=False, context=context): | 710 for base in self.ancestors(recurs=False, context=context): |
866 if base._newstyle_impl(context): | 711 if base._newstyle_impl(context): |
867 self._newstyle = True | 712 self._newstyle = True |
868 break | 713 break |
869 klass = self._explicit_metaclass() | |
870 # could be any callable, we'd need to infer the result of klass(name, | |
871 # bases, dict). punt if it's not a class node. | |
872 if klass is not None and isinstance(klass, Class): | |
873 self._newstyle = klass._newstyle_impl(context) | |
874 if self._newstyle is None: | 714 if self._newstyle is None: |
875 self._newstyle = False | 715 self._newstyle = False |
876 return self._newstyle | 716 return self._newstyle |
877 | 717 |
878 _newstyle = None | 718 _newstyle = None |
879 newstyle = property(_newstyle_impl, | 719 newstyle = property(_newstyle_impl, |
880 doc="boolean indicating if it's a new style class" | 720 doc="boolean indicating if it's a new style class" |
881 "or not") | 721 "or not") |
882 | 722 |
883 def set_line_info(self, lastchild): | 723 def set_line_info(self, lastchild): |
884 self.fromlineno = self.lineno | 724 self.fromlineno = self.lineno |
885 self.blockstart_tolineno = self.bases and self.bases[-1].tolineno or sel
f.fromlineno | 725 self.blockstart_tolineno = self.bases and self.bases[-1].tolineno or sel
f.fromlineno |
886 if lastchild is not None: | 726 if lastchild is not None: |
887 self.tolineno = lastchild.tolineno | 727 self.tolineno = lastchild.tolineno |
888 # else this is a class with only a docstring, then tolineno is (should b
e) already ok | 728 # else this is a class with only a docstring, then tolineno is (should b
e) already ok |
889 | 729 |
890 def block_range(self, lineno): | 730 def block_range(self, lineno): |
891 """return block line numbers. | 731 """return block line numbers. |
892 | 732 |
893 start from the "class" position whatever the given lineno | 733 start from the "class" position whatever the given lineno |
894 """ | 734 """ |
895 return self.fromlineno, self.tolineno | 735 return self.fromlineno, self.tolineno |
896 | 736 |
897 def pytype(self): | 737 def pytype(self): |
898 if self.newstyle: | 738 if self.newstyle: |
899 return '%s.type' % BUILTINS | 739 return '%s.type' % BUILTINS_MODULE |
900 return '%s.classobj' % BUILTINS | 740 return '%s.classobj' % BUILTINS_MODULE |
901 | 741 |
902 def display_type(self): | 742 def display_type(self): |
903 return 'Class' | 743 return 'Class' |
904 | 744 |
905 def callable(self): | 745 def callable(self): |
906 return True | 746 return True |
907 | 747 |
908 def _is_subtype_of(self, type_name): | |
909 if self.qname() == type_name: | |
910 return True | |
911 for anc in self.ancestors(): | |
912 if anc.qname() == type_name: | |
913 return True | |
914 | |
915 def infer_call_result(self, caller, context=None): | 748 def infer_call_result(self, caller, context=None): |
916 """infer what a class is returning when called""" | 749 """infer what a class is returning when called""" |
917 if self._is_subtype_of('%s.type' % (BUILTINS,)) and len(caller.args) ==
3: | 750 yield Instance(self) |
918 name_node = caller.args[0].infer().next() | |
919 if isinstance(name_node, Const) and isinstance(name_node.value, base
string): | |
920 name = name_node.value | |
921 else: | |
922 yield YES | |
923 return | |
924 result = Class(name, None) | |
925 bases = caller.args[1].infer().next() | |
926 if isinstance(bases, (Tuple, List)): | |
927 result.bases = bases.itered() | |
928 else: | |
929 # There is currently no AST node that can represent an 'unknown' | |
930 # node (YES is not an AST node), therefore we simply return YES
here | |
931 # although we know at least the name of the class. | |
932 yield YES | |
933 return | |
934 result.parent = caller.parent | |
935 yield result | |
936 else: | |
937 yield Instance(self) | |
938 | 751 |
939 def scope_lookup(self, node, name, offset=0): | 752 def scope_lookup(self, node, name, offset=0): |
940 if node in self.bases: | 753 if node in self.bases: |
941 frame = self.parent.frame() | 754 frame = self.parent.frame() |
942 # line offset to avoid that class A(A) resolve the ancestor to | 755 # line offset to avoid that class A(A) resolve the ancestor to |
943 # the defined class | 756 # the defined class |
944 offset = -1 | 757 offset = -1 |
945 else: | 758 else: |
946 frame = self | 759 frame = self |
947 return frame._scope_lookup(node, name, offset) | 760 return frame._scope_lookup(node, name, offset) |
(...skipping 16 matching lines...) Expand all Loading... |
964 # XXX inference make infinite loops possible here (see BaseTransformer | 777 # XXX inference make infinite loops possible here (see BaseTransformer |
965 # manipulation in the builder module for instance) | 778 # manipulation in the builder module for instance) |
966 yielded = set([self]) | 779 yielded = set([self]) |
967 if context is None: | 780 if context is None: |
968 context = InferenceContext() | 781 context = InferenceContext() |
969 for stmt in self.bases: | 782 for stmt in self.bases: |
970 with context.restore_path(): | 783 with context.restore_path(): |
971 try: | 784 try: |
972 for baseobj in stmt.infer(context): | 785 for baseobj in stmt.infer(context): |
973 if not isinstance(baseobj, Class): | 786 if not isinstance(baseobj, Class): |
974 if isinstance(baseobj, Instance): | 787 # duh ? |
975 baseobj = baseobj._proxied | 788 continue |
976 else: | |
977 # duh ? | |
978 continue | |
979 if baseobj in yielded: | 789 if baseobj in yielded: |
980 continue # cf xxx above | 790 continue # cf xxx above |
981 yielded.add(baseobj) | 791 yielded.add(baseobj) |
982 yield baseobj | 792 yield baseobj |
983 if recurs: | 793 if recurs: |
984 for grandpa in baseobj.ancestors(True, context): | 794 for grandpa in baseobj.ancestors(True, context): |
985 if grandpa in yielded: | 795 if grandpa in yielded: |
986 continue # cf xxx above | 796 continue # cf xxx above |
987 yielded.add(grandpa) | 797 yielded.add(grandpa) |
988 yield grandpa | 798 yield grandpa |
989 except InferenceError: | 799 except InferenceError: |
990 # XXX log error ? | 800 # XXX log error ? |
991 continue | 801 continue |
992 | 802 |
993 def local_attr_ancestors(self, name, context=None): | 803 def local_attr_ancestors(self, name, context=None): |
994 """return an iterator on astroid representation of parent classes | 804 """return an iterator on astng representation of parent classes |
995 which have <name> defined in their locals | 805 which have <name> defined in their locals |
996 """ | 806 """ |
997 for astroid in self.ancestors(context=context): | 807 for astng in self.ancestors(context=context): |
998 if name in astroid: | 808 if name in astng: |
999 yield astroid | 809 yield astng |
1000 | 810 |
1001 def instance_attr_ancestors(self, name, context=None): | 811 def instance_attr_ancestors(self, name, context=None): |
1002 """return an iterator on astroid representation of parent classes | 812 """return an iterator on astng representation of parent classes |
1003 which have <name> defined in their instance attribute dictionary | 813 which have <name> defined in their instance attribute dictionary |
1004 """ | 814 """ |
1005 for astroid in self.ancestors(context=context): | 815 for astng in self.ancestors(context=context): |
1006 if name in astroid.instance_attrs: | 816 if name in astng.instance_attrs: |
1007 yield astroid | 817 yield astng |
1008 | 818 |
1009 def has_base(self, node): | 819 def has_base(self, node): |
1010 return node in self.bases | 820 return node in self.bases |
1011 | 821 |
1012 def local_attr(self, name, context=None): | 822 def local_attr(self, name, context=None): |
1013 """return the list of assign node associated to name in this class | 823 """return the list of assign node associated to name in this class |
1014 locals or in its parents | 824 locals or in its parents |
1015 | 825 |
1016 :raises `NotFoundError`: | 826 :raises `NotFoundError`: |
1017 if no attribute with this name has been find in this class or | 827 if no attribute with this name has been find in this class or |
1018 its parent classes | 828 its parent classes |
1019 """ | 829 """ |
1020 try: | 830 try: |
1021 return self.locals[name] | 831 return self.locals[name] |
1022 except KeyError: | 832 except KeyError: |
1023 # get if from the first parent implementing it if any | 833 # get if from the first parent implementing it if any |
1024 for class_node in self.local_attr_ancestors(name, context): | 834 for class_node in self.local_attr_ancestors(name, context): |
1025 return class_node.locals[name] | 835 return class_node.locals[name] |
1026 raise NotFoundError(name) | 836 raise NotFoundError(name) |
1027 local_attr = remove_nodes(local_attr, DelAttr) | 837 local_attr = remove_nodes(local_attr, DelAttr) |
1028 | 838 |
1029 def instance_attr(self, name, context=None): | 839 def instance_attr(self, name, context=None): |
1030 """return the astroid nodes associated to name in this class instance | 840 """return the astng nodes associated to name in this class instance |
1031 attributes dictionary and in its parents | 841 attributes dictionary and in its parents |
1032 | 842 |
1033 :raises `NotFoundError`: | 843 :raises `NotFoundError`: |
1034 if no attribute with this name has been find in this class or | 844 if no attribute with this name has been find in this class or |
1035 its parent classes | 845 its parent classes |
1036 """ | 846 """ |
1037 # Return a copy, so we don't modify self.instance_attrs, | 847 values = self.instance_attrs.get(name, []) |
1038 # which could lead to infinite loop. | |
1039 values = list(self.instance_attrs.get(name, [])) | |
1040 # get all values from parents | 848 # get all values from parents |
1041 for class_node in self.instance_attr_ancestors(name, context): | 849 for class_node in self.instance_attr_ancestors(name, context): |
1042 values += class_node.instance_attrs[name] | 850 values += class_node.instance_attrs[name] |
1043 if not values: | 851 if not values: |
1044 raise NotFoundError(name) | 852 raise NotFoundError(name) |
1045 return values | 853 return values |
1046 instance_attr = remove_nodes(instance_attr, DelAttr) | 854 instance_attr = remove_nodes(instance_attr, DelAttr) |
1047 | 855 |
1048 def instanciate_class(self): | 856 def instanciate_class(self): |
1049 """return Instance of Class node, else return self""" | 857 """return Instance of Class node, else return self""" |
1050 return Instance(self) | 858 return Instance(self) |
1051 | 859 |
1052 def getattr(self, name, context=None): | 860 def getattr(self, name, context=None): |
1053 """this method doesn't look in the instance_attrs dictionary since it's | 861 """this method doesn't look in the instance_attrs dictionary since it's |
1054 done by an Instance proxy at inference time. | 862 done by an Instance proxy at inference time. |
1055 | 863 |
1056 It may return a YES object if the attribute has not been actually | 864 It may return a YES object if the attribute has not been actually |
1057 found but a __getattr__ or __getattribute__ method is defined | 865 found but a __getattr__ or __getattribute__ method is defined |
1058 """ | 866 """ |
1059 values = self.locals.get(name, []) | 867 values = self.locals.get(name, []) |
1060 if name in self.special_attributes: | 868 if name in self.special_attributes: |
1061 if name == '__module__': | 869 if name == '__module__': |
1062 return [cf(self.root().qname())] + values | 870 return [cf(self.root().qname())] + values |
1063 # FIXME: do we really need the actual list of ancestors? | 871 # FIXME : what is expected by passing the list of ancestors to cf: |
1064 # returning [Tuple()] + values don't break any test | 872 # you can just do [cf(tuple())] + values without breaking any test |
1065 # this is ticket http://www.logilab.org/ticket/52785 | 873 # this is ticket http://www.logilab.org/ticket/52785 |
| 874 if name == '__bases__': |
| 875 return [cf(tuple(self.ancestors(recurs=False, context=context)))
] + values |
1066 # XXX need proper meta class handling + MRO implementation | 876 # XXX need proper meta class handling + MRO implementation |
1067 if name == '__bases__' or (name == '__mro__' and self.newstyle): | 877 if name == '__mro__' and self.newstyle: |
1068 node = Tuple() | 878 # XXX mro is read-only but that's not our job to detect that |
1069 node.items = self.ancestors(recurs=True, context=context) | 879 return [cf(tuple(self.ancestors(recurs=True, context=context)))]
+ values |
1070 return [node] + values | |
1071 return std_special_attributes(self, name) | 880 return std_special_attributes(self, name) |
1072 # don't modify the list in self.locals! | 881 # don't modify the list in self.locals! |
1073 values = list(values) | 882 values = list(values) |
1074 for classnode in self.ancestors(recurs=True, context=context): | 883 for classnode in self.ancestors(recurs=True, context=context): |
1075 values += classnode.locals.get(name, []) | 884 values += classnode.locals.get(name, []) |
1076 if not values: | 885 if not values: |
1077 raise NotFoundError(name) | 886 raise NotFoundError(name) |
1078 return values | 887 return values |
1079 | 888 |
1080 def igetattr(self, name, context=None): | 889 def igetattr(self, name, context=None): |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1112 # need to explicitly handle optparse.Values (setattr is not detected) | 921 # need to explicitly handle optparse.Values (setattr is not detected) |
1113 if self.name == 'Values' and self.root().name == 'optparse': | 922 if self.name == 'Values' and self.root().name == 'optparse': |
1114 return True | 923 return True |
1115 try: | 924 try: |
1116 self.getattr('__getattr__', context) | 925 self.getattr('__getattr__', context) |
1117 return True | 926 return True |
1118 except NotFoundError: | 927 except NotFoundError: |
1119 #if self.newstyle: XXX cause an infinite recursion error | 928 #if self.newstyle: XXX cause an infinite recursion error |
1120 try: | 929 try: |
1121 getattribute = self.getattr('__getattribute__', context)[0] | 930 getattribute = self.getattr('__getattribute__', context)[0] |
1122 if getattribute.root().name != BUILTINS: | 931 if getattribute.root().name != BUILTINS_NAME: |
1123 # class has a custom __getattribute__ defined | 932 # class has a custom __getattribute__ defined |
1124 return True | 933 return True |
1125 except NotFoundError: | 934 except NotFoundError: |
1126 pass | 935 pass |
1127 return False | 936 return False |
1128 | 937 |
1129 def methods(self): | 938 def methods(self): |
1130 """return an iterator on all methods defined in the class and | 939 """return an iterator on all methods defined in the class and |
1131 its ancestors | 940 its ancestors |
1132 """ | 941 """ |
1133 done = {} | 942 done = {} |
1134 for astroid in chain(iter((self,)), self.ancestors()): | 943 for astng in chain(iter((self,)), self.ancestors()): |
1135 for meth in astroid.mymethods(): | 944 for meth in astng.mymethods(): |
1136 if meth.name in done: | 945 if meth.name in done: |
1137 continue | 946 continue |
1138 done[meth.name] = None | 947 done[meth.name] = None |
1139 yield meth | 948 yield meth |
1140 | 949 |
1141 def mymethods(self): | 950 def mymethods(self): |
1142 """return an iterator on all methods defined in the class""" | 951 """return an iterator on all methods defined in the class""" |
1143 for member in self.values(): | 952 for member in self.values(): |
1144 if isinstance(member, Function): | 953 if isinstance(member, Function): |
1145 yield member | 954 yield member |
(...skipping 13 matching lines...) Expand all Loading... |
1159 missing = False | 968 missing = False |
1160 for iface in unpack_infer(implements): | 969 for iface in unpack_infer(implements): |
1161 if iface is YES: | 970 if iface is YES: |
1162 missing = True | 971 missing = True |
1163 continue | 972 continue |
1164 if not iface in found and handler_func(iface): | 973 if not iface in found and handler_func(iface): |
1165 found.add(iface) | 974 found.add(iface) |
1166 yield iface | 975 yield iface |
1167 if missing: | 976 if missing: |
1168 raise InferenceError() | 977 raise InferenceError() |
1169 | |
1170 _metaclass = None | |
1171 def _explicit_metaclass(self): | |
1172 """ Return the explicit defined metaclass | |
1173 for the current class. | |
1174 | |
1175 An explicit defined metaclass is defined | |
1176 either by passing the ``metaclass`` keyword argument | |
1177 in the class definition line (Python 3) or (Python 2) by | |
1178 having a ``__metaclass__`` class attribute, or if there are | |
1179 no explicit bases but there is a global ``__metaclass__`` variable. | |
1180 """ | |
1181 if self._metaclass: | |
1182 # Expects this from Py3k TreeRebuilder | |
1183 try: | |
1184 return next(node for node in self._metaclass.infer() | |
1185 if node is not YES) | |
1186 except (InferenceError, StopIteration): | |
1187 return None | |
1188 if sys.version_info >= (3, ): | |
1189 return None | |
1190 | |
1191 if '__metaclass__' in self.locals: | |
1192 assignment = self.locals['__metaclass__'][-1] | |
1193 elif self.bases: | |
1194 return None | |
1195 elif '__metaclass__' in self.root().locals: | |
1196 assignments = [ass for ass in self.root().locals['__metaclass__'] | |
1197 if ass.lineno < self.lineno] | |
1198 if not assignments: | |
1199 return None | |
1200 assignment = assignments[-1] | |
1201 else: | |
1202 return None | |
1203 | |
1204 try: | |
1205 infered = assignment.infer().next() | |
1206 except InferenceError: | |
1207 return | |
1208 if infered is YES: # don't expose this | |
1209 return None | |
1210 return infered | |
1211 | |
1212 def metaclass(self): | |
1213 """ Return the metaclass of this class. | |
1214 | |
1215 If this class does not define explicitly a metaclass, | |
1216 then the first defined metaclass in ancestors will be used | |
1217 instead. | |
1218 """ | |
1219 klass = self._explicit_metaclass() | |
1220 if klass is None: | |
1221 for parent in self.ancestors(): | |
1222 klass = parent.metaclass() | |
1223 if klass is not None: | |
1224 break | |
1225 return klass | |
1226 | |
1227 def _islots(self): | |
1228 """ Return an iterator with the inferred slots. """ | |
1229 if '__slots__' not in self.locals: | |
1230 return | |
1231 for slots in self.igetattr('__slots__'): | |
1232 # check if __slots__ is a valid type | |
1233 for meth in ITER_METHODS: | |
1234 try: | |
1235 slots.getattr(meth) | |
1236 break | |
1237 except NotFoundError: | |
1238 continue | |
1239 else: | |
1240 continue | |
1241 | |
1242 if isinstance(slots, Const): | |
1243 # a string. Ignore the following checks, | |
1244 # but yield the node, only if it has a value | |
1245 if slots.value: | |
1246 yield slots | |
1247 continue | |
1248 if not hasattr(slots, 'itered'): | |
1249 # we can't obtain the values, maybe a .deque? | |
1250 continue | |
1251 | |
1252 if isinstance(slots, Dict): | |
1253 values = [item[0] for item in slots.items] | |
1254 else: | |
1255 values = slots.itered() | |
1256 if values is YES: | |
1257 continue | |
1258 | |
1259 for elt in values: | |
1260 try: | |
1261 for infered in elt.infer(): | |
1262 if infered is YES: | |
1263 continue | |
1264 if (not isinstance(infered, Const) or | |
1265 not isinstance(infered.value, str)): | |
1266 continue | |
1267 if not infered.value: | |
1268 continue | |
1269 yield infered | |
1270 except InferenceError: | |
1271 continue | |
1272 | |
1273 # Cached, because inferring them all the time is expensive | |
1274 @cached | |
1275 def slots(self): | |
1276 """ Return all the slots for this node. """ | |
1277 return list(self._islots()) | |
OLD | NEW |