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

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

Issue 876793002: pylint: upgrade to 1.4.1 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/logilab/astroid/rebuilder.py ('k') | third_party/logilab/astroid/test_utils.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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)
OLDNEW
« no previous file with comments | « third_party/logilab/astroid/rebuilder.py ('k') | third_party/logilab/astroid/test_utils.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698