Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

changeset 6742
7cb30f7f94f6
parent 6645
ad476851d7e0
equal deleted inserted replaced
6735:31e263d49c04 6742:7cb30f7f94f6
11 Implement the central Checker class. 11 Implement the central Checker class.
12 Also, it models the Bindings and Scopes. 12 Also, it models the Bindings and Scopes.
13 """ 13 """
14 import __future__ 14 import __future__
15 import ast 15 import ast
16 import bisect
17 import collections
16 import doctest 18 import doctest
19 import functools
17 import os 20 import os
21 import re
18 import sys 22 import sys
23 import tokenize
24
25 from . import messages
19 26
20 PY2 = sys.version_info < (3, 0) 27 PY2 = sys.version_info < (3, 0)
21 PY34 = sys.version_info < (3, 5) # Python 2.7 to 3.4 28 PY35_PLUS = sys.version_info >= (3, 5) # Python 3.5 and above
29 PY36_PLUS = sys.version_info >= (3, 6) # Python 3.6 and above
30 PY38_PLUS = sys.version_info >= (3, 8)
22 try: 31 try:
23 sys.pypy_version_info 32 sys.pypy_version_info
24 PYPY = True 33 PYPY = True
25 except AttributeError: 34 except AttributeError:
26 PYPY = False 35 PYPY = False
27 36
28 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins')) 37 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins'))
29 38
30 from . import messages 39 if PY2:
31 40 tokenize_tokenize = tokenize.generate_tokens
41 else:
42 tokenize_tokenize = tokenize.tokenize
32 43
33 if PY2: 44 if PY2:
34 def getNodeType(node_class): 45 def getNodeType(node_class):
35 # workaround str.upper() which is locale-dependent 46 # workaround str.upper() which is locale-dependent
36 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__ 47 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__
60 if isinstance(n, ast.If): 71 if isinstance(n, ast.If):
61 return [n.body] 72 return [n.body]
62 if isinstance(n, ast.Try): 73 if isinstance(n, ast.Try):
63 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers] 74 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
64 75
65 if PY34: 76 if PY35_PLUS:
77 FOR_TYPES = (ast.For, ast.AsyncFor)
78 LOOP_TYPES = (ast.While, ast.For, ast.AsyncFor)
79 else:
80 FOR_TYPES = (ast.For,)
66 LOOP_TYPES = (ast.While, ast.For) 81 LOOP_TYPES = (ast.While, ast.For)
67 else: 82
68 LOOP_TYPES = (ast.While, ast.For, ast.AsyncFor) 83 # https://github.com/python/typed_ast/blob/55420396/ast27/Parser/tokenizer.c#L102-L104
84 TYPE_COMMENT_RE = re.compile(r'^#\s*type:\s*')
85 # https://github.com/python/typed_ast/blob/55420396/ast27/Parser/tokenizer.c#L1400
86 TYPE_IGNORE_RE = re.compile(TYPE_COMMENT_RE.pattern + r'ignore\s*(#|$)')
87 # https://github.com/python/typed_ast/blob/55420396/ast27/Grammar/Grammar#L147
88 TYPE_FUNC_RE = re.compile(r'^(\(.*?\))\s*->\s*(.*)$')
69 89
70 90
71 class _FieldsOrder(dict): 91 class _FieldsOrder(dict):
72 """Fix order of AST node fields.""" 92 """Fix order of AST node fields."""
73 93
100 120
101 def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()): 121 def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()):
102 """ 122 """
103 Yield all direct child nodes of *node*, that is, all fields that 123 Yield all direct child nodes of *node*, that is, all fields that
104 are nodes and all items of fields that are lists of nodes. 124 are nodes and all items of fields that are lists of nodes.
125
126 :param node: AST node to be iterated upon
127 :param omit: String or tuple of strings denoting the
128 attributes of the node to be omitted from
129 further parsing
130 :param _fields_order: Order of AST node fields
105 """ 131 """
106 for name in _fields_order[node.__class__]: 132 for name in _fields_order[node.__class__]:
107 if name == omit: 133 if omit and name in omit:
108 continue 134 continue
109 field = getattr(node, name, None) 135 field = getattr(node, name, None)
110 if isinstance(field, ast.AST): 136 if isinstance(field, ast.AST):
111 yield field 137 yield field
112 elif isinstance(field, list): 138 elif isinstance(field, list):
179 """ 205 """
180 A binding that defines a function or a class. 206 A binding that defines a function or a class.
181 """ 207 """
182 208
183 209
210 class Builtin(Definition):
211 """A definition created for all Python builtins."""
212
213 def __init__(self, name):
214 super(Builtin, self).__init__(name, None)
215
216 def __repr__(self):
217 return '<%s object %r at 0x%x>' % (self.__class__.__name__,
218 self.name,
219 id(self))
220
221
184 class UnhandledKeyType(object): 222 class UnhandledKeyType(object):
185 """ 223 """
186 A dictionary key of a type that we cannot or do not check for duplicates. 224 A dictionary key of a type that we cannot or do not check for duplicates.
187 """ 225 """
188 226
196 def __init__(self, item): 234 def __init__(self, item):
197 self.name = item.id 235 self.name = item.id
198 236
199 def __eq__(self, compare): 237 def __eq__(self, compare):
200 return ( 238 return (
201 compare.__class__ == self.__class__ 239 compare.__class__ == self.__class__ and
202 and compare.name == self.name 240 compare.name == self.name
203 ) 241 )
204 242
205 def __hash__(self): 243 def __hash__(self):
206 return hash(self.name) 244 return hash(self.name)
207 245
375 """ 413 """
376 A binding created by an C{__all__} assignment. If the names in the list 414 A binding created by an C{__all__} assignment. If the names in the list
377 can be determined statically, they will be treated as names for export and 415 can be determined statically, they will be treated as names for export and
378 additional checking applied to them. 416 additional checking applied to them.
379 417
380 The only C{__all__} assignment that can be recognized is one which takes 418 The only recognized C{__all__} assignment via list concatenation is in the
381 the value of a literal list containing literal strings. For example:: 419 following format:
382 420
383 __all__ = ["foo", "bar"] 421 __all__ = ['a'] + ['b'] + ['c']
384 422
385 Names which are imported and not otherwise used but appear in the value of 423 Names which are imported and not otherwise used but appear in the value of
386 C{__all__} will not have an unused import warning reported for them. 424 C{__all__} will not have an unused import warning reported for them.
387 """ 425 """
388 426
389 def __init__(self, name, source, scope): 427 def __init__(self, name, source, scope):
390 if '__all__' in scope and isinstance(source, ast.AugAssign): 428 if '__all__' in scope and isinstance(source, ast.AugAssign):
391 self.names = list(scope['__all__'].names) 429 self.names = list(scope['__all__'].names)
392 else: 430 else:
393 self.names = [] 431 self.names = []
394 if isinstance(source.value, (ast.List, ast.Tuple)): 432
395 for node in source.value.elts: 433 def _add_to_names(container):
434 for node in container.elts:
396 if isinstance(node, ast.Str): 435 if isinstance(node, ast.Str):
397 self.names.append(node.s) 436 self.names.append(node.s)
437
438 if isinstance(source.value, (ast.List, ast.Tuple)):
439 _add_to_names(source.value)
440 # If concatenating lists
441 elif isinstance(source.value, ast.BinOp):
442 currentValue = source.value
443 while isinstance(currentValue.right, ast.List):
444 left = currentValue.left
445 right = currentValue.right
446 _add_to_names(right)
447 # If more lists are being added
448 if isinstance(left, ast.BinOp):
449 currentValue = left
450 # If just two lists are being added
451 elif isinstance(left, ast.List):
452 _add_to_names(left)
453 # All lists accounted for - done
454 break
455 # If not list concatenation
456 else:
457 break
398 super(ExportBinding, self).__init__(name, source) 458 super(ExportBinding, self).__init__(name, source)
399 459
400 460
401 class Scope(dict): 461 class Scope(dict):
402 importStarred = False # set to True when import * is found 462 importStarred = False # set to True when import * is found
430 def unusedAssignments(self): 490 def unusedAssignments(self):
431 """ 491 """
432 Return a generator for the assignments which have not been used. 492 Return a generator for the assignments which have not been used.
433 """ 493 """
434 for name, binding in self.items(): 494 for name, binding in self.items():
435 if (not binding.used and name not in self.globals 495 if (not binding.used and
436 and not self.usesLocals 496 name != '_' and # see issue #202
437 and isinstance(binding, Assignment)): 497 name not in self.globals and
498 not self.usesLocals and
499 isinstance(binding, Assignment)):
438 yield name, binding 500 yield name, binding
439 501
440 502
441 class GeneratorScope(Scope): 503 class GeneratorScope(Scope):
442 pass 504 pass
443 505
444 506
445 class ModuleScope(Scope): 507 class ModuleScope(Scope):
446 """Scope for a module.""" 508 """Scope for a module."""
447 _futures_allowed = True 509 _futures_allowed = True
510 _annotations_future_enabled = False
448 511
449 512
450 class DoctestScope(ModuleScope): 513 class DoctestScope(ModuleScope):
451 """Scope for a doctest.""" 514 """Scope for a doctest."""
452 515
453 516
454 # Globally defined names which are not attributes of the builtins module, or 517 # Globally defined names which are not attributes of the builtins module, or
455 # are only present on some platforms. 518 # are only present on some platforms.
456 _MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError'] 519 _MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
520 # module scope annotation will store in `__annotations__`, see also PEP 526.
521 if PY36_PLUS:
522 _MAGIC_GLOBALS.append('__annotations__')
457 523
458 524
459 def getNodeName(node): 525 def getNodeName(node):
460 # Returns node.id, or node.name, or None 526 # Returns node.id, or node.name, or None
461 if hasattr(node, 'id'): # One of the many nodes with an id 527 if hasattr(node, 'id'): # One of the many nodes with an id
462 return node.id 528 return node.id
463 if hasattr(node, 'name'): # an ExceptHandler node 529 if hasattr(node, 'name'): # an ExceptHandler node
464 return node.name 530 return node.name
465 531
466 532
533 def is_typing_overload(value, scope):
534 def is_typing_overload_decorator(node):
535 return (
536 (
537 isinstance(node, ast.Name) and
538 node.id in scope and
539 scope[node.id].fullName == 'typing.overload'
540 ) or (
541 isinstance(node, ast.Attribute) and
542 isinstance(node.value, ast.Name) and
543 node.value.id == 'typing' and
544 node.attr == 'overload'
545 )
546 )
547
548 return (
549 isinstance(value.source, ast.FunctionDef) and
550 len(value.source.decorator_list) == 1 and
551 is_typing_overload_decorator(value.source.decorator_list[0])
552 )
553
554
555 def make_tokens(code):
556 # PY3: tokenize.tokenize requires readline of bytes
557 if not isinstance(code, bytes):
558 code = code.encode('UTF-8')
559 lines = iter(code.splitlines(True))
560 # next(lines, b'') is to prevent an error in pypy3
561 return tuple(tokenize_tokenize(lambda: next(lines, b'')))
562
563
564 class _TypeableVisitor(ast.NodeVisitor):
565 """Collect the line number and nodes which are deemed typeable by
566 PEP 484
567
568 https://www.python.org/dev/peps/pep-0484/#type-comments
569 """
570 def __init__(self):
571 self.typeable_lines = [] # type: List[int]
572 self.typeable_nodes = {} # type: Dict[int, ast.AST]
573
574 def _typeable(self, node):
575 # if there is more than one typeable thing on a line last one wins
576 self.typeable_lines.append(node.lineno)
577 self.typeable_nodes[node.lineno] = node
578
579 self.generic_visit(node)
580
581 visit_Assign = visit_For = visit_FunctionDef = visit_With = _typeable
582 visit_AsyncFor = visit_AsyncFunctionDef = visit_AsyncWith = _typeable
583
584
585 def _collect_type_comments(tree, tokens):
586 visitor = _TypeableVisitor()
587 visitor.visit(tree)
588
589 type_comments = collections.defaultdict(list)
590 for tp, text, start, _, _ in tokens:
591 if (
592 tp != tokenize.COMMENT or # skip non comments
593 not TYPE_COMMENT_RE.match(text) or # skip non-type comments
594 TYPE_IGNORE_RE.match(text) # skip ignores
595 ):
596 continue
597
598 # search for the typeable node at or before the line number of the
599 # type comment.
600 # if the bisection insertion point is before any nodes this is an
601 # invalid type comment which is ignored.
602 lineno, _ = start
603 idx = bisect.bisect_right(visitor.typeable_lines, lineno)
604 if idx == 0:
605 continue
606 node = visitor.typeable_nodes[visitor.typeable_lines[idx - 1]]
607 type_comments[node].append((start, text))
608
609 return type_comments
610
611
467 class Checker(object): 612 class Checker(object):
468 """ 613 """
469 I check the cleanliness and sanity of Python code. 614 I check the cleanliness and sanity of Python code.
470 615
471 @ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements 616 @ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
474 at the time L{deferFunction} was called. 619 at the time L{deferFunction} was called.
475 620
476 @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for 621 @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
477 callables which are deferred assignment checks. 622 callables which are deferred assignment checks.
478 """ 623 """
624
625 _ast_node_scope = {
626 ast.Module: ModuleScope,
627 ast.ClassDef: ClassScope,
628 ast.FunctionDef: FunctionScope,
629 ast.Lambda: FunctionScope,
630 ast.ListComp: GeneratorScope,
631 ast.SetComp: GeneratorScope,
632 ast.GeneratorExp: GeneratorScope,
633 ast.DictComp: GeneratorScope,
634 }
635 if PY35_PLUS:
636 _ast_node_scope[ast.AsyncFunctionDef] = FunctionScope,
479 637
480 nodeDepth = 0 638 nodeDepth = 0
481 offset = None 639 offset = None
482 traceTree = False 640 traceTree = False
483 641
485 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS') 643 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
486 if _customBuiltIns: 644 if _customBuiltIns:
487 builtIns.update(_customBuiltIns.split(',')) 645 builtIns.update(_customBuiltIns.split(','))
488 del _customBuiltIns 646 del _customBuiltIns
489 647
648 # TODO: file_tokens= is required to perform checks on type comments,
649 # eventually make this a required positional argument. For now it
650 # is defaulted to `()` for api compatibility.
490 def __init__(self, tree, filename='(none)', builtins=None, 651 def __init__(self, tree, filename='(none)', builtins=None,
491 withDoctest='PYFLAKES_DOCTEST' in os.environ): 652 withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()):
492 self._nodeHandlers = {} 653 self._nodeHandlers = {}
493 self._deferredFunctions = [] 654 self._deferredFunctions = []
494 self._deferredAssignments = [] 655 self._deferredAssignments = []
495 self.deadScopes = [] 656 self.deadScopes = []
496 self.messages = [] 657 self.messages = []
497 self.filename = filename 658 self.filename = filename
498 if builtins: 659 if builtins:
499 self.builtIns = self.builtIns.union(builtins) 660 self.builtIns = self.builtIns.union(builtins)
500 self.withDoctest = withDoctest 661 self.withDoctest = withDoctest
501 self.scopeStack = [ModuleScope()] 662 try:
663 self.scopeStack = [Checker._ast_node_scope[type(tree)]()]
664 except KeyError:
665 raise RuntimeError('No scope implemented for the node %r' % tree)
502 self.exceptHandlers = [()] 666 self.exceptHandlers = [()]
503 self.root = tree 667 self.root = tree
668 self._type_comments = _collect_type_comments(tree, file_tokens)
669 for builtin in self.builtIns:
670 self.addBinding(None, Builtin(builtin))
504 self.handleChildren(tree) 671 self.handleChildren(tree)
505 self.runDeferred(self._deferredFunctions) 672 self.runDeferred(self._deferredFunctions)
506 # Set _deferredFunctions to None so that deferFunction will fail 673 # Set _deferredFunctions to None so that deferFunction will fail
507 # noisily if called after we've run through the deferred functions. 674 # noisily if called after we've run through the deferred functions.
508 self._deferredFunctions = None 675 self._deferredFunctions = None
558 assert value is False 725 assert value is False
559 if isinstance(self.scope, ModuleScope): 726 if isinstance(self.scope, ModuleScope):
560 self.scope._futures_allowed = False 727 self.scope._futures_allowed = False
561 728
562 @property 729 @property
730 def annotationsFutureEnabled(self):
731 scope = self.scopeStack[0]
732 if not isinstance(scope, ModuleScope):
733 return False
734 return scope._annotations_future_enabled
735
736 @annotationsFutureEnabled.setter
737 def annotationsFutureEnabled(self, value):
738 assert value is True
739 assert isinstance(self.scope, ModuleScope)
740 self.scope._annotations_future_enabled = True
741
742 @property
563 def scope(self): 743 def scope(self):
564 return self.scopeStack[-1] 744 return self.scopeStack[-1]
565 745
566 def popScope(self): 746 def popScope(self):
567 self.deadScopes.append(self.scopeStack.pop()) 747 self.deadScopes.append(self.scopeStack.pop())
594 self.report(messages.UndefinedExport, 774 self.report(messages.UndefinedExport,
595 scope['__all__'].source, name) 775 scope['__all__'].source, name)
596 776
597 # mark all import '*' as used by the undefined in __all__ 777 # mark all import '*' as used by the undefined in __all__
598 if scope.importStarred: 778 if scope.importStarred:
779 from_list = []
599 for binding in scope.values(): 780 for binding in scope.values():
600 if isinstance(binding, StarImportation): 781 if isinstance(binding, StarImportation):
601 binding.used = all_binding 782 binding.used = all_binding
783 from_list.append(binding.fullName)
784 # report * usage, with a list of possible sources
785 from_list = ', '.join(sorted(from_list))
786 for name in undefined:
787 self.report(messages.ImportStarUsage,
788 scope['__all__'].source, name, from_list)
602 789
603 # Look for imported names that aren't used. 790 # Look for imported names that aren't used.
604 for value in scope.values(): 791 for value in scope.values():
605 if isinstance(value, Importation): 792 if isinstance(value, Importation):
606 used = value.used or value.name in all_names 793 used = value.used or value.name in all_names
607 if not used: 794 if not used:
608 messg = messages.UnusedImport 795 messg = messages.UnusedImport
609 self.report(messg, value.source, str(value)) 796 self.report(messg, value.source, str(value))
610 for node in value.redefined: 797 for node in value.redefined:
611 if isinstance(self.getParent(node), ast.For): 798 if isinstance(self.getParent(node), FOR_TYPES):
612 messg = messages.ImportShadowedByLoopVar 799 messg = messages.ImportShadowedByLoopVar
613 elif used: 800 elif used:
614 continue 801 continue
615 else: 802 else:
616 messg = messages.RedefinedWhileUnused 803 messg = messages.RedefinedWhileUnused
645 def descendantOf(self, node, ancestors, stop): 832 def descendantOf(self, node, ancestors, stop):
646 for a in ancestors: 833 for a in ancestors:
647 if self.getCommonAncestor(node, a, stop): 834 if self.getCommonAncestor(node, a, stop):
648 return True 835 return True
649 return False 836 return False
837
838 def _getAncestor(self, node, ancestor_type):
839 parent = node
840 while True:
841 if parent is self.root:
842 return None
843 parent = self.getParent(parent)
844 if isinstance(parent, ancestor_type):
845 return parent
846
847 def getScopeNode(self, node):
848 return self._getAncestor(node, tuple(Checker._ast_node_scope.keys()))
650 849
651 def differentForks(self, lnode, rnode): 850 def differentForks(self, lnode, rnode):
652 """True, if lnode and rnode are located on different forks of IF/TRY""" 851 """True, if lnode and rnode are located on different forks of IF/TRY"""
653 ancestor = self.getCommonAncestor(lnode, rnode, self.root) 852 ancestor = self.getCommonAncestor(lnode, rnode, self.root)
654 parts = getAlternatives(ancestor) 853 parts = getAlternatives(ancestor)
670 for scope in self.scopeStack[::-1]: 869 for scope in self.scopeStack[::-1]:
671 if value.name in scope: 870 if value.name in scope:
672 break 871 break
673 existing = scope.get(value.name) 872 existing = scope.get(value.name)
674 873
675 if existing and not self.differentForks(node, existing.source): 874 if (existing and not isinstance(existing, Builtin) and
875 not self.differentForks(node, existing.source)):
676 876
677 parent_stmt = self.getParent(value.source) 877 parent_stmt = self.getParent(value.source)
678 if isinstance(existing, Importation) and isinstance(parent_stmt, ast.For): 878 if isinstance(existing, Importation) and isinstance(parent_stmt, FOR_TYPES):
679 self.report(messages.ImportShadowedByLoopVar, 879 self.report(messages.ImportShadowedByLoopVar,
680 node, value.name, existing.source) 880 node, value.name, existing.source)
681 881
682 elif scope is self.scope: 882 elif scope is self.scope:
683 if (isinstance(parent_stmt, ast.comprehension) and 883 if (isinstance(parent_stmt, ast.comprehension) and
684 not isinstance(self.getParent(existing.source), 884 not isinstance(self.getParent(existing.source),
685 (ast.For, ast.comprehension))): 885 (FOR_TYPES, ast.comprehension))):
686 self.report(messages.RedefinedInListComp, 886 self.report(messages.RedefinedInListComp,
687 node, value.name, existing.source) 887 node, value.name, existing.source)
688 elif not existing.used and value.redefines(existing): 888 elif not existing.used and value.redefines(existing):
689 if value.name != '_' or isinstance(existing, Importation): 889 if value.name != '_' or isinstance(existing, Importation):
690 self.report(messages.RedefinedWhileUnused, 890 if not is_typing_overload(existing, self.scope):
691 node, value.name, existing.source) 891 self.report(messages.RedefinedWhileUnused,
892 node, value.name, existing.source)
692 893
693 elif isinstance(existing, Importation) and value.redefines(existing): 894 elif isinstance(existing, Importation) and value.redefines(existing):
694 existing.redefined.append(node) 895 existing.redefined.append(node)
695 896
696 if value.name in self.scope: 897 if value.name in self.scope:
724 # only generators used in a class scope can access the 925 # only generators used in a class scope can access the
725 # names of the class. this is skipped during the first 926 # names of the class. this is skipped during the first
726 # iteration 927 # iteration
727 continue 928 continue
728 929
930 if (name == 'print' and
931 isinstance(scope.get(name, None), Builtin)):
932 parent = self.getParent(node)
933 if (isinstance(parent, ast.BinOp) and
934 isinstance(parent.op, ast.RShift)):
935 self.report(messages.InvalidPrintSyntax, node)
936
729 try: 937 try:
730 scope[name].used = (self.scope, node) 938 scope[name].used = (self.scope, node)
939
940 # if the name of SubImportation is same as
941 # alias of other Importation and the alias
942 # is used, SubImportation also should be marked as used.
943 n = scope[name]
944 if isinstance(n, Importation) and n._has_alias():
945 try:
946 scope[n.fullName].used = (self.scope, node)
947 except KeyError:
948 pass
731 except KeyError: 949 except KeyError:
732 pass 950 pass
733 else: 951 else:
734 return 952 return
735 953
736 importStarred = importStarred or scope.importStarred 954 importStarred = importStarred or scope.importStarred
737 955
738 if in_generators is not False: 956 if in_generators is not False:
739 in_generators = isinstance(scope, GeneratorScope) 957 in_generators = isinstance(scope, GeneratorScope)
740
741 # look in the built-ins
742 if name in self.builtIns:
743 return
744 958
745 if importStarred: 959 if importStarred:
746 from_list = [] 960 from_list = []
747 961
748 for scope in self.scopeStack[-1::-1]: 962 for scope in self.scopeStack[-1::-1]:
757 self.report(messages.ImportStarUsage, node, name, from_list) 971 self.report(messages.ImportStarUsage, node, name, from_list)
758 return 972 return
759 973
760 if name == '__path__' and os.path.basename(self.filename) == '__init__.py': 974 if name == '__path__' and os.path.basename(self.filename) == '__init__.py':
761 # the special name __path__ is valid only in packages 975 # the special name __path__ is valid only in packages
976 return
977
978 if name == '__module__' and isinstance(self.scope, ClassScope):
762 return 979 return
763 980
764 # protected with a NameError handler? 981 # protected with a NameError handler?
765 if 'NameError' not in self.exceptHandlers[-1]: 982 if 'NameError' not in self.exceptHandlers[-1]:
766 self.report(messages.UndefinedName, node, name) 983 self.report(messages.UndefinedName, node, name)
784 self.report(messages.UndefinedLocal, 1001 self.report(messages.UndefinedLocal,
785 scope[name].used[1], name, scope[name].source) 1002 scope[name].used[1], name, scope[name].source)
786 break 1003 break
787 1004
788 parent_stmt = self.getParent(node) 1005 parent_stmt = self.getParent(node)
789 if isinstance(parent_stmt, (ast.For, ast.comprehension)) or ( 1006 if isinstance(parent_stmt, (FOR_TYPES, ast.comprehension)) or (
790 parent_stmt != node.parent and 1007 parent_stmt != node.parent and
791 not self.isLiteralTupleUnpacking(parent_stmt)): 1008 not self.isLiteralTupleUnpacking(parent_stmt)):
792 binding = Binding(name, node) 1009 binding = Binding(name, node)
793 elif name == '__all__' and isinstance(self.scope, ModuleScope): 1010 elif name == '__all__' and isinstance(self.scope, ModuleScope):
794 binding = ExportBinding(name, node.parent, self.scope) 1011 binding = ExportBinding(name, node.parent, self.scope)
1012 elif isinstance(getattr(node, 'ctx', None), ast.Param):
1013 binding = Argument(name, self.getScopeNode(node))
795 else: 1014 else:
796 binding = Assignment(name, node) 1015 binding = Assignment(name, node)
797 self.addBinding(node, binding) 1016 self.addBinding(node, binding)
798 1017
799 def handleNodeDelete(self, node): 1018 def handleNodeDelete(self, node):
824 try: 1043 try:
825 del self.scope[name] 1044 del self.scope[name]
826 except KeyError: 1045 except KeyError:
827 self.report(messages.UndefinedName, node, name) 1046 self.report(messages.UndefinedName, node, name)
828 1047
1048 def _handle_type_comments(self, node):
1049 for (lineno, col_offset), comment in self._type_comments.get(node, ()):
1050 comment = comment.split(':', 1)[1].strip()
1051 func_match = TYPE_FUNC_RE.match(comment)
1052 if func_match:
1053 parts = (
1054 func_match.group(1).replace('*', ''),
1055 func_match.group(2).strip(),
1056 )
1057 else:
1058 parts = (comment,)
1059
1060 for part in parts:
1061 if PY2:
1062 part = part.replace('...', 'Ellipsis')
1063 self.deferFunction(functools.partial(
1064 self.handleStringAnnotation,
1065 part, node, lineno, col_offset,
1066 messages.CommentAnnotationSyntaxError,
1067 ))
1068
829 def handleChildren(self, tree, omit=None): 1069 def handleChildren(self, tree, omit=None):
1070 self._handle_type_comments(tree)
830 for node in iter_child_nodes(tree, omit=omit): 1071 for node in iter_child_nodes(tree, omit=omit):
831 self.handleNode(node, tree) 1072 self.handleNode(node, tree)
832 1073
833 def isLiteralTupleUnpacking(self, node): 1074 def isLiteralTupleUnpacking(self, node):
834 if isinstance(node, ast.Assign): 1075 if isinstance(node, ast.Assign):
849 if isinstance(node, ast.Expr): 1090 if isinstance(node, ast.Expr):
850 node = node.value 1091 node = node.value
851 if not isinstance(node, ast.Str): 1092 if not isinstance(node, ast.Str):
852 return (None, None) 1093 return (None, None)
853 1094
854 if PYPY: 1095 if PYPY or PY38_PLUS:
855 doctest_lineno = node.lineno - 1 1096 doctest_lineno = node.lineno - 1
856 else: 1097 else:
857 # Computed incorrectly if the docstring has backslash 1098 # Computed incorrectly if the docstring has backslash
858 doctest_lineno = node.lineno - node.s.count('\n') - 1 1099 doctest_lineno = node.lineno - node.s.count('\n') - 1
859 1100
909 # Place doctest in module scope 1150 # Place doctest in module scope
910 saved_stack = self.scopeStack 1151 saved_stack = self.scopeStack
911 self.scopeStack = [self.scopeStack[0]] 1152 self.scopeStack = [self.scopeStack[0]]
912 node_offset = self.offset or (0, 0) 1153 node_offset = self.offset or (0, 0)
913 self.pushScope(DoctestScope) 1154 self.pushScope(DoctestScope)
914 underscore_in_builtins = '_' in self.builtIns 1155 self.addBinding(None, Builtin('_'))
915 if not underscore_in_builtins:
916 self.builtIns.add('_')
917 for example in examples: 1156 for example in examples:
918 try: 1157 try:
919 tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST) 1158 tree = ast.parse(example.source, "<doctest>")
920 except SyntaxError: 1159 except SyntaxError:
921 e = sys.exc_info()[1] 1160 e = sys.exc_info()[1]
922 if PYPY: 1161 if PYPY:
923 e.offset += 1 1162 e.offset += 1
924 position = (node_lineno + example.lineno + e.lineno, 1163 position = (node_lineno + example.lineno + e.lineno,
927 else: 1166 else:
928 self.offset = (node_offset[0] + node_lineno + example.lineno, 1167 self.offset = (node_offset[0] + node_lineno + example.lineno,
929 node_offset[1] + example.indent + 4) 1168 node_offset[1] + example.indent + 4)
930 self.handleChildren(tree) 1169 self.handleChildren(tree)
931 self.offset = node_offset 1170 self.offset = node_offset
932 if not underscore_in_builtins:
933 self.builtIns.remove('_')
934 self.popScope() 1171 self.popScope()
935 self.scopeStack = saved_stack 1172 self.scopeStack = saved_stack
1173
1174 def handleStringAnnotation(self, s, node, ref_lineno, ref_col_offset, err):
1175 try:
1176 tree = ast.parse(s)
1177 except SyntaxError:
1178 self.report(err, node, s)
1179 return
1180
1181 body = tree.body
1182 if len(body) != 1 or not isinstance(body[0], ast.Expr):
1183 self.report(err, node, s)
1184 return
1185
1186 parsed_annotation = tree.body[0].value
1187 for descendant in ast.walk(parsed_annotation):
1188 if (
1189 'lineno' in descendant._attributes and
1190 'col_offset' in descendant._attributes
1191 ):
1192 descendant.lineno = ref_lineno
1193 descendant.col_offset = ref_col_offset
1194
1195 self.handleNode(parsed_annotation, node)
936 1196
937 def handleAnnotation(self, annotation, node): 1197 def handleAnnotation(self, annotation, node):
938 if isinstance(annotation, ast.Str): 1198 if isinstance(annotation, ast.Str):
939 # Defer handling forward annotation. 1199 # Defer handling forward annotation.
940 def handleForwardAnnotation(): 1200 self.deferFunction(functools.partial(
941 try: 1201 self.handleStringAnnotation,
942 tree = ast.parse(annotation.s) 1202 annotation.s,
943 except SyntaxError: 1203 node,
944 self.report( 1204 annotation.lineno,
945 messages.ForwardAnnotationSyntaxError, 1205 annotation.col_offset,
946 node, 1206 messages.ForwardAnnotationSyntaxError,
947 annotation.s, 1207 ))
948 ) 1208 elif self.annotationsFutureEnabled:
949 return 1209 self.deferFunction(lambda: self.handleNode(annotation, node))
950
951 body = tree.body
952 if len(body) != 1 or not isinstance(body[0], ast.Expr):
953 self.report(
954 messages.ForwardAnnotationSyntaxError,
955 node,
956 annotation.s,
957 )
958 return
959
960 parsed_annotation = tree.body[0].value
961 for descendant in ast.walk(parsed_annotation):
962 ast.copy_location(descendant, annotation)
963
964 self.handleNode(parsed_annotation, node)
965
966 self.deferFunction(handleForwardAnnotation)
967 else: 1210 else:
968 self.handleNode(annotation, node) 1211 self.handleNode(annotation, node)
969 1212
970 def ignore(self, node): 1213 def ignore(self, node):
971 pass 1214 pass
977 1220
978 PASS = ignore 1221 PASS = ignore
979 1222
980 # "expr" type nodes 1223 # "expr" type nodes
981 BOOLOP = BINOP = UNARYOP = IFEXP = SET = \ 1224 BOOLOP = BINOP = UNARYOP = IFEXP = SET = \
982 COMPARE = CALL = REPR = ATTRIBUTE = SUBSCRIPT = \ 1225 CALL = REPR = ATTRIBUTE = SUBSCRIPT = \
983 STARRED = NAMECONSTANT = handleChildren 1226 STARRED = NAMECONSTANT = handleChildren
984 1227
985 NUM = STR = BYTES = ELLIPSIS = ignore 1228 NUM = STR = BYTES = ELLIPSIS = CONSTANT = ignore
986 1229
987 # "slice" type nodes 1230 # "slice" type nodes
988 SLICE = EXTSLICE = INDEX = handleChildren 1231 SLICE = EXTSLICE = INDEX = handleChildren
989 1232
990 # expression contexts are node instances too, though being constants 1233 # expression contexts are node instances too, though being constants
1099 Handle occurrence of Name (which can be a load/store/delete access.) 1342 Handle occurrence of Name (which can be a load/store/delete access.)
1100 """ 1343 """
1101 # Locate the name in locals / function / globals scopes. 1344 # Locate the name in locals / function / globals scopes.
1102 if isinstance(node.ctx, (ast.Load, ast.AugLoad)): 1345 if isinstance(node.ctx, (ast.Load, ast.AugLoad)):
1103 self.handleNodeLoad(node) 1346 self.handleNodeLoad(node)
1104 if (node.id == 'locals' and isinstance(self.scope, FunctionScope) 1347 if (node.id == 'locals' and isinstance(self.scope, FunctionScope) and
1105 and isinstance(node.parent, ast.Call)): 1348 isinstance(node.parent, ast.Call)):
1106 # we are doing locals() call in current scope 1349 # we are doing locals() call in current scope
1107 self.scope.usesLocals = True 1350 self.scope.usesLocals = True
1108 elif isinstance(node.ctx, (ast.Store, ast.AugStore)): 1351 elif isinstance(node.ctx, (ast.Store, ast.AugStore, ast.Param)):
1109 self.handleNodeStore(node) 1352 self.handleNodeStore(node)
1110 elif isinstance(node.ctx, ast.Del): 1353 elif isinstance(node.ctx, ast.Del):
1111 self.handleNodeDelete(node) 1354 self.handleNodeDelete(node)
1112 else: 1355 else:
1113 # must be a Param context -- this only happens for names in function 1356 # Unknown context
1114 # arguments, but these aren't dispatched through here
1115 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,)) 1357 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
1116 1358
1117 def CONTINUE(self, node): 1359 def CONTINUE(self, node):
1118 # Walk the tree up until we see a loop (OK), a function or class 1360 # Walk the tree up until we see a loop (OK), a function or class
1119 # definition (not OK), for 'continue', a finally block (not OK), or 1361 # definition (not OK), for 'continue', a finally block (not OK), or
1225 self.handleNode(default, node) 1467 self.handleNode(default, node)
1226 1468
1227 def runFunction(): 1469 def runFunction():
1228 1470
1229 self.pushScope() 1471 self.pushScope()
1230 for name in args: 1472
1231 self.addBinding(node, Argument(name, node)) 1473 self.handleChildren(node, omit='decorator_list')
1232 if isinstance(node.body, list):
1233 # case for FunctionDefs
1234 for stmt in node.body:
1235 self.handleNode(stmt, node)
1236 else:
1237 # case for Lambdas
1238 self.handleNode(node.body, node)
1239 1474
1240 def checkUnusedAssignments(): 1475 def checkUnusedAssignments():
1241 """ 1476 """
1242 Check to see if any assignments have not been used. 1477 Check to see if any assignments have not been used.
1243 """ 1478 """
1256 self.scope.returnValue) 1491 self.scope.returnValue)
1257 self.deferAssignment(checkReturnWithArgumentInsideGenerator) 1492 self.deferAssignment(checkReturnWithArgumentInsideGenerator)
1258 self.popScope() 1493 self.popScope()
1259 1494
1260 self.deferFunction(runFunction) 1495 self.deferFunction(runFunction)
1496
1497 def ARGUMENTS(self, node):
1498 self.handleChildren(node, omit=('defaults', 'kw_defaults'))
1499 if PY2:
1500 scope_node = self.getScopeNode(node)
1501 if node.vararg:
1502 self.addBinding(node, Argument(node.vararg, scope_node))
1503 if node.kwarg:
1504 self.addBinding(node, Argument(node.kwarg, scope_node))
1505
1506 def ARG(self, node):
1507 self.addBinding(node, Argument(node.arg, self.getScopeNode(node)))
1261 1508
1262 def CLASSDEF(self, node): 1509 def CLASSDEF(self, node):
1263 """ 1510 """
1264 Check names used in a class definition, including its decorators, base 1511 Check names used in a class definition, including its decorators, base
1265 classes, and the body of its definition. Additionally, add its name to 1512 classes, and the body of its definition. Additionally, add its name to
1338 if node.module == '__future__': 1585 if node.module == '__future__':
1339 importation = FutureImportation(name, node, self.scope) 1586 importation = FutureImportation(name, node, self.scope)
1340 if alias.name not in __future__.all_feature_names: 1587 if alias.name not in __future__.all_feature_names:
1341 self.report(messages.FutureFeatureNotDefined, 1588 self.report(messages.FutureFeatureNotDefined,
1342 node, alias.name) 1589 node, alias.name)
1590 if alias.name == 'annotations':
1591 self.annotationsFutureEnabled = True
1343 elif alias.name == '*': 1592 elif alias.name == '*':
1344 # Only Python 2, local import * is a SyntaxWarning 1593 # Only Python 2, local import * is a SyntaxWarning
1345 if not PY2 and not isinstance(self.scope, ModuleScope): 1594 if not PY2 and not isinstance(self.scope, ModuleScope):
1346 self.report(messages.ImportStarNotPermitted, 1595 self.report(messages.ImportStarNotPermitted,
1347 node, module) 1596 node, module)
1391 # simple string, creates a local that is only bound within the scope of 1640 # simple string, creates a local that is only bound within the scope of
1392 # the except: block. As such, temporarily remove the existing binding 1641 # the except: block. As such, temporarily remove the existing binding
1393 # to more accurately determine if the name is used in the except: 1642 # to more accurately determine if the name is used in the except:
1394 # block. 1643 # block.
1395 1644
1396 for scope in self.scopeStack[::-1]: 1645 try:
1397 try: 1646 prev_definition = self.scope.pop(node.name)
1398 binding = scope.pop(node.name) 1647 except KeyError:
1399 except KeyError:
1400 pass
1401 else:
1402 prev_definition = scope, binding
1403 break
1404 else:
1405 prev_definition = None 1648 prev_definition = None
1406 1649
1407 self.handleNodeStore(node) 1650 self.handleNodeStore(node)
1408 self.handleChildren(node) 1651 self.handleChildren(node)
1409 1652
1424 if not binding.used: 1667 if not binding.used:
1425 self.report(messages.UnusedVariable, node, node.name) 1668 self.report(messages.UnusedVariable, node, node.name)
1426 1669
1427 # Restore. 1670 # Restore.
1428 if prev_definition: 1671 if prev_definition:
1429 scope, binding = prev_definition 1672 self.scope[node.name] = prev_definition
1430 scope[node.name] = binding
1431 1673
1432 def ANNASSIGN(self, node): 1674 def ANNASSIGN(self, node):
1433 if node.value: 1675 if node.value:
1434 # Only bind the *targets* if the assignment has a value. 1676 # Only bind the *targets* if the assignment has a value.
1435 # Otherwise it's not really ast.Store and shouldn't silence 1677 # Otherwise it's not really ast.Store and shouldn't silence
1438 self.handleAnnotation(node.annotation, node) 1680 self.handleAnnotation(node.annotation, node)
1439 if node.value: 1681 if node.value:
1440 # If the assignment has value, handle the *value* now. 1682 # If the assignment has value, handle the *value* now.
1441 self.handleNode(node.value, node) 1683 self.handleNode(node.value, node)
1442 1684
1685 def COMPARE(self, node):
1686 literals = (ast.Str, ast.Num)
1687 if not PY2:
1688 literals += (ast.Bytes,)
1689
1690 left = node.left
1691 for op, right in zip(node.ops, node.comparators):
1692 if (isinstance(op, (ast.Is, ast.IsNot)) and
1693 (isinstance(left, literals) or isinstance(right, literals))):
1694 self.report(messages.IsLiteral, node)
1695 left = right
1696
1697 self.handleChildren(node)
1698
1443 1699
1444 # 1700 #
1445 # eflag: noqa = M702 1701 # eflag: noqa = M702

eric ide

mercurial