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