src/eric7/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py

branch
eric7
changeset 10164
b2fbf59d889f
parent 9653
e67609152c5e
child 10439
21c28b0f9e41
equal deleted inserted replaced
10163:bab2f909e60b 10164:b2fbf59d889f
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 builtins 15 import builtins
16 import ast 16 import ast
17 import collections
17 import contextlib 18 import contextlib
18 import doctest 19 import doctest
19 import functools 20 import functools
20 import os 21 import os
21 import re 22 import re
23 import sys 24 import sys
24 import warnings 25 import warnings
25 26
26 from pyflakes import messages 27 from pyflakes import messages
27 28
28 PY38_PLUS = sys.version_info >= (3, 8)
29 PYPY = hasattr(sys, 'pypy_version_info') 29 PYPY = hasattr(sys, 'pypy_version_info')
30 30
31 builtin_vars = dir(builtins) 31 builtin_vars = dir(builtins)
32 32
33 parse_format_string = string.Formatter().parse 33 parse_format_string = string.Formatter().parse
34 34
35 35
36 def getAlternatives(n): 36 def getAlternatives(n):
37 if isinstance(n, ast.If): 37 if isinstance(n, ast.If):
38 return [n.body] 38 return [n.body]
39 if isinstance(n, ast.Try): 39 elif isinstance(n, ast.Try):
40 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers] 40 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
41 elif sys.version_info >= (3, 10) and isinstance(n, ast.Match):
42 return [mc.body for mc in n.cases]
41 43
42 44
43 FOR_TYPES = (ast.For, ast.AsyncFor) 45 FOR_TYPES = (ast.For, ast.AsyncFor)
44 46
45 if PY38_PLUS: 47
46 def _is_singleton(node): # type: (ast.AST) -> bool 48 def _is_singleton(node): # type: (ast.AST) -> bool
47 return ( 49 return (
48 isinstance(node, ast.Constant) and 50 isinstance(node, ast.Constant) and
49 isinstance(node.value, (bool, type(Ellipsis), type(None))) 51 isinstance(node.value, (bool, type(Ellipsis), type(None)))
50 ) 52 )
51 else:
52 def _is_singleton(node): # type: (ast.AST) -> bool
53 return isinstance(node, (ast.NameConstant, ast.Ellipsis))
54 53
55 54
56 def _is_tuple_constant(node): # type: (ast.AST) -> bool 55 def _is_tuple_constant(node): # type: (ast.AST) -> bool
57 return ( 56 return (
58 isinstance(node, ast.Tuple) and 57 isinstance(node, ast.Tuple) and
59 all(_is_constant(elt) for elt in node.elts) 58 all(_is_constant(elt) for elt in node.elts)
60 ) 59 )
61 60
62 61
63 if PY38_PLUS: 62 def _is_constant(node):
64 def _is_constant(node): 63 return isinstance(node, ast.Constant) or _is_tuple_constant(node)
65 return isinstance(node, ast.Constant) or _is_tuple_constant(node)
66 else:
67 def _is_constant(node):
68 return (
69 isinstance(node, (ast.Str, ast.Num, ast.Bytes)) or
70 _is_singleton(node) or
71 _is_tuple_constant(node)
72 )
73 64
74 65
75 def _is_const_non_singleton(node): # type: (ast.AST) -> bool 66 def _is_const_non_singleton(node): # type: (ast.AST) -> bool
76 return _is_constant(node) and not _is_singleton(node) 67 return _is_constant(node) and not _is_singleton(node)
77 68
214 if isinstance(item, ast.AST): 205 if isinstance(item, ast.AST):
215 yield item 206 yield item
216 207
217 208
218 def convert_to_value(item): 209 def convert_to_value(item):
219 if isinstance(item, ast.Str): 210 if isinstance(item, ast.Constant):
220 return item.s 211 return item.value
221 elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
222 return item.s
223 elif isinstance(item, ast.Tuple): 212 elif isinstance(item, ast.Tuple):
224 return tuple(convert_to_value(i) for i in item.elts) 213 return tuple(convert_to_value(i) for i in item.elts)
225 elif isinstance(item, ast.Num):
226 return item.n
227 elif isinstance(item, ast.Name): 214 elif isinstance(item, ast.Name):
228 result = VariableKey(item=item) 215 return VariableKey(item=item)
229 constants_lookup = {
230 'True': True,
231 'False': False,
232 'None': None,
233 }
234 return constants_lookup.get(
235 result.name,
236 result,
237 )
238 elif isinstance(item, ast.NameConstant):
239 return item.value
240 else: 216 else:
241 return UnhandledKeyType() 217 return UnhandledKeyType()
242 218
243 219
244 def is_notimplemented_name_node(node): 220 def is_notimplemented_name_node(node):
279 255
280 class Definition(Binding): 256 class Definition(Binding):
281 """ 257 """
282 A binding that defines a function or a class. 258 A binding that defines a function or a class.
283 """ 259 """
260 def redefines(self, other):
261 return (
262 super().redefines(other) or
263 (isinstance(other, Assignment) and self.name == other.name)
264 )
284 265
285 266
286 class Builtin(Definition): 267 class Builtin(Definition):
287 """A definition created for all Python builtins.""" 268 """A definition created for all Python builtins."""
288 269
526 else: 507 else:
527 self.names = [] 508 self.names = []
528 509
529 def _add_to_names(container): 510 def _add_to_names(container):
530 for node in container.elts: 511 for node in container.elts:
531 if isinstance(node, ast.Str): 512 if isinstance(node, ast.Constant) and isinstance(node.value, str):
532 self.names.append(node.s) 513 self.names.append(node.value)
533 514
534 if isinstance(source.value, (ast.List, ast.Tuple)): 515 if isinstance(source.value, (ast.List, ast.Tuple)):
535 _add_to_names(source.value) 516 _add_to_names(source.value)
536 # If concatenating lists or tuples 517 # If concatenating lists or tuples
537 elif isinstance(source.value, ast.BinOp): 518 elif isinstance(source.value, ast.BinOp):
601 for name, binding in self.items(): 582 for name, binding in self.items():
602 if not binding.used and isinstance(binding, Annotation): 583 if not binding.used and isinstance(binding, Annotation):
603 yield name, binding 584 yield name, binding
604 585
605 586
587 class TypeScope(Scope):
588 pass
589
590
606 class GeneratorScope(Scope): 591 class GeneratorScope(Scope):
607 pass 592 pass
608 593
609 594
610 class ModuleScope(Scope): 595 class ModuleScope(Scope):
735 return func(self, *args, **kwargs) 720 return func(self, *args, **kwargs)
736 return in_annotation_func 721 return in_annotation_func
737 722
738 723
739 class Checker: 724 class Checker:
740 """ 725 """I check the cleanliness and sanity of Python code."""
741 I check the cleanliness and sanity of Python code.
742
743 @ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
744 of the list are two-tuples. The first element is the callable passed
745 to L{deferFunction}. The second element is a copy of the scope stack
746 at the time L{deferFunction} was called.
747
748 @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
749 callables which are deferred assignment checks.
750 """
751 726
752 _ast_node_scope = { 727 _ast_node_scope = {
753 ast.Module: ModuleScope, 728 ast.Module: ModuleScope,
754 ast.ClassDef: ClassScope, 729 ast.ClassDef: ClassScope,
755 ast.FunctionDef: FunctionScope, 730 ast.FunctionDef: FunctionScope,
762 } 737 }
763 738
764 nodeDepth = 0 739 nodeDepth = 0
765 offset = None 740 offset = None
766 _in_annotation = AnnotationState.NONE 741 _in_annotation = AnnotationState.NONE
767 _in_deferred = False
768 742
769 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS) 743 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
770 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS') 744 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
771 if _customBuiltIns: 745 if _customBuiltIns:
772 builtIns.update(_customBuiltIns.split(',')) 746 builtIns.update(_customBuiltIns.split(','))
773 del _customBuiltIns 747 del _customBuiltIns
774 748
775 def __init__(self, tree, filename='(none)', builtins=None, 749 def __init__(self, tree, filename='(none)', builtins=None,
776 withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()): 750 withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()):
777 self._nodeHandlers = {} 751 self._nodeHandlers = {}
778 self._deferredFunctions = [] 752 self._deferred = collections.deque()
779 self._deferredAssignments = []
780 self.deadScopes = [] 753 self.deadScopes = []
781 self.messages = [] 754 self.messages = []
782 self.filename = filename 755 self.filename = filename
783 if builtins: 756 if builtins:
784 self.builtIns = self.builtIns.union(builtins) 757 self.builtIns = self.builtIns.union(builtins)
785 self.withDoctest = withDoctest 758 self.withDoctest = withDoctest
759 self.exceptHandlers = [()]
760 self.root = tree
761
762 self.scopeStack = []
786 try: 763 try:
787 self.scopeStack = [Checker._ast_node_scope[type(tree)]()] 764 scope_tp = Checker._ast_node_scope[type(tree)]
788 except KeyError: 765 except KeyError:
789 raise RuntimeError('No scope implemented for the node %r' % tree) 766 raise RuntimeError('No scope implemented for the node %r' % tree)
790 self.exceptHandlers = [()] 767
791 self.root = tree 768 with self.in_scope(scope_tp):
792 for builtin in self.builtIns: 769 for builtin in self.builtIns:
793 self.addBinding(None, Builtin(builtin)) 770 self.addBinding(None, Builtin(builtin))
794 self.handleChildren(tree) 771 self.handleChildren(tree)
795 self._in_deferred = True 772 self._run_deferred()
796 self.runDeferred(self._deferredFunctions) 773
797 # Set _deferredFunctions to None so that deferFunction will fail
798 # noisily if called after we've run through the deferred functions.
799 self._deferredFunctions = None
800 self.runDeferred(self._deferredAssignments)
801 # Set _deferredAssignments to None so that deferAssignment will fail
802 # noisily if called after we've run through the deferred assignments.
803 self._deferredAssignments = None
804 del self.scopeStack[1:]
805 self.popScope()
806 self.checkDeadScopes() 774 self.checkDeadScopes()
807 775
808 if file_tokens: 776 if file_tokens:
809 warnings.warn( 777 warnings.warn(
810 '`file_tokens` will be removed in a future version', 778 '`file_tokens` will be removed in a future version',
818 This is used for handling function bodies, which must be deferred 786 This is used for handling function bodies, which must be deferred
819 because code later in the file might modify the global scope. When 787 because code later in the file might modify the global scope. When
820 `callable` is called, the scope at the time this is called will be 788 `callable` is called, the scope at the time this is called will be
821 restored, however it will contain any new bindings added to it. 789 restored, however it will contain any new bindings added to it.
822 """ 790 """
823 self._deferredFunctions.append((callable, self.scopeStack[:], self.offset)) 791 self._deferred.append((callable, self.scopeStack[:], self.offset))
824 792
825 def deferAssignment(self, callable): 793 def _run_deferred(self):
826 """ 794 orig = (self.scopeStack, self.offset)
827 Schedule an assignment handler to be called just after deferred 795
828 function handlers. 796 while self._deferred:
829 """ 797 handler, scope, offset = self._deferred.popleft()
830 self._deferredAssignments.append((callable, self.scopeStack[:], self.offset)) 798 self.scopeStack, self.offset = scope, offset
831
832 def runDeferred(self, deferred):
833 """
834 Run the callables in C{deferred} using their associated scope stack.
835 """
836 for handler, scope, offset in deferred:
837 self.scopeStack = scope
838 self.offset = offset
839 handler() 799 handler()
800
801 self.scopeStack, self.offset = orig
840 802
841 def _in_doctest(self): 803 def _in_doctest(self):
842 return (len(self.scopeStack) >= 2 and 804 return (len(self.scopeStack) >= 2 and
843 isinstance(self.scopeStack[1], DoctestScope)) 805 isinstance(self.scopeStack[1], DoctestScope))
844 806
871 833
872 @property 834 @property
873 def scope(self): 835 def scope(self):
874 return self.scopeStack[-1] 836 return self.scopeStack[-1]
875 837
876 def popScope(self): 838 @contextlib.contextmanager
877 self.deadScopes.append(self.scopeStack.pop()) 839 def in_scope(self, cls):
840 self.scopeStack.append(cls())
841 try:
842 yield
843 finally:
844 self.deadScopes.append(self.scopeStack.pop())
878 845
879 def checkDeadScopes(self): 846 def checkDeadScopes(self):
880 """ 847 """
881 Look at scopes which have been fully examined and report names in them 848 Look at scopes which have been fully examined and report names in them
882 which were imported but unused. 849 which were imported but unused.
883 """ 850 """
884 for scope in self.deadScopes: 851 for scope in self.deadScopes:
885 # imports in classes are public members 852 # imports in classes are public members
886 if isinstance(scope, ClassScope): 853 if isinstance(scope, ClassScope):
887 continue 854 continue
855
856 if isinstance(scope, FunctionScope):
857 for name, binding in scope.unused_assignments():
858 self.report(messages.UnusedVariable, binding.source, name)
859 for name, binding in scope.unused_annotations():
860 self.report(messages.UnusedAnnotation, binding.source, name)
888 861
889 all_binding = scope.get('__all__') 862 all_binding = scope.get('__all__')
890 if all_binding and not isinstance(all_binding, ExportBinding): 863 if all_binding and not isinstance(all_binding, ExportBinding):
891 all_binding = None 864 all_binding = None
892 865
934 continue 907 continue
935 else: 908 else:
936 messg = messages.RedefinedWhileUnused 909 messg = messages.RedefinedWhileUnused
937 self.report(messg, node, value.name, value.source) 910 self.report(messg, node, value.name, value.source)
938 911
939 def pushScope(self, scopeClass=FunctionScope):
940 self.scopeStack.append(scopeClass())
941
942 def report(self, messageClass, *args, **kwargs): 912 def report(self, messageClass, *args, **kwargs):
943 self.messages.append(messageClass(self.filename, *args, **kwargs)) 913 self.messages.append(messageClass(self.filename, *args, **kwargs))
944 914
945 def getParent(self, node): 915 def getParent(self, node):
946 # Lookup the first parent which is not Tuple, List or Starred 916 # Lookup the first parent which is not Tuple, List or Starred
1078 def handleNodeLoad(self, node, parent): 1048 def handleNodeLoad(self, node, parent):
1079 name = getNodeName(node) 1049 name = getNodeName(node)
1080 if not name: 1050 if not name:
1081 return 1051 return
1082 1052
1083 in_generators = None 1053 # only the following can access class scoped variables (since classes
1054 # aren't really a scope)
1055 # - direct accesses (not within a nested scope)
1056 # - generators
1057 # - type annotations (for generics, etc.)
1058 can_access_class_vars = None
1084 importStarred = None 1059 importStarred = None
1085 1060
1086 # try enclosing function scopes and global scope 1061 # try enclosing function scopes and global scope
1087 for scope in self.scopeStack[-1::-1]: 1062 for scope in self.scopeStack[-1::-1]:
1088 if isinstance(scope, ClassScope): 1063 if isinstance(scope, ClassScope):
1089 if name == '__class__': 1064 if name == '__class__':
1090 return 1065 return
1091 elif in_generators is False: 1066 elif can_access_class_vars is False:
1092 # only generators used in a class scope can access the 1067 # only generators used in a class scope can access the
1093 # names of the class. this is skipped during the first 1068 # names of the class. this is skipped during the first
1094 # iteration 1069 # iteration
1095 continue 1070 continue
1096 1071
1097 binding = scope.get(name, None) 1072 binding = scope.get(name, None)
1098 if isinstance(binding, Annotation) and not self._in_postponed_annotation: 1073 if isinstance(binding, Annotation) and not self._in_postponed_annotation:
1099 scope[name].used = True 1074 scope[name].used = (self.scope, node)
1100 continue 1075 continue
1101 1076
1102 if name == 'print' and isinstance(binding, Builtin): 1077 if name == 'print' and isinstance(binding, Builtin):
1103 if (isinstance(parent, ast.BinOp) and 1078 if (isinstance(parent, ast.BinOp) and
1104 isinstance(parent.op, ast.RShift)): 1079 isinstance(parent.op, ast.RShift)):
1121 else: 1096 else:
1122 return 1097 return
1123 1098
1124 importStarred = importStarred or scope.importStarred 1099 importStarred = importStarred or scope.importStarred
1125 1100
1126 if in_generators is not False: 1101 if can_access_class_vars is not False:
1127 in_generators = isinstance(scope, GeneratorScope) 1102 can_access_class_vars = isinstance(
1103 scope, (TypeScope, GeneratorScope),
1104 )
1128 1105
1129 if importStarred: 1106 if importStarred:
1130 from_list = [] 1107 from_list = []
1131 1108
1132 for scope in self.scopeStack[-1::-1]: 1109 for scope in self.scopeStack[-1::-1]:
1186 node._pyflakes_parent, 1163 node._pyflakes_parent,
1187 (ast.Assign, ast.AugAssign, ast.AnnAssign) 1164 (ast.Assign, ast.AugAssign, ast.AnnAssign)
1188 ) 1165 )
1189 ): 1166 ):
1190 binding = ExportBinding(name, node._pyflakes_parent, self.scope) 1167 binding = ExportBinding(name, node._pyflakes_parent, self.scope)
1191 elif PY38_PLUS and isinstance(parent_stmt, ast.NamedExpr): 1168 elif isinstance(parent_stmt, ast.NamedExpr):
1192 binding = NamedExprAssignment(name, node) 1169 binding = NamedExprAssignment(name, node)
1193 else: 1170 else:
1194 binding = Assignment(name, node) 1171 binding = Assignment(name, node)
1195 self.addBinding(node, binding) 1172 self.addBinding(node, binding)
1196 1173
1253 def isDocstring(self, node): 1230 def isDocstring(self, node):
1254 """ 1231 """
1255 Determine if the given node is a docstring, as long as it is at the 1232 Determine if the given node is a docstring, as long as it is at the
1256 correct place in the node tree. 1233 correct place in the node tree.
1257 """ 1234 """
1258 return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and 1235 return (
1259 isinstance(node.value, ast.Str)) 1236 isinstance(node, ast.Expr) and
1237 isinstance(node.value, ast.Constant) and
1238 isinstance(node.value.value, str)
1239 )
1260 1240
1261 def getDocstring(self, node): 1241 def getDocstring(self, node):
1262 if isinstance(node, ast.Expr): 1242 if (
1263 node = node.value 1243 isinstance(node, ast.Expr) and
1264 if not isinstance(node, ast.Str): 1244 isinstance(node.value, ast.Constant) and
1265 return (None, None) 1245 isinstance(node.value.value, str)
1266 1246 ):
1267 if PYPY or PY38_PLUS: 1247 return node.value.value, node.lineno - 1
1268 doctest_lineno = node.lineno - 1
1269 else: 1248 else:
1270 # Computed incorrectly if the docstring has backslash 1249 return None, None
1271 doctest_lineno = node.lineno - node.s.count('\n') - 1
1272
1273 return (node.s, doctest_lineno)
1274 1250
1275 def handleNode(self, node, parent): 1251 def handleNode(self, node, parent):
1276 if node is None: 1252 if node is None:
1277 return 1253 return
1278 if self.offset and getattr(node, 'lineno', None) is not None: 1254 if self.offset and getattr(node, 'lineno', None) is not None:
1279 node.lineno += self.offset[0] 1255 node.lineno += self.offset[0]
1280 node.col_offset += self.offset[1] 1256 node.col_offset += self.offset[1]
1281 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or 1257 if (
1282 self.isDocstring(node)): 1258 self.futuresAllowed and
1259 self.nodeDepth == 0 and
1260 not isinstance(node, ast.ImportFrom) and
1261 not self.isDocstring(node)
1262 ):
1283 self.futuresAllowed = False 1263 self.futuresAllowed = False
1284 self.nodeDepth += 1 1264 self.nodeDepth += 1
1285 node._pyflakes_depth = self.nodeDepth 1265 node._pyflakes_depth = self.nodeDepth
1286 node._pyflakes_parent = parent 1266 node._pyflakes_parent = parent
1287 try: 1267 try:
1305 1285
1306 # Place doctest in module scope 1286 # Place doctest in module scope
1307 saved_stack = self.scopeStack 1287 saved_stack = self.scopeStack
1308 self.scopeStack = [self.scopeStack[0]] 1288 self.scopeStack = [self.scopeStack[0]]
1309 node_offset = self.offset or (0, 0) 1289 node_offset = self.offset or (0, 0)
1310 self.pushScope(DoctestScope) 1290 with self.in_scope(DoctestScope):
1311 if '_' not in self.scopeStack[0]: 1291 if '_' not in self.scopeStack[0]:
1312 self.addBinding(None, Builtin('_')) 1292 self.addBinding(None, Builtin('_'))
1313 for example in examples: 1293 for example in examples:
1314 try: 1294 try:
1315 tree = ast.parse(example.source, "<doctest>") 1295 tree = ast.parse(example.source, "<doctest>")
1316 except SyntaxError as e: 1296 except SyntaxError as e:
1317 position = (node_lineno + example.lineno + e.lineno, 1297 position = (node_lineno + example.lineno + e.lineno,
1318 example.indent + 4 + (e.offset or 0)) 1298 example.indent + 4 + (e.offset or 0))
1319 self.report(messages.DoctestSyntaxError, node, position) 1299 self.report(messages.DoctestSyntaxError, node, position)
1320 else: 1300 else:
1321 self.offset = (node_offset[0] + node_lineno + example.lineno, 1301 self.offset = (node_offset[0] + node_lineno + example.lineno,
1322 node_offset[1] + example.indent + 4) 1302 node_offset[1] + example.indent + 4)
1323 self.handleChildren(tree) 1303 self.handleChildren(tree)
1324 self.offset = node_offset 1304 self.offset = node_offset
1325 self.popScope()
1326 self.scopeStack = saved_stack 1305 self.scopeStack = saved_stack
1327 1306
1328 @in_string_annotation 1307 @in_string_annotation
1329 def handleStringAnnotation(self, s, node, ref_lineno, ref_col_offset, err): 1308 def handleStringAnnotation(self, s, node, ref_lineno, ref_col_offset, err):
1330 try: 1309 try:
1347 descendant.lineno = ref_lineno 1326 descendant.lineno = ref_lineno
1348 descendant.col_offset = ref_col_offset 1327 descendant.col_offset = ref_col_offset
1349 1328
1350 self.handleNode(parsed_annotation, node) 1329 self.handleNode(parsed_annotation, node)
1351 1330
1331 def handle_annotation_always_deferred(self, annotation, parent):
1332 fn = in_annotation(Checker.handleNode)
1333 self.deferFunction(lambda: fn(self, annotation, parent))
1334
1352 @in_annotation 1335 @in_annotation
1353 def handleAnnotation(self, annotation, node): 1336 def handleAnnotation(self, annotation, node):
1354 if isinstance(annotation, ast.Str): 1337 if (
1338 isinstance(annotation, ast.Constant) and
1339 isinstance(annotation.value, str)
1340 ):
1355 # Defer handling forward annotation. 1341 # Defer handling forward annotation.
1356 self.deferFunction(functools.partial( 1342 self.deferFunction(functools.partial(
1357 self.handleStringAnnotation, 1343 self.handleStringAnnotation,
1358 annotation.s, 1344 annotation.value,
1359 node, 1345 node,
1360 annotation.lineno, 1346 annotation.lineno,
1361 annotation.col_offset, 1347 annotation.col_offset,
1362 messages.ForwardAnnotationSyntaxError, 1348 messages.ForwardAnnotationSyntaxError,
1363 )) 1349 ))
1364 elif self.annotationsFutureEnabled: 1350 elif self.annotationsFutureEnabled:
1365 fn = in_annotation(Checker.handleNode) 1351 self.handle_annotation_always_deferred(annotation, node)
1366 self.deferFunction(lambda: fn(self, annotation, node))
1367 else: 1352 else:
1368 self.handleNode(annotation, node) 1353 self.handleNode(annotation, node)
1369 1354
1370 def ignore(self, node): 1355 def ignore(self, node):
1371 pass 1356 pass
1418 else: 1403 else:
1419 self.handleChildren(node) 1404 self.handleChildren(node)
1420 1405
1421 def _handle_string_dot_format(self, node): 1406 def _handle_string_dot_format(self, node):
1422 try: 1407 try:
1423 placeholders = tuple(parse_format_string(node.func.value.s)) 1408 placeholders = tuple(parse_format_string(node.func.value.value))
1424 except ValueError as e: 1409 except ValueError as e:
1425 self.report(messages.StringDotFormatInvalidFormat, node, e) 1410 self.report(messages.StringDotFormatInvalidFormat, node, e)
1426 return 1411 return
1427 1412
1428 auto = None 1413 auto = None
1534 ) 1519 )
1535 1520
1536 def CALL(self, node): 1521 def CALL(self, node):
1537 if ( 1522 if (
1538 isinstance(node.func, ast.Attribute) and 1523 isinstance(node.func, ast.Attribute) and
1539 isinstance(node.func.value, ast.Str) and 1524 isinstance(node.func.value, ast.Constant) and
1525 isinstance(node.func.value.value, str) and
1540 node.func.attr == 'format' 1526 node.func.attr == 'format'
1541 ): 1527 ):
1542 self._handle_string_dot_format(node) 1528 self._handle_string_dot_format(node)
1543 1529
1544 omit = [] 1530 omit = []
1615 else: 1601 else:
1616 self.handleChildren(node) 1602 self.handleChildren(node)
1617 1603
1618 def _handle_percent_format(self, node): 1604 def _handle_percent_format(self, node):
1619 try: 1605 try:
1620 placeholders = parse_percent_format(node.left.s) 1606 placeholders = parse_percent_format(node.left.value)
1621 except ValueError: 1607 except ValueError:
1622 self.report( 1608 self.report(
1623 messages.PercentFormatInvalidFormat, 1609 messages.PercentFormatInvalidFormat,
1624 node, 1610 node,
1625 'incomplete format', 1611 'incomplete format',
1694 elif not positional: 1680 elif not positional:
1695 self.report(messages.PercentFormatExpectedMapping, node) 1681 self.report(messages.PercentFormatExpectedMapping, node)
1696 1682
1697 if ( 1683 if (
1698 isinstance(node.right, ast.Dict) and 1684 isinstance(node.right, ast.Dict) and
1699 all(isinstance(k, ast.Str) for k in node.right.keys) 1685 all(
1686 isinstance(k, ast.Constant) and isinstance(k.value, str)
1687 for k in node.right.keys
1688 )
1700 ): 1689 ):
1701 if positional and positional_count > 1: 1690 if positional and positional_count > 1:
1702 self.report(messages.PercentFormatExpectedSequence, node) 1691 self.report(messages.PercentFormatExpectedSequence, node)
1703 return 1692 return
1704 1693
1705 substitution_keys = {k.s for k in node.right.keys} 1694 substitution_keys = {k.value for k in node.right.keys}
1706 extra_keys = substitution_keys - named 1695 extra_keys = substitution_keys - named
1707 missing_keys = named - substitution_keys 1696 missing_keys = named - substitution_keys
1708 if not positional and extra_keys: 1697 if not positional and extra_keys:
1709 self.report( 1698 self.report(
1710 messages.PercentFormatExtraNamedArguments, 1699 messages.PercentFormatExtraNamedArguments,
1719 ) 1708 )
1720 1709
1721 def BINOP(self, node): 1710 def BINOP(self, node):
1722 if ( 1711 if (
1723 isinstance(node.op, ast.Mod) and 1712 isinstance(node.op, ast.Mod) and
1724 isinstance(node.left, ast.Str) 1713 isinstance(node.left, ast.Constant) and
1714 isinstance(node.left.value, str)
1725 ): 1715 ):
1726 self._handle_percent_format(node) 1716 self._handle_percent_format(node)
1727 self.handleChildren(node) 1717 self.handleChildren(node)
1728 1718
1729 def STR(self, node): 1719 def CONSTANT(self, node):
1730 if self._in_annotation: 1720 if isinstance(node.value, str) and self._in_annotation:
1731 fn = functools.partial( 1721 fn = functools.partial(
1732 self.handleStringAnnotation, 1722 self.handleStringAnnotation,
1733 node.s, 1723 node.value,
1734 node, 1724 node,
1735 node.lineno, 1725 node.lineno,
1736 node.col_offset, 1726 node.col_offset,
1737 messages.ForwardAnnotationSyntaxError, 1727 messages.ForwardAnnotationSyntaxError,
1738 ) 1728 )
1739 if self._in_deferred: 1729 self.deferFunction(fn)
1740 fn()
1741 else:
1742 self.deferFunction(fn)
1743
1744 if PY38_PLUS:
1745 def CONSTANT(self, node):
1746 if isinstance(node.value, str):
1747 return self.STR(node)
1748 else:
1749 NUM = BYTES = ELLIPSIS = CONSTANT = ignore
1750 1730
1751 # "slice" type nodes 1731 # "slice" type nodes
1752 SLICE = EXTSLICE = INDEX = handleChildren 1732 SLICE = EXTSLICE = INDEX = handleChildren
1753 1733
1754 # expression contexts are node instances too, though being constants 1734 # expression contexts are node instances too, though being constants
1872 scope[node_name] = node_value 1852 scope[node_name] = node_value
1873 1853
1874 NONLOCAL = GLOBAL 1854 NONLOCAL = GLOBAL
1875 1855
1876 def GENERATOREXP(self, node): 1856 def GENERATOREXP(self, node):
1877 self.pushScope(GeneratorScope) 1857 with self.in_scope(GeneratorScope):
1878 self.handleChildren(node) 1858 self.handleChildren(node)
1879 self.popScope()
1880 1859
1881 LISTCOMP = DICTCOMP = SETCOMP = GENERATOREXP 1860 LISTCOMP = DICTCOMP = SETCOMP = GENERATOREXP
1882 1861
1883 def NAME(self, node): 1862 def NAME(self, node):
1884 """ 1863 """
1910 # Doesn't apply unless it's in the loop itself 1889 # Doesn't apply unless it's in the loop itself
1911 if n_child not in n.orelse: 1890 if n_child not in n.orelse:
1912 return 1891 return
1913 if isinstance(n, (ast.FunctionDef, ast.ClassDef)): 1892 if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
1914 break 1893 break
1915 # Handle Try/TryFinally difference in Python < and >= 3.3
1916 if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
1917 if n_child in n.finalbody and not PY38_PLUS:
1918 self.report(messages.ContinueInFinally, node)
1919 return
1920 if isinstance(node, ast.Continue): 1894 if isinstance(node, ast.Continue):
1921 self.report(messages.ContinueOutsideLoop, node) 1895 self.report(messages.ContinueOutsideLoop, node)
1922 else: # ast.Break 1896 else: # ast.Break
1923 self.report(messages.BreakOutsideLoop, node) 1897 self.report(messages.BreakOutsideLoop, node)
1924 1898
1947 AWAIT = YIELDFROM = YIELD 1921 AWAIT = YIELDFROM = YIELD
1948 1922
1949 def FUNCTIONDEF(self, node): 1923 def FUNCTIONDEF(self, node):
1950 for deco in node.decorator_list: 1924 for deco in node.decorator_list:
1951 self.handleNode(deco, node) 1925 self.handleNode(deco, node)
1952 self.LAMBDA(node) 1926
1927 with self._type_param_scope(node):
1928 self.LAMBDA(node)
1929
1953 self.addBinding(node, FunctionDefinition(node.name, node)) 1930 self.addBinding(node, FunctionDefinition(node.name, node))
1954 # doctest does not process doctest within a doctest, 1931 # doctest does not process doctest within a doctest,
1955 # or in nested functions. 1932 # or in nested functions.
1956 if (self.withDoctest and 1933 if (self.withDoctest and
1957 not self._in_doctest() and 1934 not self._in_doctest() and
1962 1939
1963 def LAMBDA(self, node): 1940 def LAMBDA(self, node):
1964 args = [] 1941 args = []
1965 annotations = [] 1942 annotations = []
1966 1943
1967 if PY38_PLUS: 1944 for arg in node.args.posonlyargs:
1968 for arg in node.args.posonlyargs: 1945 args.append(arg.arg)
1969 args.append(arg.arg) 1946 annotations.append(arg.annotation)
1970 annotations.append(arg.annotation)
1971 for arg in node.args.args + node.args.kwonlyargs: 1947 for arg in node.args.args + node.args.kwonlyargs:
1972 args.append(arg.arg) 1948 args.append(arg.arg)
1973 annotations.append(arg.annotation) 1949 annotations.append(arg.annotation)
1974 defaults = node.args.defaults + node.args.kw_defaults 1950 defaults = node.args.defaults + node.args.kw_defaults
1975 1951
1996 1972
1997 for default in defaults: 1973 for default in defaults:
1998 self.handleNode(default, node) 1974 self.handleNode(default, node)
1999 1975
2000 def runFunction(): 1976 def runFunction():
2001 1977 with self.in_scope(FunctionScope):
2002 self.pushScope() 1978 self.handleChildren(
2003 1979 node,
2004 self.handleChildren(node, omit=['decorator_list', 'returns']) 1980 omit=('decorator_list', 'returns', 'type_params'),
2005 1981 )
2006 def check_unused_assignments():
2007 """
2008 Check to see if any assignments have not been used.
2009 """
2010 for name, binding in self.scope.unused_assignments():
2011 self.report(messages.UnusedVariable, binding.source, name)
2012
2013 def check_unused_annotations():
2014 """
2015 Check to see if any annotations have not been used.
2016 """
2017 for name, binding in self.scope.unused_annotations():
2018 self.report(messages.UnusedAnnotation, binding.source, name)
2019
2020 self.deferAssignment(check_unused_assignments)
2021 self.deferAssignment(check_unused_annotations)
2022
2023 self.popScope()
2024 1982
2025 self.deferFunction(runFunction) 1983 self.deferFunction(runFunction)
2026 1984
2027 def ARGUMENTS(self, node): 1985 def ARGUMENTS(self, node):
2028 self.handleChildren(node, omit=('defaults', 'kw_defaults')) 1986 self.handleChildren(node, omit=('defaults', 'kw_defaults'))
2036 classes, and the body of its definition. Additionally, add its name to 1994 classes, and the body of its definition. Additionally, add its name to
2037 the current scope. 1995 the current scope.
2038 """ 1996 """
2039 for deco in node.decorator_list: 1997 for deco in node.decorator_list:
2040 self.handleNode(deco, node) 1998 self.handleNode(deco, node)
2041 for baseNode in node.bases: 1999
2042 self.handleNode(baseNode, node) 2000 with self._type_param_scope(node):
2043 for keywordNode in node.keywords: 2001 for baseNode in node.bases:
2044 self.handleNode(keywordNode, node) 2002 self.handleNode(baseNode, node)
2045 self.pushScope(ClassScope) 2003 for keywordNode in node.keywords:
2046 # doctest does not process doctest within a doctest 2004 self.handleNode(keywordNode, node)
2047 # classes within classes are processed. 2005 with self.in_scope(ClassScope):
2048 if (self.withDoctest and 2006 # doctest does not process doctest within a doctest
2049 not self._in_doctest() and 2007 # classes within classes are processed.
2050 not isinstance(self.scope, FunctionScope)): 2008 if (self.withDoctest and
2051 self.deferFunction(lambda: self.handleDoctests(node)) 2009 not self._in_doctest() and
2052 for stmt in node.body: 2010 not isinstance(self.scope, FunctionScope)):
2053 self.handleNode(stmt, node) 2011 self.deferFunction(lambda: self.handleDoctests(node))
2054 self.popScope() 2012 for stmt in node.body:
2013 self.handleNode(stmt, node)
2014
2055 self.addBinding(node, ClassDefinition(node.name, node)) 2015 self.addBinding(node, ClassDefinition(node.name, node))
2056 2016
2057 def AUGASSIGN(self, node): 2017 def AUGASSIGN(self, node):
2058 self.handleNodeLoad(node.target, node) 2018 self.handleNodeLoad(node.target, node)
2059 self.handleNode(node.value, node) 2019 self.handleNode(node.value, node)
2223 def _match_target(self, node): 2183 def _match_target(self, node):
2224 self.handleNodeStore(node) 2184 self.handleNodeStore(node)
2225 self.handleChildren(node) 2185 self.handleChildren(node)
2226 2186
2227 MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target 2187 MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target
2188
2189 @contextlib.contextmanager
2190 def _type_param_scope(self, node):
2191 with contextlib.ExitStack() as ctx:
2192 if sys.version_info >= (3, 12):
2193 ctx.enter_context(self.in_scope(TypeScope))
2194 for param in node.type_params:
2195 self.handleNode(param, node)
2196 yield
2197
2198 def TYPEVAR(self, node):
2199 self.handleNodeStore(node)
2200 self.handle_annotation_always_deferred(node.bound, node)
2201
2202 def TYPEALIAS(self, node):
2203 self.handleNode(node.name, node)
2204 with self._type_param_scope(node):
2205 self.handle_annotation_always_deferred(node.value, node)

eric ide

mercurial