OLD | NEW |
1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | 1 # copyright 2003-2013 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 # | 3 # |
4 # This file is part of astroid. | 4 # This file is part of astroid. |
5 # | 5 # |
6 # astroid is free software: you can redistribute it and/or modify it | 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 | 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 | 8 # Free Software Foundation, either version 2.1 of the License, or (at your |
9 # option) any later version. | 9 # option) any later version. |
10 # | 10 # |
11 # astroid is distributed in the hope that it will be useful, but | 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 | 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 | 13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License |
14 # for more details. | 14 # for more details. |
15 # | 15 # |
16 # You should have received a copy of the GNU Lesser General Public License along | 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/>. | 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 | 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 | 19 new local scope in the language definition : Module, Class, Function (and |
20 Lambda, GenExpr, DictComp and SetComp to some extent). | 20 Lambda, GenExpr, DictComp and SetComp to some extent). |
21 """ | 21 """ |
22 from __future__ import with_statement | 22 from __future__ import with_statement |
23 | 23 |
24 __doctype__ = "restructuredtext en" | 24 __doctype__ = "restructuredtext en" |
25 | 25 |
26 import sys | 26 import sys |
| 27 import warnings |
27 from itertools import chain | 28 from itertools import chain |
28 try: | 29 try: |
29 from io import BytesIO | 30 from io import BytesIO |
30 except ImportError: | 31 except ImportError: |
31 from cStringIO import StringIO as BytesIO | 32 from cStringIO import StringIO as BytesIO |
32 | 33 |
33 import six | 34 import six |
34 from logilab.common.compat import builtins | 35 from logilab.common.compat import builtins |
35 from logilab.common.decorators import cached, cachedproperty | 36 from logilab.common.decorators import cached, cachedproperty |
36 | 37 |
37 from astroid.exceptions import NotFoundError, \ | 38 from astroid.exceptions import NotFoundError, \ |
38 AstroidBuildingException, InferenceError | 39 AstroidBuildingException, InferenceError, ResolveError |
39 from astroid.node_classes import Const, DelName, DelAttr, \ | 40 from astroid.node_classes import Const, DelName, DelAttr, \ |
40 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ | 41 Dict, From, List, Pass, Raise, Return, Tuple, Yield, YieldFrom, \ |
41 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc | 42 LookupMixIn, const_factory as cf, unpack_infer, Name, CallFunc |
42 from astroid.bases import NodeNG, InferenceContext, Instance,\ | 43 from astroid.bases import NodeNG, InferenceContext, Instance,\ |
43 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, \ | 44 YES, Generator, UnboundMethod, BoundMethod, _infer_stmts, \ |
44 BUILTINS | 45 BUILTINS |
45 from astroid.mixins import FilterStmtsMixin | 46 from astroid.mixins import FilterStmtsMixin |
46 from astroid.bases import Statement | 47 from astroid.bases import Statement |
47 from astroid.manager import AstroidManager | 48 from astroid.manager import AstroidManager |
48 | 49 |
49 ITER_METHODS = ('__iter__', '__getitem__') | 50 ITER_METHODS = ('__iter__', '__getitem__') |
50 PY3K = sys.version_info >= (3, 0) | 51 PY3K = sys.version_info >= (3, 0) |
51 | 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 |
52 | 93 |
53 def remove_nodes(func, cls): | 94 def remove_nodes(func, cls): |
54 def wrapper(*args, **kwargs): | 95 def wrapper(*args, **kwargs): |
55 nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] | 96 nodes = [n for n in func(*args, **kwargs) if not isinstance(n, cls)] |
56 if not nodes: | 97 if not nodes: |
57 raise NotFoundError() | 98 raise NotFoundError() |
58 return nodes | 99 return nodes |
59 return wrapper | 100 return wrapper |
60 | 101 |
61 | 102 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) | 291 scope_attrs = set(('__name__', '__doc__', '__file__', '__path__')) |
251 | 292 |
252 def __init__(self, name, doc, pure_python=True): | 293 def __init__(self, name, doc, pure_python=True): |
253 self.name = name | 294 self.name = name |
254 self.doc = doc | 295 self.doc = doc |
255 self.pure_python = pure_python | 296 self.pure_python = pure_python |
256 self.locals = self.globals = {} | 297 self.locals = self.globals = {} |
257 self.body = [] | 298 self.body = [] |
258 self.future_imports = set() | 299 self.future_imports = set() |
259 | 300 |
260 @cachedproperty | 301 def _get_stream(self): |
261 def file_stream(self): | |
262 if self.file_bytes is not None: | 302 if self.file_bytes is not None: |
263 return BytesIO(self.file_bytes) | 303 return BytesIO(self.file_bytes) |
264 if self.file is not None: | 304 if self.file is not None: |
265 return open(self.file, 'rb') | 305 stream = open(self.file, 'rb') |
| 306 return stream |
266 return None | 307 return None |
267 | 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 |
268 def block_range(self, lineno): | 332 def block_range(self, lineno): |
269 """return block line numbers. | 333 """return block line numbers. |
270 | 334 |
271 start from the beginning whatever the given lineno | 335 start from the beginning whatever the given lineno |
272 """ | 336 """ |
273 return self.fromlineno, self.tolineno | 337 return self.fromlineno, self.tolineno |
274 | 338 |
275 def scope_lookup(self, node, name, offset=0): | 339 def scope_lookup(self, node, name, offset=0): |
276 if name in self.scope_attrs and not name in self.locals: | 340 if name in self.scope_attrs and not name in self.locals: |
277 try: | 341 try: |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 """class representing a ListComp node""" | 562 """class representing a ListComp node""" |
499 def __init__(self): | 563 def __init__(self): |
500 self.locals = {} | 564 self.locals = {} |
501 else: | 565 else: |
502 class ListComp(_ListComp): | 566 class ListComp(_ListComp): |
503 """class representing a ListComp node""" | 567 """class representing a ListComp node""" |
504 | 568 |
505 # Function ################################################################### | 569 # Function ################################################################### |
506 | 570 |
507 def _infer_decorator_callchain(node): | 571 def _infer_decorator_callchain(node): |
508 """ Detect decorator call chaining and see if the | 572 """Detect decorator call chaining and see if the end result is a |
509 end result is a static or a classmethod. | 573 static or a classmethod. |
510 """ | 574 """ |
511 current = node | 575 if not isinstance(node, Function): |
512 while True: | 576 return |
513 if isinstance(current, CallFunc): | 577 if not node.parent: |
514 try: | 578 return |
515 current = next(current.func.infer()) | 579 try: |
516 except InferenceError: | 580 # TODO: We don't handle multiple inference results right now, |
517 return | 581 # because there's no flow to reason when the return |
518 elif isinstance(current, Function): | 582 # is what we are looking for, a static or a class method. |
519 if not current.parent: | 583 result = next(node.infer_call_result(node.parent)) |
520 return | 584 except (StopIteration, InferenceError): |
521 try: | 585 return |
522 # TODO: We don't handle multiple inference results right now, | 586 if isinstance(result, Instance): |
523 # because there's no flow to reason when the return | 587 result = result._proxied |
524 # is what we are looking for, a static or a class method. | 588 if isinstance(result, Class): |
525 result = next(current.infer_call_result(current.parent)) | 589 if result.is_subtype_of('%s.classmethod' % BUILTINS): |
526 if current is result: | 590 return 'classmethod' |
527 # This will lead to an infinite loop, where a decorator | 591 if result.is_subtype_of('%s.staticmethod' % BUILTINS): |
528 # returns itself. | 592 return 'staticmethod' |
529 return | 593 |
530 except (StopIteration, InferenceError): | |
531 return | |
532 if isinstance(result, (Function, CallFunc)): | |
533 current = result | |
534 else: | |
535 if isinstance(result, Instance): | |
536 result = result._proxied | |
537 if isinstance(result, Class): | |
538 if (result.name == 'classmethod' and | |
539 result.root().name == BUILTINS): | |
540 return 'classmethod' | |
541 elif (result.name == 'staticmethod' and | |
542 result.root().name == BUILTINS): | |
543 return 'staticmethod' | |
544 else: | |
545 return | |
546 else: | |
547 # We aren't interested in anything else returned, | |
548 # so go back to the function type inference. | |
549 return | |
550 else: | |
551 return | |
552 | 594 |
553 def _function_type(self): | 595 def _function_type(self): |
554 """ | 596 """ |
555 Function type, possible values are: | 597 Function type, possible values are: |
556 method, function, staticmethod, classmethod. | 598 method, function, staticmethod, classmethod. |
557 """ | 599 """ |
558 # Can't infer that this node is decorated | 600 # Can't infer that this node is decorated |
559 # with a subclass of `classmethod` where `type` is first set, | 601 # with a subclass of `classmethod` where `type` is first set, |
560 # so do it here. | 602 # so do it here. |
561 if self.decorators: | 603 if self.decorators: |
562 for node in self.decorators.nodes: | 604 for node in self.decorators.nodes: |
563 if isinstance(node, CallFunc): | 605 if isinstance(node, CallFunc): |
564 _type = _infer_decorator_callchain(node) | 606 # Handle the following case: |
565 if _type is None: | 607 # @some_decorator(arg1, arg2) |
| 608 # def func(...) |
| 609 # |
| 610 try: |
| 611 current = next(node.func.infer()) |
| 612 except InferenceError: |
566 continue | 613 continue |
567 else: | 614 _type = _infer_decorator_callchain(current) |
| 615 if _type is not None: |
568 return _type | 616 return _type |
569 if not isinstance(node, Name): | 617 |
570 continue | |
571 try: | 618 try: |
572 for infered in node.infer(): | 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 |
573 if not isinstance(infered, Class): | 625 if not isinstance(infered, Class): |
574 continue | 626 continue |
575 for ancestor in infered.ancestors(): | 627 for ancestor in infered.ancestors(): |
576 if isinstance(ancestor, Class): | 628 if not isinstance(ancestor, Class): |
577 if (ancestor.name == 'classmethod' and | 629 continue |
578 ancestor.root().name == BUILTINS): | 630 if ancestor.is_subtype_of('%s.classmethod' % BUILTINS): |
579 return 'classmethod' | 631 return 'classmethod' |
580 elif (ancestor.name == 'staticmethod' and | 632 elif ancestor.is_subtype_of('%s.staticmethod' % BUILTINS
): |
581 ancestor.root().name == BUILTINS): | 633 return 'staticmethod' |
582 return 'staticmethod' | |
583 except InferenceError: | 634 except InferenceError: |
584 pass | 635 pass |
585 return self._type | 636 return self._type |
586 | 637 |
587 | 638 |
588 class Lambda(LocalsDictNodeNG, FilterStmtsMixin): | 639 class Lambda(LocalsDictNodeNG, FilterStmtsMixin): |
589 _astroid_fields = ('args', 'body',) | 640 _astroid_fields = ('args', 'body',) |
590 name = '<lambda>' | 641 name = '<lambda>' |
591 | 642 |
592 # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' | 643 # function's type, 'function' | 'method' | 'staticmethod' | 'classmethod' |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 """infer what a function is returning when called""" | 807 """infer what a function is returning when called""" |
757 if self.is_generator(): | 808 if self.is_generator(): |
758 yield Generator() | 809 yield Generator() |
759 return | 810 return |
760 # This is really a gigantic hack to work around metaclass generators | 811 # This is really a gigantic hack to work around metaclass generators |
761 # that return transient class-generating functions. Pylint's AST structu
re | 812 # that return transient class-generating functions. Pylint's AST structu
re |
762 # cannot handle a base class object that is only used for calling __new_
_, | 813 # cannot handle a base class object that is only used for calling __new_
_, |
763 # but does not contribute to the inheritance structure itself. We inject | 814 # but does not contribute to the inheritance structure itself. We inject |
764 # a fake class into the hierarchy here for several well-known metaclass | 815 # a fake class into the hierarchy here for several well-known metaclass |
765 # generators, and filter it out later. | 816 # generators, and filter it out later. |
766 if (self.name == 'with_metaclass' and | 817 if (self.name == 'with_metaclass' and |
767 len(self.args.args) == 1 and | 818 len(self.args.args) == 1 and |
768 self.args.vararg is not None): | 819 self.args.vararg is not None): |
769 metaclass = next(caller.args[0].infer(context)) | 820 metaclass = next(caller.args[0].infer(context)) |
770 if isinstance(metaclass, Class): | 821 if isinstance(metaclass, Class): |
771 c = Class('temporary_class', None) | 822 c = Class('temporary_class', None) |
772 c.hide = True | 823 c.hide = True |
773 c.parent = self | 824 c.parent = self |
774 c.bases = [next(b.infer(context)) for b in caller.args[1:]] | 825 c.bases = [next(b.infer(context)) for b in caller.args[1:]] |
775 c._metaclass = metaclass | 826 c._metaclass = metaclass |
776 yield c | 827 yield c |
777 return | 828 return |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1321 values = slots.itered() | 1372 values = slots.itered() |
1322 if values is YES: | 1373 if values is YES: |
1323 continue | 1374 continue |
1324 | 1375 |
1325 for elt in values: | 1376 for elt in values: |
1326 try: | 1377 try: |
1327 for infered in elt.infer(): | 1378 for infered in elt.infer(): |
1328 if infered is YES: | 1379 if infered is YES: |
1329 continue | 1380 continue |
1330 if (not isinstance(infered, Const) or | 1381 if (not isinstance(infered, Const) or |
1331 not isinstance(infered.value, str)): | 1382 not isinstance(infered.value, |
| 1383 six.string_types)): |
1332 continue | 1384 continue |
1333 if not infered.value: | 1385 if not infered.value: |
1334 continue | 1386 continue |
1335 yield infered | 1387 yield infered |
1336 except InferenceError: | 1388 except InferenceError: |
1337 continue | 1389 continue |
1338 | 1390 |
1339 # Cached, because inferring them all the time is expensive | 1391 # Cached, because inferring them all the time is expensive |
1340 @cached | 1392 @cached |
1341 def slots(self): | 1393 def slots(self): |
1342 """ Return all the slots for this node. """ | 1394 """Get all the slots for this node. |
1343 return list(self._islots()) | 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 |