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

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9376
e143a7e7254b
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5 # Original (c) 2005-2010 Divmod, Inc.
6 #
7 # This module is based on pyflakes but was modified to work with eric
8 """
9 Main module.
10
11 Implement the central Checker class.
12 Also, it models the Bindings and Scopes.
13 """
14 import __future__
15 import ast
16 import bisect
17 import collections
18 import contextlib
19 import doctest
20 import functools
21 import os
22 import re
23 import string
24 import sys
25 import tokenize
26
27 from . import messages
28
29 PY2 = sys.version_info < (3, 0)
30 PY35_PLUS = sys.version_info >= (3, 5) # Python 3.5 and above
31 PY36_PLUS = sys.version_info >= (3, 6) # Python 3.6 and above
32 PY38_PLUS = sys.version_info >= (3, 8)
33 try:
34 sys.pypy_version_info
35 PYPY = True
36 except AttributeError:
37 PYPY = False
38
39 builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins'))
40
41 parse_format_string = string.Formatter().parse
42
43 if PY2:
44 tokenize_tokenize = tokenize.generate_tokens
45 else:
46 tokenize_tokenize = tokenize.tokenize
47
48 if PY2:
49 def getNodeType(node_class):
50 # workaround str.upper() which is locale-dependent
51 return str(unicode(node_class.__name__).upper()) # __IGNORE_WARNING__
52
53 def get_raise_argument(node):
54 return node.type
55
56 else:
57 def getNodeType(node_class):
58 return node_class.__name__.upper()
59
60 def get_raise_argument(node):
61 return node.exc
62
63 # Silence `pyflakes` from reporting `undefined name 'unicode'` in Python 3.
64 unicode = str
65
66 # Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
67 if PY2:
68 def getAlternatives(n):
69 if isinstance(n, (ast.If, ast.TryFinally)):
70 return [n.body]
71 if isinstance(n, ast.TryExcept):
72 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
73 else:
74 def getAlternatives(n):
75 if isinstance(n, ast.If):
76 return [n.body]
77 if isinstance(n, ast.Try):
78 return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
79
80 if PY35_PLUS:
81 FOR_TYPES = (ast.For, ast.AsyncFor)
82 LOOP_TYPES = (ast.While, ast.For, ast.AsyncFor)
83 FUNCTION_TYPES = (ast.FunctionDef, ast.AsyncFunctionDef)
84 else:
85 FOR_TYPES = (ast.For,)
86 LOOP_TYPES = (ast.While, ast.For)
87 FUNCTION_TYPES = (ast.FunctionDef,)
88
89 if PY36_PLUS:
90 ANNASSIGN_TYPES = (ast.AnnAssign,)
91 else:
92 ANNASSIGN_TYPES = ()
93
94 if PY38_PLUS:
95 def _is_singleton(node): # type: (ast.AST) -> bool
96 return (
97 isinstance(node, ast.Constant) and
98 isinstance(node.value, (bool, type(Ellipsis), type(None)))
99 )
100 elif not PY2:
101 def _is_singleton(node): # type: (ast.AST) -> bool
102 return isinstance(node, (ast.NameConstant, ast.Ellipsis))
103 else:
104 def _is_singleton(node): # type: (ast.AST) -> bool
105 return (
106 isinstance(node, ast.Name) and
107 node.id in {'True', 'False', 'Ellipsis', 'None'}
108 )
109
110
111 def _is_tuple_constant(node): # type: (ast.AST) -> bool
112 return (
113 isinstance(node, ast.Tuple) and
114 all(_is_constant(elt) for elt in node.elts)
115 )
116
117
118 if PY38_PLUS:
119 def _is_constant(node):
120 return isinstance(node, ast.Constant) or _is_tuple_constant(node)
121 else:
122 _const_tps = (ast.Str, ast.Num)
123 if not PY2:
124 _const_tps += (ast.Bytes,)
125
126 def _is_constant(node):
127 return (
128 isinstance(node, _const_tps) or
129 _is_singleton(node) or
130 _is_tuple_constant(node)
131 )
132
133
134 def _is_const_non_singleton(node): # type: (ast.AST) -> bool
135 return _is_constant(node) and not _is_singleton(node)
136
137
138 def _is_name_or_attr(node, name): # type: (ast.Ast, str) -> bool
139 return (
140 (isinstance(node, ast.Name) and node.id == name) or
141 (isinstance(node, ast.Attribute) and node.attr == name)
142 )
143
144
145 # https://github.com/python/typed_ast/blob/1.4.0/ast27/Parser/tokenizer.c#L102-L104
146 TYPE_COMMENT_RE = re.compile(r'^#\s*type:\s*')
147 # https://github.com/python/typed_ast/blob/1.4.0/ast27/Parser/tokenizer.c#L1408-L1413
148 ASCII_NON_ALNUM = ''.join([chr(i) for i in range(128) if not chr(i).isalnum()])
149 TYPE_IGNORE_RE = re.compile(
150 TYPE_COMMENT_RE.pattern + r'ignore([{}]|$)'.format(ASCII_NON_ALNUM))
151 # https://github.com/python/typed_ast/blob/1.4.0/ast27/Grammar/Grammar#L147
152 TYPE_FUNC_RE = re.compile(r'^(\(.*?\))\s*->\s*(.*)$')
153
154
155 MAPPING_KEY_RE = re.compile(r'\(([^()]*)\)')
156 CONVERSION_FLAG_RE = re.compile('[#0+ -]*')
157 WIDTH_RE = re.compile(r'(?:\*|\d*)')
158 PRECISION_RE = re.compile(r'(?:\.(?:\*|\d*))?')
159 LENGTH_RE = re.compile('[hlL]?')
160 # https://docs.python.org/3/library/stdtypes.html#old-string-formatting
161 VALID_CONVERSIONS = frozenset('diouxXeEfFgGcrsa%')
162
163
164 def _must_match(regex, string, pos):
165 # type: (Pattern[str], str, int) -> Match[str]
166 match = regex.match(string, pos)
167 assert match is not None
168 return match
169
170
171 def parse_percent_format(s): # type: (str) -> Tuple[PercentFormat, ...]
172 """Parses the string component of a `'...' % ...` format call
173
174 Copied from https://github.com/asottile/pyupgrade at v1.20.1
175 """
176
177 def _parse_inner():
178 # type: () -> Generator[PercentFormat, None, None]
179 string_start = 0
180 string_end = 0
181 in_fmt = False
182
183 i = 0
184 while i < len(s):
185 if not in_fmt:
186 try:
187 i = s.index('%', i)
188 except ValueError: # no more % fields!
189 yield s[string_start:], None
190 return
191 else:
192 string_end = i
193 i += 1
194 in_fmt = True
195 else:
196 key_match = MAPPING_KEY_RE.match(s, i)
197 if key_match:
198 key = key_match.group(1) # type: Optional[str]
199 i = key_match.end()
200 else:
201 key = None
202
203 conversion_flag_match = _must_match(CONVERSION_FLAG_RE, s, i)
204 conversion_flag = conversion_flag_match.group() or None
205 i = conversion_flag_match.end()
206
207 width_match = _must_match(WIDTH_RE, s, i)
208 width = width_match.group() or None
209 i = width_match.end()
210
211 precision_match = _must_match(PRECISION_RE, s, i)
212 precision = precision_match.group() or None
213 i = precision_match.end()
214
215 # length modifier is ignored
216 i = _must_match(LENGTH_RE, s, i).end()
217
218 try:
219 conversion = s[i]
220 except IndexError:
221 raise ValueError('end-of-string while parsing format')
222 i += 1
223
224 fmt = (key, conversion_flag, width, precision, conversion)
225 yield s[string_start:string_end], fmt
226
227 in_fmt = False
228 string_start = i
229
230 if in_fmt:
231 raise ValueError('end-of-string while parsing format')
232
233 return tuple(_parse_inner())
234
235
236 class _FieldsOrder(dict):
237 """Fix order of AST node fields."""
238
239 def _get_fields(self, node_class):
240 # handle iter before target, and generators before element
241 fields = node_class._fields
242 if 'iter' in fields:
243 key_first = 'iter'.find
244 elif 'generators' in fields:
245 key_first = 'generators'.find
246 else:
247 key_first = 'value'.find
248 return tuple(sorted(fields, key=key_first, reverse=True))
249
250 def __missing__(self, node_class):
251 self[node_class] = fields = self._get_fields(node_class)
252 return fields
253
254
255 def counter(items):
256 """
257 Simplest required implementation of collections.Counter. Required as 2.6
258 does not have Counter in collections.
259 """
260 results = {}
261 for item in items:
262 results[item] = results.get(item, 0) + 1
263 return results
264
265
266 def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()):
267 """
268 Yield all direct child nodes of *node*, that is, all fields that
269 are nodes and all items of fields that are lists of nodes.
270
271 :param node: AST node to be iterated upon
272 :param omit: String or tuple of strings denoting the
273 attributes of the node to be omitted from
274 further parsing
275 :param _fields_order: Order of AST node fields
276 """
277 for name in _fields_order[node.__class__]:
278 if omit and name in omit:
279 continue
280 field = getattr(node, name, None)
281 if isinstance(field, ast.AST):
282 yield field
283 elif isinstance(field, list):
284 for item in field:
285 if isinstance(item, ast.AST):
286 yield item
287
288
289 def convert_to_value(item):
290 if isinstance(item, ast.Str):
291 return item.s
292 elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
293 return item.s
294 elif isinstance(item, ast.Tuple):
295 return tuple(convert_to_value(i) for i in item.elts)
296 elif isinstance(item, ast.Num):
297 return item.n
298 elif isinstance(item, ast.Name):
299 result = VariableKey(item=item)
300 constants_lookup = {
301 'True': True,
302 'False': False,
303 'None': None,
304 }
305 return constants_lookup.get(
306 result.name,
307 result,
308 )
309 elif (not PY2) and isinstance(item, ast.NameConstant):
310 # None, True, False are nameconstants in python3, but names in 2
311 return item.value
312 else:
313 return UnhandledKeyType()
314
315
316 def is_notimplemented_name_node(node):
317 return isinstance(node, ast.Name) and getNodeName(node) == 'NotImplemented'
318
319
320 class Binding(object):
321 """
322 Represents the binding of a value to a name.
323
324 The checker uses this to keep track of which names have been bound and
325 which names have not. See L{Assignment} for a special type of binding that
326 is checked with stricter rules.
327
328 @ivar used: pair of (L{Scope}, node) indicating the scope and
329 the node that this binding was last used.
330 """
331
332 def __init__(self, name, source):
333 self.name = name
334 self.source = source
335 self.used = False
336
337 def __str__(self):
338 return self.name
339
340 def __repr__(self):
341 return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
342 self.name,
343 self.source.lineno,
344 id(self))
345
346 def redefines(self, other):
347 return isinstance(other, Definition) and self.name == other.name
348
349
350 class Definition(Binding):
351 """
352 A binding that defines a function or a class.
353 """
354
355
356 class Builtin(Definition):
357 """A definition created for all Python builtins."""
358
359 def __init__(self, name):
360 super().__init__(name, None)
361
362 def __repr__(self):
363 return '<%s object %r at 0x%x>' % (self.__class__.__name__,
364 self.name,
365 id(self))
366
367
368 class UnhandledKeyType(object):
369 """
370 A dictionary key of a type that we cannot or do not check for duplicates.
371 """
372
373
374 class VariableKey(object):
375 """
376 A dictionary key which is a variable.
377
378 @ivar item: The variable AST object.
379 """
380 def __init__(self, item):
381 self.name = item.id
382
383 def __eq__(self, compare):
384 return (
385 compare.__class__ == self.__class__ and
386 compare.name == self.name
387 )
388
389 def __hash__(self):
390 return hash(self.name)
391
392
393 class Importation(Definition):
394 """
395 A binding created by an import statement.
396
397 @ivar fullName: The complete name given to the import statement,
398 possibly including multiple dotted components.
399 @type fullName: C{str}
400 """
401
402 def __init__(self, name, source, full_name=None):
403 self.fullName = full_name or name
404 self.redefined = []
405 super().__init__(name, source)
406
407 def redefines(self, other):
408 if isinstance(other, SubmoduleImportation):
409 # See note in SubmoduleImportation about RedefinedWhileUnused
410 return self.fullName == other.fullName
411 return isinstance(other, Definition) and self.name == other.name
412
413 def _has_alias(self):
414 """Return whether importation needs an as clause."""
415 return not self.fullName.split('.')[-1] == self.name
416
417 @property
418 def source_statement(self):
419 """Generate a source statement equivalent to the import."""
420 if self._has_alias():
421 return 'import %s as %s' % (self.fullName, self.name)
422 else:
423 return 'import %s' % self.fullName
424
425 def __str__(self):
426 """Return import full name with alias."""
427 if self._has_alias():
428 return self.fullName + ' as ' + self.name
429 else:
430 return self.fullName
431
432
433 class SubmoduleImportation(Importation):
434 """
435 A binding created by a submodule import statement.
436
437 A submodule import is a special case where the root module is implicitly
438 imported, without an 'as' clause, and the submodule is also imported.
439 Python does not restrict which attributes of the root module may be used.
440
441 This class is only used when the submodule import is without an 'as' clause.
442
443 pyflakes handles this case by registering the root module name in the scope,
444 allowing any attribute of the root module to be accessed.
445
446 RedefinedWhileUnused is suppressed in `redefines` unless the submodule
447 name is also the same, to avoid false positives.
448 """
449
450 def __init__(self, name, source):
451 # A dot should only appear in the name when it is a submodule import
452 assert '.' in name and (not source or isinstance(source, ast.Import))
453 package_name = name.split('.')[0]
454 super().__init__(package_name, source)
455 self.fullName = name
456
457 def redefines(self, other):
458 if isinstance(other, Importation):
459 return self.fullName == other.fullName
460 return super().redefines(other)
461
462 def __str__(self):
463 return self.fullName
464
465 @property
466 def source_statement(self):
467 return 'import ' + self.fullName
468
469
470 class ImportationFrom(Importation):
471
472 def __init__(self, name, source, module, real_name=None):
473 self.module = module
474 self.real_name = real_name or name
475
476 if module.endswith('.'):
477 full_name = module + self.real_name
478 else:
479 full_name = module + '.' + self.real_name
480
481 super().__init__(name, source, full_name)
482
483 def __str__(self):
484 """Return import full name with alias."""
485 if self.real_name != self.name:
486 return self.fullName + ' as ' + self.name
487 else:
488 return self.fullName
489
490 @property
491 def source_statement(self):
492 if self.real_name != self.name:
493 return 'from %s import %s as %s' % (self.module,
494 self.real_name,
495 self.name)
496 else:
497 return 'from %s import %s' % (self.module, self.name)
498
499
500 class StarImportation(Importation):
501 """A binding created by a 'from x import *' statement."""
502
503 def __init__(self, name, source):
504 super().__init__('*', source)
505 # Each star importation needs a unique name, and
506 # may not be the module name otherwise it will be deemed imported
507 self.name = name + '.*'
508 self.fullName = name
509
510 @property
511 def source_statement(self):
512 return 'from ' + self.fullName + ' import *'
513
514 def __str__(self):
515 # When the module ends with a ., avoid the ambiguous '..*'
516 if self.fullName.endswith('.'):
517 return self.source_statement
518 else:
519 return self.name
520
521
522 class FutureImportation(ImportationFrom):
523 """
524 A binding created by a from `__future__` import statement.
525
526 `__future__` imports are implicitly used.
527 """
528
529 def __init__(self, name, source, scope):
530 super().__init__(name, source, '__future__')
531 self.used = (scope, source)
532
533
534 class Argument(Binding):
535 """
536 Represents binding a name as an argument.
537 """
538
539
540 class Assignment(Binding):
541 """
542 Represents binding a name with an explicit assignment.
543
544 The checker will raise warnings for any Assignment that isn't used. Also,
545 the checker does not consider assignments in tuple/list unpacking to be
546 Assignments, rather it treats them as simple Bindings.
547 """
548
549
550 class Annotation(Binding):
551 """
552 Represents binding a name to a type without an associated value.
553
554 As long as this name is not assigned a value in another binding, it is considered
555 undefined for most purposes. One notable exception is using the name as a type
556 annotation.
557 """
558
559 def redefines(self, other):
560 """An Annotation doesn't define any name, so it cannot redefine one."""
561 return False
562
563
564 class FunctionDefinition(Definition):
565 pass
566
567
568 class ClassDefinition(Definition):
569 pass
570
571
572 class ExportBinding(Binding):
573 """
574 A binding created by an C{__all__} assignment. If the names in the list
575 can be determined statically, they will be treated as names for export and
576 additional checking applied to them.
577
578 The only recognized C{__all__} assignment via list/tuple concatenation is in the
579 following format:
580
581 __all__ = ['a'] + ['b'] + ['c']
582
583 Names which are imported and not otherwise used but appear in the value of
584 C{__all__} will not have an unused import warning reported for them.
585 """
586
587 def __init__(self, name, source, scope):
588 if '__all__' in scope and isinstance(source, ast.AugAssign):
589 self.names = list(scope['__all__'].names)
590 else:
591 self.names = []
592
593 def _add_to_names(container):
594 for node in container.elts:
595 if isinstance(node, ast.Str):
596 self.names.append(node.s)
597
598 if isinstance(source.value, (ast.List, ast.Tuple)):
599 _add_to_names(source.value)
600 # If concatenating lists or tuples
601 elif isinstance(source.value, ast.BinOp):
602 currentValue = source.value
603 while isinstance(currentValue.right, (ast.List, ast.Tuple)):
604 left = currentValue.left
605 right = currentValue.right
606 _add_to_names(right)
607 # If more lists are being added
608 if isinstance(left, ast.BinOp):
609 currentValue = left
610 # If just two lists are being added
611 elif isinstance(left, (ast.List, ast.Tuple)):
612 _add_to_names(left)
613 # All lists accounted for - done
614 break
615 # If not list concatenation
616 else:
617 break
618 super().__init__(name, source)
619
620
621 class Scope(dict):
622 importStarred = False # set to True when import * is found
623
624 def __repr__(self):
625 scope_cls = self.__class__.__name__
626 return '<%s at 0x%x %s>' % (scope_cls, id(self), dict.__repr__(self))
627
628
629 class ClassScope(Scope):
630 pass
631
632
633 class FunctionScope(Scope):
634 """
635 I represent a name scope for a function.
636
637 @ivar globals: Names declared 'global' in this function.
638 """
639 usesLocals = False
640 alwaysUsed = {'__tracebackhide__', '__traceback_info__',
641 '__traceback_supplement__'}
642
643 def __init__(self):
644 super().__init__()
645 # Simplify: manage the special locals as globals
646 self.globals = self.alwaysUsed.copy()
647 self.returnValue = None # First non-empty return
648 self.isGenerator = False # Detect a generator
649
650 def unusedAssignments(self):
651 """
652 Return a generator for the assignments which have not been used.
653 """
654 for name, binding in self.items():
655 if (not binding.used and
656 name != '_' and # see issue #202
657 name not in self.globals and
658 not self.usesLocals and
659 isinstance(binding, Assignment)):
660 yield name, binding
661
662
663 class GeneratorScope(Scope):
664 pass
665
666
667 class ModuleScope(Scope):
668 """Scope for a module."""
669 _futures_allowed = True
670 _annotations_future_enabled = False
671
672
673 class DoctestScope(ModuleScope):
674 """Scope for a doctest."""
675
676
677 class DummyNode(object):
678 """Used in place of an `ast.AST` to set error message positions"""
679 def __init__(self, lineno, col_offset):
680 self.lineno = lineno
681 self.col_offset = col_offset
682
683
684 class DetectClassScopedMagic:
685 names = dir()
686
687
688 # Globally defined names which are not attributes of the builtins module, or
689 # are only present on some platforms.
690 _MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
691 # module scope annotation will store in `__annotations__`, see also PEP 526.
692 if PY36_PLUS:
693 _MAGIC_GLOBALS.append('__annotations__')
694
695
696 def getNodeName(node):
697 # Returns node.id, or node.name, or None
698 if hasattr(node, 'id'): # One of the many nodes with an id
699 return node.id
700 if hasattr(node, 'name'): # an ExceptHandler node
701 return node.name
702 if hasattr(node, 'rest'): # a MatchMapping node
703 return node.rest
704
705
706 TYPING_MODULES = frozenset(('typing', 'typing_extensions'))
707
708
709 def _is_typing_helper(node, is_name_match_fn, scope_stack):
710 """
711 Internal helper to determine whether or not something is a member of a
712 typing module. This is used as part of working out whether we are within a
713 type annotation context.
714
715 Note: you probably don't want to use this function directly. Instead see the
716 utils below which wrap it (`_is_typing` and `_is_any_typing_member`).
717 """
718
719 def _bare_name_is_attr(name):
720 for scope in reversed(scope_stack):
721 if name in scope:
722 return (
723 isinstance(scope[name], ImportationFrom) and
724 scope[name].module in TYPING_MODULES and
725 is_name_match_fn(scope[name].real_name)
726 )
727
728 return False
729
730 def _module_scope_is_typing(name):
731 for scope in reversed(scope_stack):
732 if name in scope:
733 return (
734 isinstance(scope[name], Importation) and
735 scope[name].fullName in TYPING_MODULES
736 )
737
738 return False
739
740 return (
741 (
742 isinstance(node, ast.Name) and
743 _bare_name_is_attr(node.id)
744 ) or (
745 isinstance(node, ast.Attribute) and
746 isinstance(node.value, ast.Name) and
747 _module_scope_is_typing(node.value.id) and
748 is_name_match_fn(node.attr)
749 )
750 )
751
752
753 def _is_typing(node, typing_attr, scope_stack):
754 """
755 Determine whether `node` represents the member of a typing module specified
756 by `typing_attr`.
757
758 This is used as part of working out whether we are within a type annotation
759 context.
760 """
761 return _is_typing_helper(node, lambda x: x == typing_attr, scope_stack)
762
763
764 def _is_any_typing_member(node, scope_stack):
765 """
766 Determine whether `node` represents any member of a typing module.
767
768 This is used as part of working out whether we are within a type annotation
769 context.
770 """
771 return _is_typing_helper(node, lambda x: True, scope_stack)
772
773
774 def is_typing_overload(value, scope_stack):
775 return (
776 isinstance(value.source, FUNCTION_TYPES) and
777 any(
778 _is_typing(dec, 'overload', scope_stack)
779 for dec in value.source.decorator_list
780 )
781 )
782
783
784 class AnnotationState:
785 NONE = 0
786 STRING = 1
787 BARE = 2
788
789
790 def in_annotation(func):
791 @functools.wraps(func)
792 def in_annotation_func(self, *args, **kwargs):
793 with self._enter_annotation():
794 return func(self, *args, **kwargs)
795 return in_annotation_func
796
797
798 def in_string_annotation(func):
799 @functools.wraps(func)
800 def in_annotation_func(self, *args, **kwargs):
801 with self._enter_annotation(AnnotationState.STRING):
802 return func(self, *args, **kwargs)
803 return in_annotation_func
804
805
806 def make_tokens(code):
807 # PY3: tokenize.tokenize requires readline of bytes
808 if not isinstance(code, bytes):
809 code = code.encode('UTF-8')
810 lines = iter(code.splitlines(True))
811 # next(lines, b'') is to prevent an error in pypy3
812 return tuple(tokenize_tokenize(lambda: next(lines, b'')))
813
814
815 class _TypeableVisitor(ast.NodeVisitor):
816 """Collect the line number and nodes which are deemed typeable by
817 PEP 484
818
819 https://www.python.org/dev/peps/pep-0484/#type-comments
820 """
821 def __init__(self):
822 self.typeable_lines = [] # type: List[int]
823 self.typeable_nodes = {} # type: Dict[int, ast.AST]
824
825 def _typeable(self, node):
826 # if there is more than one typeable thing on a line last one wins
827 self.typeable_lines.append(node.lineno)
828 self.typeable_nodes[node.lineno] = node
829
830 self.generic_visit(node)
831
832 visit_Assign = visit_For = visit_FunctionDef = visit_With = _typeable
833 visit_AsyncFor = visit_AsyncFunctionDef = visit_AsyncWith = _typeable
834
835
836 def _collect_type_comments(tree, tokens):
837 visitor = _TypeableVisitor()
838 visitor.visit(tree)
839
840 type_comments = collections.defaultdict(list)
841 for tp, text, start, _, _ in tokens:
842 if (
843 tp != tokenize.COMMENT or # skip non comments
844 not TYPE_COMMENT_RE.match(text) or # skip non-type comments
845 TYPE_IGNORE_RE.match(text) # skip ignores
846 ):
847 continue
848
849 # search for the typeable node at or before the line number of the
850 # type comment.
851 # if the bisection insertion point is before any nodes this is an
852 # invalid type comment which is ignored.
853 lineno, _ = start
854 idx = bisect.bisect_right(visitor.typeable_lines, lineno)
855 if idx == 0:
856 continue
857 node = visitor.typeable_nodes[visitor.typeable_lines[idx - 1]]
858 type_comments[node].append((start, text))
859
860 return type_comments
861
862
863 class Checker(object):
864 """
865 I check the cleanliness and sanity of Python code.
866
867 @ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
868 of the list are two-tuples. The first element is the callable passed
869 to L{deferFunction}. The second element is a copy of the scope stack
870 at the time L{deferFunction} was called.
871
872 @ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
873 callables which are deferred assignment checks.
874 """
875
876 _ast_node_scope = {
877 ast.Module: ModuleScope,
878 ast.ClassDef: ClassScope,
879 ast.FunctionDef: FunctionScope,
880 ast.Lambda: FunctionScope,
881 ast.ListComp: GeneratorScope,
882 ast.SetComp: GeneratorScope,
883 ast.GeneratorExp: GeneratorScope,
884 ast.DictComp: GeneratorScope,
885 }
886 if PY35_PLUS:
887 _ast_node_scope[ast.AsyncFunctionDef] = FunctionScope
888
889 nodeDepth = 0
890 offset = None
891 _in_annotation = AnnotationState.NONE
892 _in_deferred = False
893
894 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
895 _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
896 if _customBuiltIns:
897 builtIns.update(_customBuiltIns.split(','))
898 del _customBuiltIns
899
900 # TODO: file_tokens= is required to perform checks on type comments,
901 # eventually make this a required positional argument. For now it
902 # is defaulted to `()` for api compatibility.
903 def __init__(self, tree, filename='(none)', builtins=None,
904 withDoctest='PYFLAKES_DOCTEST' in os.environ, file_tokens=()):
905 self._nodeHandlers = {}
906 self._deferredFunctions = []
907 self._deferredAssignments = []
908 self.deadScopes = []
909 self.messages = []
910 self.filename = filename
911 if builtins:
912 self.builtIns = self.builtIns.union(builtins)
913 self.withDoctest = withDoctest
914 try:
915 self.scopeStack = [Checker._ast_node_scope[type(tree)]()]
916 except KeyError:
917 raise RuntimeError('No scope implemented for the node %r' % tree)
918 self.exceptHandlers = [()]
919 self.root = tree
920 self._type_comments = _collect_type_comments(tree, file_tokens)
921 for builtin in self.builtIns:
922 self.addBinding(None, Builtin(builtin))
923 self.handleChildren(tree)
924 self._in_deferred = True
925 self.runDeferred(self._deferredFunctions)
926 # Set _deferredFunctions to None so that deferFunction will fail
927 # noisily if called after we've run through the deferred functions.
928 self._deferredFunctions = None
929 self.runDeferred(self._deferredAssignments)
930 # Set _deferredAssignments to None so that deferAssignment will fail
931 # noisily if called after we've run through the deferred assignments.
932 self._deferredAssignments = None
933 del self.scopeStack[1:]
934 self.popScope()
935 self.checkDeadScopes()
936
937 def deferFunction(self, callable):
938 """
939 Schedule a function handler to be called just before completion.
940
941 This is used for handling function bodies, which must be deferred
942 because code later in the file might modify the global scope. When
943 `callable` is called, the scope at the time this is called will be
944 restored, however it will contain any new bindings added to it.
945 """
946 self._deferredFunctions.append((callable, self.scopeStack[:], self.offset))
947
948 def deferAssignment(self, callable):
949 """
950 Schedule an assignment handler to be called just after deferred
951 function handlers.
952 """
953 self._deferredAssignments.append((callable, self.scopeStack[:], self.offset))
954
955 def runDeferred(self, deferred):
956 """
957 Run the callables in C{deferred} using their associated scope stack.
958 """
959 for handler, scope, offset in deferred:
960 self.scopeStack = scope
961 self.offset = offset
962 handler()
963
964 def _in_doctest(self):
965 return (len(self.scopeStack) >= 2 and
966 isinstance(self.scopeStack[1], DoctestScope))
967
968 @property
969 def futuresAllowed(self):
970 if not all(isinstance(scope, ModuleScope)
971 for scope in self.scopeStack):
972 return False
973
974 return self.scope._futures_allowed
975
976 @futuresAllowed.setter
977 def futuresAllowed(self, value):
978 assert value is False
979 if isinstance(self.scope, ModuleScope):
980 self.scope._futures_allowed = False
981
982 @property
983 def annotationsFutureEnabled(self):
984 scope = self.scopeStack[0]
985 if not isinstance(scope, ModuleScope):
986 return False
987 return scope._annotations_future_enabled
988
989 @annotationsFutureEnabled.setter
990 def annotationsFutureEnabled(self, value):
991 assert value is True
992 assert isinstance(self.scope, ModuleScope)
993 self.scope._annotations_future_enabled = True
994
995 @property
996 def scope(self):
997 return self.scopeStack[-1]
998
999 def popScope(self):
1000 self.deadScopes.append(self.scopeStack.pop())
1001
1002 def checkDeadScopes(self):
1003 """
1004 Look at scopes which have been fully examined and report names in them
1005 which were imported but unused.
1006 """
1007 for scope in self.deadScopes:
1008 # imports in classes are public members
1009 if isinstance(scope, ClassScope):
1010 continue
1011
1012 all_binding = scope.get('__all__')
1013 if all_binding and not isinstance(all_binding, ExportBinding):
1014 all_binding = None
1015
1016 if all_binding:
1017 all_names = set(all_binding.names)
1018 undefined = [
1019 name for name in all_binding.names
1020 if name not in scope
1021 ]
1022 else:
1023 all_names = undefined = []
1024
1025 if undefined:
1026 if not scope.importStarred and \
1027 os.path.basename(self.filename) != '__init__.py':
1028 # Look for possible mistakes in the export list
1029 for name in undefined:
1030 self.report(messages.UndefinedExport,
1031 scope['__all__'].source, name)
1032
1033 # mark all import '*' as used by the undefined in __all__
1034 if scope.importStarred:
1035 from_list = []
1036 for binding in scope.values():
1037 if isinstance(binding, StarImportation):
1038 binding.used = all_binding
1039 from_list.append(binding.fullName)
1040 # report * usage, with a list of possible sources
1041 from_list = ', '.join(sorted(from_list))
1042 for name in undefined:
1043 self.report(messages.ImportStarUsage,
1044 scope['__all__'].source, name, from_list)
1045
1046 # Look for imported names that aren't used.
1047 for value in scope.values():
1048 if isinstance(value, Importation):
1049 used = value.used or value.name in all_names
1050 if not used:
1051 messg = messages.UnusedImport
1052 self.report(messg, value.source, str(value))
1053 for node in value.redefined:
1054 if isinstance(self.getParent(node), FOR_TYPES):
1055 messg = messages.ImportShadowedByLoopVar
1056 elif used:
1057 continue
1058 else:
1059 messg = messages.RedefinedWhileUnused
1060 self.report(messg, node, value.name, value.source)
1061
1062 def pushScope(self, scopeClass=FunctionScope):
1063 self.scopeStack.append(scopeClass())
1064
1065 def report(self, messageClass, *args, **kwargs):
1066 self.messages.append(messageClass(self.filename, *args, **kwargs))
1067
1068 def getParent(self, node):
1069 # Lookup the first parent which is not Tuple, List or Starred
1070 while True:
1071 node = node._pyflakes_parent
1072 if not hasattr(node, 'elts') and not hasattr(node, 'ctx'):
1073 return node
1074
1075 def getCommonAncestor(self, lnode, rnode, stop):
1076 if (
1077 stop in (lnode, rnode) or
1078 not (
1079 hasattr(lnode, '_pyflakes_parent') and
1080 hasattr(rnode, '_pyflakes_parent')
1081 )
1082 ):
1083 return None
1084 if lnode is rnode:
1085 return lnode
1086
1087 if (lnode._pyflakes_depth > rnode._pyflakes_depth):
1088 return self.getCommonAncestor(lnode._pyflakes_parent, rnode, stop)
1089 if (lnode._pyflakes_depth < rnode._pyflakes_depth):
1090 return self.getCommonAncestor(lnode, rnode._pyflakes_parent, stop)
1091 return self.getCommonAncestor(
1092 lnode._pyflakes_parent,
1093 rnode._pyflakes_parent,
1094 stop,
1095 )
1096
1097 def descendantOf(self, node, ancestors, stop):
1098 for a in ancestors:
1099 if self.getCommonAncestor(node, a, stop):
1100 return True
1101 return False
1102
1103 def _getAncestor(self, node, ancestor_type):
1104 parent = node
1105 while True:
1106 if parent is self.root:
1107 return None
1108 parent = self.getParent(parent)
1109 if isinstance(parent, ancestor_type):
1110 return parent
1111
1112 def getScopeNode(self, node):
1113 return self._getAncestor(node, tuple(Checker._ast_node_scope.keys()))
1114
1115 def differentForks(self, lnode, rnode):
1116 """True, if lnode and rnode are located on different forks of IF/TRY"""
1117 ancestor = self.getCommonAncestor(lnode, rnode, self.root)
1118 parts = getAlternatives(ancestor)
1119 if parts:
1120 for items in parts:
1121 if self.descendantOf(lnode, items, ancestor) ^ \
1122 self.descendantOf(rnode, items, ancestor):
1123 return True
1124 return False
1125
1126 def addBinding(self, node, value):
1127 """
1128 Called when a binding is altered.
1129
1130 - `node` is the statement responsible for the change
1131 - `value` is the new value, a Binding instance
1132 """
1133 # assert value.source in (node, node._pyflakes_parent):
1134 for scope in self.scopeStack[::-1]:
1135 if value.name in scope:
1136 break
1137 existing = scope.get(value.name)
1138
1139 if (existing and not isinstance(existing, Builtin) and
1140 not self.differentForks(node, existing.source)):
1141
1142 parent_stmt = self.getParent(value.source)
1143 if isinstance(existing, Importation) and isinstance(parent_stmt, FOR_TYPES):
1144 self.report(messages.ImportShadowedByLoopVar,
1145 node, value.name, existing.source)
1146
1147 elif scope is self.scope:
1148 if (isinstance(parent_stmt, ast.comprehension) and
1149 not isinstance(self.getParent(existing.source),
1150 (FOR_TYPES, ast.comprehension))):
1151 self.report(messages.RedefinedInListComp,
1152 node, value.name, existing.source)
1153 elif not existing.used and value.redefines(existing):
1154 if value.name != '_' or isinstance(existing, Importation):
1155 if not is_typing_overload(existing, self.scopeStack):
1156 self.report(messages.RedefinedWhileUnused,
1157 node, value.name, existing.source)
1158
1159 elif isinstance(existing, Importation) and value.redefines(existing):
1160 existing.redefined.append(node)
1161
1162 if value.name in self.scope:
1163 # then assume the rebound name is used as a global or within a loop
1164 value.used = self.scope[value.name].used
1165
1166 # don't treat annotations as assignments if there is an existing value
1167 # in scope
1168 if value.name not in self.scope or not isinstance(value, Annotation):
1169 self.scope[value.name] = value
1170
1171 def _unknown_handler(self, node):
1172 # this environment variable configures whether to error on unknown
1173 # ast types.
1174 #
1175 # this is silent by default but the error is enabled for the pyflakes
1176 # testsuite.
1177 #
1178 # this allows new syntax to be added to python without *requiring*
1179 # changes from the pyflakes side. but will still produce an error
1180 # in the pyflakes testsuite (so more specific handling can be added if
1181 # needed).
1182 if os.environ.get('PYFLAKES_ERROR_UNKNOWN'):
1183 raise NotImplementedError('Unexpected type: {}'.format(type(node)))
1184 else:
1185 self.handleChildren(node)
1186
1187 def getNodeHandler(self, node_class):
1188 try:
1189 return self._nodeHandlers[node_class]
1190 except KeyError:
1191 nodeType = getNodeType(node_class)
1192 self._nodeHandlers[node_class] = handler = getattr(
1193 self, nodeType, self._unknown_handler,
1194 )
1195 return handler
1196
1197 def handleNodeLoad(self, node):
1198 name = getNodeName(node)
1199 if not name:
1200 return
1201
1202 in_generators = None
1203 importStarred = None
1204
1205 # try enclosing function scopes and global scope
1206 for scope in self.scopeStack[-1::-1]:
1207 if isinstance(scope, ClassScope):
1208 if not PY2 and name == '__class__':
1209 return
1210 elif in_generators is False:
1211 # only generators used in a class scope can access the
1212 # names of the class. this is skipped during the first
1213 # iteration
1214 continue
1215
1216 binding = scope.get(name, None)
1217 if isinstance(binding, Annotation) and not self._in_postponed_annotation:
1218 continue
1219
1220 if name == 'print' and isinstance(binding, Builtin):
1221 parent = self.getParent(node)
1222 if (isinstance(parent, ast.BinOp) and
1223 isinstance(parent.op, ast.RShift)):
1224 self.report(messages.InvalidPrintSyntax, node)
1225
1226 try:
1227 scope[name].used = (self.scope, node)
1228
1229 # if the name of SubImportation is same as
1230 # alias of other Importation and the alias
1231 # is used, SubImportation also should be marked as used.
1232 n = scope[name]
1233 if isinstance(n, Importation) and n._has_alias():
1234 try:
1235 scope[n.fullName].used = (self.scope, node)
1236 except KeyError:
1237 pass
1238 except KeyError:
1239 pass
1240 else:
1241 return
1242
1243 importStarred = importStarred or scope.importStarred
1244
1245 if in_generators is not False:
1246 in_generators = isinstance(scope, GeneratorScope)
1247
1248 if importStarred:
1249 from_list = []
1250
1251 for scope in self.scopeStack[-1::-1]:
1252 for binding in scope.values():
1253 if isinstance(binding, StarImportation):
1254 # mark '*' imports as used for each scope
1255 binding.used = (self.scope, node)
1256 from_list.append(binding.fullName)
1257
1258 # report * usage, with a list of possible sources
1259 from_list = ', '.join(sorted(from_list))
1260 self.report(messages.ImportStarUsage, node, name, from_list)
1261 return
1262
1263 if name == '__path__' and os.path.basename(self.filename) == '__init__.py':
1264 # the special name __path__ is valid only in packages
1265 return
1266
1267 if name in DetectClassScopedMagic.names and isinstance(self.scope, ClassScope):
1268 return
1269
1270 # protected with a NameError handler?
1271 if 'NameError' not in self.exceptHandlers[-1]:
1272 self.report(messages.UndefinedName, node, name)
1273
1274 def handleNodeStore(self, node):
1275 name = getNodeName(node)
1276 if not name:
1277 return
1278 # if the name hasn't already been defined in the current scope
1279 if isinstance(self.scope, FunctionScope) and name not in self.scope:
1280 # for each function or module scope above us
1281 for scope in self.scopeStack[:-1]:
1282 if not isinstance(scope, (FunctionScope, ModuleScope)):
1283 continue
1284 # if the name was defined in that scope, and the name has
1285 # been accessed already in the current scope, and hasn't
1286 # been declared global
1287 used = name in scope and scope[name].used
1288 if used and used[0] is self.scope and name not in self.scope.globals:
1289 # then it's probably a mistake
1290 self.report(messages.UndefinedLocal,
1291 scope[name].used[1], name, scope[name].source)
1292 break
1293
1294 parent_stmt = self.getParent(node)
1295 if isinstance(parent_stmt, ANNASSIGN_TYPES) and parent_stmt.value is None:
1296 binding = Annotation(name, node)
1297 elif isinstance(parent_stmt, (FOR_TYPES, ast.comprehension)) or (
1298 parent_stmt != node._pyflakes_parent and
1299 not self.isLiteralTupleUnpacking(parent_stmt)):
1300 binding = Binding(name, node)
1301 elif name == '__all__' and isinstance(self.scope, ModuleScope):
1302 binding = ExportBinding(name, node._pyflakes_parent, self.scope)
1303 elif PY2 and isinstance(getattr(node, 'ctx', None), ast.Param):
1304 binding = Argument(name, self.getScopeNode(node))
1305 else:
1306 binding = Assignment(name, node)
1307 self.addBinding(node, binding)
1308
1309 def handleNodeDelete(self, node):
1310
1311 def on_conditional_branch():
1312 """
1313 Return `True` if node is part of a conditional body.
1314 """
1315 current = getattr(node, '_pyflakes_parent', None)
1316 while current:
1317 if isinstance(current, (ast.If, ast.While, ast.IfExp)):
1318 return True
1319 current = getattr(current, '_pyflakes_parent', None)
1320 return False
1321
1322 name = getNodeName(node)
1323 if not name:
1324 return
1325
1326 if on_conditional_branch():
1327 # We cannot predict if this conditional branch is going to
1328 # be executed.
1329 return
1330
1331 if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
1332 self.scope.globals.remove(name)
1333 else:
1334 try:
1335 del self.scope[name]
1336 except KeyError:
1337 self.report(messages.UndefinedName, node, name)
1338
1339 @contextlib.contextmanager
1340 def _enter_annotation(self, ann_type=AnnotationState.BARE):
1341 orig, self._in_annotation = self._in_annotation, ann_type
1342 try:
1343 yield
1344 finally:
1345 self._in_annotation = orig
1346
1347 @property
1348 def _in_postponed_annotation(self):
1349 return (
1350 self._in_annotation == AnnotationState.STRING or
1351 self.annotationsFutureEnabled
1352 )
1353
1354 def _handle_type_comments(self, node):
1355 for (lineno, col_offset), comment in self._type_comments.get(node, ()):
1356 comment = comment.split(':', 1)[1].strip()
1357 func_match = TYPE_FUNC_RE.match(comment)
1358 if func_match:
1359 parts = (
1360 func_match.group(1).replace('*', ''),
1361 func_match.group(2).strip(),
1362 )
1363 else:
1364 parts = (comment,)
1365
1366 for part in parts:
1367 if PY2:
1368 part = part.replace('...', 'Ellipsis')
1369 self.deferFunction(functools.partial(
1370 self.handleStringAnnotation,
1371 part, DummyNode(lineno, col_offset), lineno, col_offset,
1372 messages.CommentAnnotationSyntaxError,
1373 ))
1374
1375 def handleChildren(self, tree, omit=None):
1376 self._handle_type_comments(tree)
1377 for node in iter_child_nodes(tree, omit=omit):
1378 self.handleNode(node, tree)
1379
1380 def isLiteralTupleUnpacking(self, node):
1381 if isinstance(node, ast.Assign):
1382 for child in node.targets + [node.value]:
1383 if not hasattr(child, 'elts'):
1384 return False
1385 return True
1386
1387 def isDocstring(self, node):
1388 """
1389 Determine if the given node is a docstring, as long as it is at the
1390 correct place in the node tree.
1391 """
1392 return isinstance(node, ast.Str) or (isinstance(node, ast.Expr) and
1393 isinstance(node.value, ast.Str))
1394
1395 def getDocstring(self, node):
1396 if isinstance(node, ast.Expr):
1397 node = node.value
1398 if not isinstance(node, ast.Str):
1399 return (None, None)
1400
1401 if PYPY or PY38_PLUS:
1402 doctest_lineno = node.lineno - 1
1403 else:
1404 # Computed incorrectly if the docstring has backslash
1405 doctest_lineno = node.lineno - node.s.count('\n') - 1
1406
1407 return (node.s, doctest_lineno)
1408
1409 def handleNode(self, node, parent):
1410 if node is None:
1411 return
1412 if self.offset and getattr(node, 'lineno', None) is not None:
1413 node.lineno += self.offset[0]
1414 node.col_offset += self.offset[1]
1415 if self.futuresAllowed and not (isinstance(node, ast.ImportFrom) or
1416 self.isDocstring(node)):
1417 self.futuresAllowed = False
1418 self.nodeDepth += 1
1419 node._pyflakes_depth = self.nodeDepth
1420 node._pyflakes_parent = parent
1421 try:
1422 handler = self.getNodeHandler(node.__class__)
1423 handler(node)
1424 finally:
1425 self.nodeDepth -= 1
1426
1427 _getDoctestExamples = doctest.DocTestParser().get_examples
1428
1429 def handleDoctests(self, node):
1430 try:
1431 if hasattr(node, 'docstring'):
1432 docstring = node.docstring
1433
1434 # This is just a reasonable guess. In Python 3.7, docstrings no
1435 # longer have line numbers associated with them. This will be
1436 # incorrect if there are empty lines between the beginning
1437 # of the function and the docstring.
1438 node_lineno = node.lineno
1439 if hasattr(node, 'args'):
1440 node_lineno = max([node_lineno] +
1441 [arg.lineno for arg in node.args.args])
1442 else:
1443 (docstring, node_lineno) = self.getDocstring(node.body[0])
1444 examples = docstring and self._getDoctestExamples(docstring)
1445 except (ValueError, IndexError):
1446 # e.g. line 6 of the docstring for <string> has inconsistent
1447 # leading whitespace: ...
1448 return
1449 if not examples:
1450 return
1451
1452 # Place doctest in module scope
1453 saved_stack = self.scopeStack
1454 self.scopeStack = [self.scopeStack[0]]
1455 node_offset = self.offset or (0, 0)
1456 self.pushScope(DoctestScope)
1457 if '_' not in self.scopeStack[0]:
1458 self.addBinding(None, Builtin('_'))
1459 for example in examples:
1460 try:
1461 tree = ast.parse(example.source, "<doctest>")
1462 except SyntaxError:
1463 e = sys.exc_info()[1]
1464 if PYPY:
1465 e.offset += 1
1466 position = (node_lineno + example.lineno + e.lineno,
1467 example.indent + 4 + (e.offset or 0))
1468 self.report(messages.DoctestSyntaxError, node, position)
1469 else:
1470 self.offset = (node_offset[0] + node_lineno + example.lineno,
1471 node_offset[1] + example.indent + 4)
1472 self.handleChildren(tree)
1473 self.offset = node_offset
1474 self.popScope()
1475 self.scopeStack = saved_stack
1476
1477 @in_string_annotation
1478 def handleStringAnnotation(self, s, node, ref_lineno, ref_col_offset, err):
1479 try:
1480 tree = ast.parse(s)
1481 except SyntaxError:
1482 self.report(err, node, s)
1483 return
1484
1485 body = tree.body
1486 if len(body) != 1 or not isinstance(body[0], ast.Expr):
1487 self.report(err, node, s)
1488 return
1489
1490 parsed_annotation = tree.body[0].value
1491 for descendant in ast.walk(parsed_annotation):
1492 if (
1493 'lineno' in descendant._attributes and
1494 'col_offset' in descendant._attributes
1495 ):
1496 descendant.lineno = ref_lineno
1497 descendant.col_offset = ref_col_offset
1498
1499 self.handleNode(parsed_annotation, node)
1500
1501 @in_annotation
1502 def handleAnnotation(self, annotation, node):
1503 if isinstance(annotation, ast.Str):
1504 # Defer handling forward annotation.
1505 self.deferFunction(functools.partial(
1506 self.handleStringAnnotation,
1507 annotation.s,
1508 node,
1509 annotation.lineno,
1510 annotation.col_offset,
1511 messages.ForwardAnnotationSyntaxError,
1512 ))
1513 elif self.annotationsFutureEnabled:
1514 fn = in_annotation(Checker.handleNode)
1515 self.deferFunction(lambda: fn(self, annotation, node))
1516 else:
1517 self.handleNode(annotation, node)
1518
1519 def ignore(self, node):
1520 pass
1521
1522 # "stmt" type nodes
1523 DELETE = PRINT = FOR = ASYNCFOR = WHILE = WITH = WITHITEM = \
1524 ASYNCWITH = ASYNCWITHITEM = TRYFINALLY = EXEC = \
1525 EXPR = ASSIGN = handleChildren
1526
1527 PASS = ignore
1528
1529 # "expr" type nodes
1530 BOOLOP = UNARYOP = SET = \
1531 REPR = ATTRIBUTE = \
1532 STARRED = NAMECONSTANT = NAMEDEXPR = handleChildren
1533
1534 def SUBSCRIPT(self, node):
1535 if _is_name_or_attr(node.value, 'Literal'):
1536 with self._enter_annotation(AnnotationState.NONE):
1537 self.handleChildren(node)
1538 elif _is_name_or_attr(node.value, 'Annotated'):
1539 self.handleNode(node.value, node)
1540
1541 # py39+
1542 if isinstance(node.slice, ast.Tuple):
1543 slice_tuple = node.slice
1544 # <py39
1545 elif (
1546 isinstance(node.slice, ast.Index) and
1547 isinstance(node.slice.value, ast.Tuple)
1548 ):
1549 slice_tuple = node.slice.value
1550 else:
1551 slice_tuple = None
1552
1553 # not a multi-arg `Annotated`
1554 if slice_tuple is None or len(slice_tuple.elts) < 2:
1555 self.handleNode(node.slice, node)
1556 else:
1557 # the first argument is the type
1558 self.handleNode(slice_tuple.elts[0], node)
1559 # the rest of the arguments are not
1560 with self._enter_annotation(AnnotationState.NONE):
1561 for arg in slice_tuple.elts[1:]:
1562 self.handleNode(arg, node)
1563
1564 self.handleNode(node.ctx, node)
1565 else:
1566 if _is_any_typing_member(node.value, self.scopeStack):
1567 with self._enter_annotation():
1568 self.handleChildren(node)
1569 else:
1570 self.handleChildren(node)
1571
1572 def _handle_string_dot_format(self, node):
1573 try:
1574 placeholders = tuple(parse_format_string(node.func.value.s))
1575 except ValueError as e:
1576 self.report(messages.StringDotFormatInvalidFormat, node, e)
1577 return
1578
1579 class state: # py2-compatible `nonlocal`
1580 auto = None
1581 next_auto = 0
1582
1583 placeholder_positional = set()
1584 placeholder_named = set()
1585
1586 def _add_key(fmtkey):
1587 """Returns True if there is an error which should early-exit"""
1588 if fmtkey is None: # end of string or `{` / `}` escapes
1589 return False
1590
1591 # attributes / indices are allowed in `.format(...)`
1592 fmtkey, _, _ = fmtkey.partition('.')
1593 fmtkey, _, _ = fmtkey.partition('[')
1594
1595 try:
1596 fmtkey = int(fmtkey)
1597 except ValueError:
1598 pass
1599 else: # fmtkey was an integer
1600 if state.auto is True:
1601 self.report(messages.StringDotFormatMixingAutomatic, node)
1602 return True
1603 else:
1604 state.auto = False
1605
1606 if fmtkey == '':
1607 if state.auto is False:
1608 self.report(messages.StringDotFormatMixingAutomatic, node)
1609 return True
1610 else:
1611 state.auto = True
1612
1613 fmtkey = state.next_auto
1614 state.next_auto += 1
1615
1616 if isinstance(fmtkey, int):
1617 placeholder_positional.add(fmtkey)
1618 else:
1619 placeholder_named.add(fmtkey)
1620
1621 return False
1622
1623 for _, fmtkey, spec, _ in placeholders:
1624 if _add_key(fmtkey):
1625 return
1626
1627 # spec can also contain format specifiers
1628 if spec is not None:
1629 try:
1630 spec_placeholders = tuple(parse_format_string(spec))
1631 except ValueError as e:
1632 self.report(messages.StringDotFormatInvalidFormat, node, e)
1633 return
1634
1635 for _, spec_fmtkey, spec_spec, _ in spec_placeholders:
1636 # can't recurse again
1637 if spec_spec is not None and '{' in spec_spec:
1638 self.report(
1639 messages.StringDotFormatInvalidFormat,
1640 node,
1641 'Max string recursion exceeded',
1642 )
1643 return
1644 if _add_key(spec_fmtkey):
1645 return
1646
1647 # bail early if there is *args or **kwargs
1648 if (
1649 # python 2.x *args / **kwargs
1650 getattr(node, 'starargs', None) or
1651 getattr(node, 'kwargs', None) or
1652 # python 3.x *args
1653 any(
1654 isinstance(arg, getattr(ast, 'Starred', ()))
1655 for arg in node.args
1656 ) or
1657 # python 3.x **kwargs
1658 any(kwd.arg is None for kwd in node.keywords)
1659 ):
1660 return
1661
1662 substitution_positional = set(range(len(node.args)))
1663 substitution_named = {kwd.arg for kwd in node.keywords}
1664
1665 extra_positional = substitution_positional - placeholder_positional
1666 extra_named = substitution_named - placeholder_named
1667
1668 missing_arguments = (
1669 (placeholder_positional | placeholder_named) -
1670 (substitution_positional | substitution_named)
1671 )
1672
1673 if extra_positional:
1674 self.report(
1675 messages.StringDotFormatExtraPositionalArguments,
1676 node,
1677 ', '.join(sorted(str(x) for x in extra_positional)),
1678 )
1679 if extra_named:
1680 self.report(
1681 messages.StringDotFormatExtraNamedArguments,
1682 node,
1683 ', '.join(sorted(extra_named)),
1684 )
1685 if missing_arguments:
1686 self.report(
1687 messages.StringDotFormatMissingArgument,
1688 node,
1689 ', '.join(sorted(str(x) for x in missing_arguments)),
1690 )
1691
1692 def CALL(self, node):
1693 if (
1694 isinstance(node.func, ast.Attribute) and
1695 isinstance(node.func.value, ast.Str) and
1696 node.func.attr == 'format'
1697 ):
1698 self._handle_string_dot_format(node)
1699
1700 omit = []
1701 annotated = []
1702 not_annotated = []
1703
1704 if (
1705 _is_typing(node.func, 'cast', self.scopeStack) and
1706 len(node.args) >= 1
1707 ):
1708 with self._enter_annotation():
1709 self.handleNode(node.args[0], node)
1710
1711 elif _is_typing(node.func, 'TypeVar', self.scopeStack):
1712
1713 # TypeVar("T", "int", "str")
1714 omit += ["args"]
1715 annotated += [arg for arg in node.args[1:]]
1716
1717 # TypeVar("T", bound="str")
1718 omit += ["keywords"]
1719 annotated += [k.value for k in node.keywords if k.arg == "bound"]
1720 not_annotated += [
1721 (k, ["value"] if k.arg == "bound" else None)
1722 for k in node.keywords
1723 ]
1724
1725 elif _is_typing(node.func, "TypedDict", self.scopeStack):
1726 # TypedDict("a", {"a": int})
1727 if len(node.args) > 1 and isinstance(node.args[1], ast.Dict):
1728 omit += ["args"]
1729 annotated += node.args[1].values
1730 not_annotated += [
1731 (arg, ["values"] if i == 1 else None)
1732 for i, arg in enumerate(node.args)
1733 ]
1734
1735 # TypedDict("a", a=int)
1736 omit += ["keywords"]
1737 annotated += [k.value for k in node.keywords]
1738 not_annotated += [(k, ["value"]) for k in node.keywords]
1739
1740 elif _is_typing(node.func, "NamedTuple", self.scopeStack):
1741 # NamedTuple("a", [("a", int)])
1742 if (
1743 len(node.args) > 1 and
1744 isinstance(node.args[1], (ast.Tuple, ast.List)) and
1745 all(isinstance(x, (ast.Tuple, ast.List)) and
1746 len(x.elts) == 2 for x in node.args[1].elts)
1747 ):
1748 omit += ["args"]
1749 annotated += [elt.elts[1] for elt in node.args[1].elts]
1750 not_annotated += [(elt.elts[0], None) for elt in node.args[1].elts]
1751 not_annotated += [
1752 (arg, ["elts"] if i == 1 else None)
1753 for i, arg in enumerate(node.args)
1754 ]
1755 not_annotated += [(elt, "elts") for elt in node.args[1].elts]
1756
1757 # NamedTuple("a", a=int)
1758 omit += ["keywords"]
1759 annotated += [k.value for k in node.keywords]
1760 not_annotated += [(k, ["value"]) for k in node.keywords]
1761
1762 if omit:
1763 with self._enter_annotation(AnnotationState.NONE):
1764 for na_node, na_omit in not_annotated:
1765 self.handleChildren(na_node, omit=na_omit)
1766 self.handleChildren(node, omit=omit)
1767
1768 with self._enter_annotation():
1769 for annotated_node in annotated:
1770 self.handleNode(annotated_node, node)
1771 else:
1772 self.handleChildren(node)
1773
1774 def _handle_percent_format(self, node):
1775 try:
1776 placeholders = parse_percent_format(node.left.s)
1777 except ValueError:
1778 self.report(
1779 messages.PercentFormatInvalidFormat,
1780 node,
1781 'incomplete format',
1782 )
1783 return
1784
1785 named = set()
1786 positional_count = 0
1787 positional = None
1788 for _, placeholder in placeholders:
1789 if placeholder is None:
1790 continue
1791 name, _, width, precision, conversion = placeholder
1792
1793 if conversion == '%':
1794 continue
1795
1796 if conversion not in VALID_CONVERSIONS:
1797 self.report(
1798 messages.PercentFormatUnsupportedFormatCharacter,
1799 node,
1800 conversion,
1801 )
1802
1803 if positional is None and conversion:
1804 positional = name is None
1805
1806 for part in (width, precision):
1807 if part is not None and '*' in part:
1808 if not positional:
1809 self.report(
1810 messages.PercentFormatStarRequiresSequence,
1811 node,
1812 )
1813 else:
1814 positional_count += 1
1815
1816 if positional and name is not None:
1817 self.report(
1818 messages.PercentFormatMixedPositionalAndNamed,
1819 node,
1820 )
1821 return
1822 elif not positional and name is None:
1823 self.report(
1824 messages.PercentFormatMixedPositionalAndNamed,
1825 node,
1826 )
1827 return
1828
1829 if positional:
1830 positional_count += 1
1831 else:
1832 named.add(name)
1833
1834 if (
1835 isinstance(node.right, (ast.List, ast.Tuple)) and
1836 # does not have any *splats (py35+ feature)
1837 not any(
1838 isinstance(elt, getattr(ast, 'Starred', ()))
1839 for elt in node.right.elts
1840 )
1841 ):
1842 substitution_count = len(node.right.elts)
1843 if positional and positional_count != substitution_count:
1844 self.report(
1845 messages.PercentFormatPositionalCountMismatch,
1846 node,
1847 positional_count,
1848 substitution_count,
1849 )
1850 elif not positional:
1851 self.report(messages.PercentFormatExpectedMapping, node)
1852
1853 if (
1854 isinstance(node.right, ast.Dict) and
1855 all(isinstance(k, ast.Str) for k in node.right.keys)
1856 ):
1857 if positional and positional_count > 1:
1858 self.report(messages.PercentFormatExpectedSequence, node)
1859 return
1860
1861 substitution_keys = {k.s for k in node.right.keys}
1862 extra_keys = substitution_keys - named
1863 missing_keys = named - substitution_keys
1864 if not positional and extra_keys:
1865 self.report(
1866 messages.PercentFormatExtraNamedArguments,
1867 node,
1868 ', '.join(sorted(extra_keys)),
1869 )
1870 if not positional and missing_keys:
1871 self.report(
1872 messages.PercentFormatMissingArgument,
1873 node,
1874 ', '.join(sorted(missing_keys)),
1875 )
1876
1877 def BINOP(self, node):
1878 if (
1879 isinstance(node.op, ast.Mod) and
1880 isinstance(node.left, ast.Str)
1881 ):
1882 self._handle_percent_format(node)
1883 self.handleChildren(node)
1884
1885 def STR(self, node):
1886 if self._in_annotation:
1887 fn = functools.partial(
1888 self.handleStringAnnotation,
1889 node.s,
1890 node,
1891 node.lineno,
1892 node.col_offset,
1893 messages.ForwardAnnotationSyntaxError,
1894 )
1895 if self._in_deferred:
1896 fn()
1897 else:
1898 self.deferFunction(fn)
1899
1900 if PY38_PLUS:
1901 def CONSTANT(self, node):
1902 if isinstance(node.value, str):
1903 return self.STR(node)
1904 else:
1905 NUM = BYTES = ELLIPSIS = CONSTANT = ignore
1906
1907 # "slice" type nodes
1908 SLICE = EXTSLICE = INDEX = handleChildren
1909
1910 # expression contexts are node instances too, though being constants
1911 LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
1912
1913 # same for operators
1914 AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
1915 BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
1916 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = \
1917 MATMULT = ignore
1918
1919 def RAISE(self, node):
1920 self.handleChildren(node)
1921
1922 arg = get_raise_argument(node)
1923
1924 if isinstance(arg, ast.Call):
1925 if is_notimplemented_name_node(arg.func):
1926 # Handle "raise NotImplemented(...)"
1927 self.report(messages.RaiseNotImplemented, node)
1928 elif is_notimplemented_name_node(arg):
1929 # Handle "raise NotImplemented"
1930 self.report(messages.RaiseNotImplemented, node)
1931
1932 # additional node types
1933 COMPREHENSION = KEYWORD = FORMATTEDVALUE = handleChildren
1934
1935 _in_fstring = False
1936
1937 def JOINEDSTR(self, node):
1938 if (
1939 # the conversion / etc. flags are parsed as f-strings without
1940 # placeholders
1941 not self._in_fstring and
1942 not any(isinstance(x, ast.FormattedValue) for x in node.values)
1943 ):
1944 self.report(messages.FStringMissingPlaceholders, node)
1945
1946 self._in_fstring, orig = True, self._in_fstring
1947 try:
1948 self.handleChildren(node)
1949 finally:
1950 self._in_fstring = orig
1951
1952 def DICT(self, node):
1953 # Complain if there are duplicate keys with different values
1954 # If they have the same value it's not going to cause potentially
1955 # unexpected behaviour so we'll not complain.
1956 keys = [
1957 convert_to_value(key) for key in node.keys
1958 ]
1959
1960 key_counts = counter(keys)
1961 duplicate_keys = [
1962 key for key, count in key_counts.items()
1963 if count > 1
1964 ]
1965
1966 for key in duplicate_keys:
1967 key_indices = [i for i, i_key in enumerate(keys) if i_key == key]
1968
1969 values = counter(
1970 convert_to_value(node.values[index])
1971 for index in key_indices
1972 )
1973 if any(count == 1 for value, count in values.items()):
1974 for key_index in key_indices:
1975 key_node = node.keys[key_index]
1976 if isinstance(key, VariableKey):
1977 self.report(messages.MultiValueRepeatedKeyVariable,
1978 key_node,
1979 key.name)
1980 else:
1981 self.report(
1982 messages.MultiValueRepeatedKeyLiteral,
1983 key_node,
1984 key,
1985 )
1986 self.handleChildren(node)
1987
1988 def IF(self, node):
1989 if isinstance(node.test, ast.Tuple) and node.test.elts != []:
1990 self.report(messages.IfTuple, node)
1991 self.handleChildren(node)
1992
1993 IFEXP = IF
1994
1995 def ASSERT(self, node):
1996 if isinstance(node.test, ast.Tuple) and node.test.elts != []:
1997 self.report(messages.AssertTuple, node)
1998 self.handleChildren(node)
1999
2000 def GLOBAL(self, node):
2001 """
2002 Keep track of globals declarations.
2003 """
2004 global_scope_index = 1 if self._in_doctest() else 0
2005 global_scope = self.scopeStack[global_scope_index]
2006
2007 # Ignore 'global' statement in global scope.
2008 if self.scope is not global_scope:
2009
2010 # One 'global' statement can bind multiple (comma-delimited) names.
2011 for node_name in node.names:
2012 node_value = Assignment(node_name, node)
2013
2014 # Remove UndefinedName messages already reported for this name.
2015 # TODO: if the global is not used in this scope, it does not
2016 # become a globally defined name. See test_unused_global.
2017 self.messages = [
2018 m for m in self.messages if not
2019 isinstance(m, messages.UndefinedName) or
2020 m.message_args[0] != node_name]
2021
2022 # Bind name to global scope if it doesn't exist already.
2023 global_scope.setdefault(node_name, node_value)
2024
2025 # Bind name to non-global scopes, but as already "used".
2026 node_value.used = (global_scope, node)
2027 for scope in self.scopeStack[global_scope_index + 1:]:
2028 scope[node_name] = node_value
2029
2030 NONLOCAL = GLOBAL
2031
2032 def GENERATOREXP(self, node):
2033 self.pushScope(GeneratorScope)
2034 self.handleChildren(node)
2035 self.popScope()
2036
2037 LISTCOMP = handleChildren if PY2 else GENERATOREXP
2038
2039 DICTCOMP = SETCOMP = GENERATOREXP
2040
2041 def NAME(self, node):
2042 """
2043 Handle occurrence of Name (which can be a load/store/delete access.)
2044 """
2045 # Locate the name in locals / function / globals scopes.
2046 if isinstance(node.ctx, ast.Load):
2047 self.handleNodeLoad(node)
2048 if (node.id == 'locals' and isinstance(self.scope, FunctionScope) and
2049 isinstance(node._pyflakes_parent, ast.Call)):
2050 # we are doing locals() call in current scope
2051 self.scope.usesLocals = True
2052 elif isinstance(node.ctx, ast.Store):
2053 self.handleNodeStore(node)
2054 elif PY2 and isinstance(node.ctx, ast.Param):
2055 self.handleNodeStore(node)
2056 elif isinstance(node.ctx, ast.Del):
2057 self.handleNodeDelete(node)
2058 else:
2059 # Unknown context
2060 raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
2061
2062 def CONTINUE(self, node):
2063 # Walk the tree up until we see a loop (OK), a function or class
2064 # definition (not OK), for 'continue', a finally block (not OK), or
2065 # the top module scope (not OK)
2066 n = node
2067 while hasattr(n, '_pyflakes_parent'):
2068 n, n_child = n._pyflakes_parent, n
2069 if isinstance(n, LOOP_TYPES):
2070 # Doesn't apply unless it's in the loop itself
2071 if n_child not in n.orelse:
2072 return
2073 if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
2074 break
2075 # Handle Try/TryFinally difference in Python < and >= 3.3
2076 if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
2077 if n_child in n.finalbody and not PY38_PLUS:
2078 self.report(messages.ContinueInFinally, node)
2079 return
2080 if isinstance(node, ast.Continue):
2081 self.report(messages.ContinueOutsideLoop, node)
2082 else: # ast.Break
2083 self.report(messages.BreakOutsideLoop, node)
2084
2085 BREAK = CONTINUE
2086
2087 def RETURN(self, node):
2088 if isinstance(self.scope, (ClassScope, ModuleScope)):
2089 self.report(messages.ReturnOutsideFunction, node)
2090 return
2091
2092 if (
2093 node.value and
2094 hasattr(self.scope, 'returnValue') and
2095 not self.scope.returnValue
2096 ):
2097 self.scope.returnValue = node.value
2098 self.handleNode(node.value, node)
2099
2100 def YIELD(self, node):
2101 if isinstance(self.scope, (ClassScope, ModuleScope)):
2102 self.report(messages.YieldOutsideFunction, node)
2103 return
2104
2105 self.scope.isGenerator = True
2106 self.handleNode(node.value, node)
2107
2108 AWAIT = YIELDFROM = YIELD
2109
2110 def FUNCTIONDEF(self, node):
2111 for deco in node.decorator_list:
2112 self.handleNode(deco, node)
2113 self.LAMBDA(node)
2114 self.addBinding(node, FunctionDefinition(node.name, node))
2115 # doctest does not process doctest within a doctest,
2116 # or in nested functions.
2117 if (self.withDoctest and
2118 not self._in_doctest() and
2119 not isinstance(self.scope, FunctionScope)):
2120 self.deferFunction(lambda: self.handleDoctests(node))
2121
2122 ASYNCFUNCTIONDEF = FUNCTIONDEF
2123
2124 def LAMBDA(self, node):
2125 args = []
2126 annotations = []
2127
2128 if PY2:
2129 def addArgs(arglist):
2130 for arg in arglist:
2131 if isinstance(arg, ast.Tuple):
2132 addArgs(arg.elts)
2133 else:
2134 args.append(arg.id)
2135 addArgs(node.args.args)
2136 defaults = node.args.defaults
2137 else:
2138 if PY38_PLUS:
2139 for arg in node.args.posonlyargs:
2140 args.append(arg.arg)
2141 annotations.append(arg.annotation)
2142 for arg in node.args.args + node.args.kwonlyargs:
2143 args.append(arg.arg)
2144 annotations.append(arg.annotation)
2145 defaults = node.args.defaults + node.args.kw_defaults
2146
2147 # Only for Python3 FunctionDefs
2148 is_py3_func = hasattr(node, 'returns')
2149
2150 for arg_name in ('vararg', 'kwarg'):
2151 wildcard = getattr(node.args, arg_name)
2152 if not wildcard:
2153 continue
2154 args.append(wildcard if PY2 else wildcard.arg)
2155 if is_py3_func:
2156 if PY2: # Python 2.7
2157 argannotation = arg_name + 'annotation'
2158 annotations.append(getattr(node.args, argannotation))
2159 else: # Python >= 3.4
2160 annotations.append(wildcard.annotation)
2161
2162 if is_py3_func:
2163 annotations.append(node.returns)
2164
2165 if len(set(args)) < len(args):
2166 for (idx, arg) in enumerate(args):
2167 if arg in args[:idx]:
2168 self.report(messages.DuplicateArgument, node, arg)
2169
2170 for annotation in annotations:
2171 self.handleAnnotation(annotation, node)
2172
2173 for default in defaults:
2174 self.handleNode(default, node)
2175
2176 def runFunction():
2177
2178 self.pushScope()
2179
2180 self.handleChildren(node, omit=['decorator_list', 'returns'])
2181
2182 def checkUnusedAssignments():
2183 """
2184 Check to see if any assignments have not been used.
2185 """
2186 for name, binding in self.scope.unusedAssignments():
2187 self.report(messages.UnusedVariable, binding.source, name)
2188 self.deferAssignment(checkUnusedAssignments)
2189
2190 if PY2:
2191 def checkReturnWithArgumentInsideGenerator():
2192 """
2193 Check to see if there is any return statement with
2194 arguments but the function is a generator.
2195 """
2196 if self.scope.isGenerator and self.scope.returnValue:
2197 self.report(messages.ReturnWithArgsInsideGenerator,
2198 self.scope.returnValue)
2199 self.deferAssignment(checkReturnWithArgumentInsideGenerator)
2200 self.popScope()
2201
2202 self.deferFunction(runFunction)
2203
2204 def ARGUMENTS(self, node):
2205 self.handleChildren(node, omit=('defaults', 'kw_defaults'))
2206 if PY2:
2207 scope_node = self.getScopeNode(node)
2208 if node.vararg:
2209 self.addBinding(node, Argument(node.vararg, scope_node))
2210 if node.kwarg:
2211 self.addBinding(node, Argument(node.kwarg, scope_node))
2212
2213 def ARG(self, node):
2214 self.addBinding(node, Argument(node.arg, self.getScopeNode(node)))
2215
2216 def CLASSDEF(self, node):
2217 """
2218 Check names used in a class definition, including its decorators, base
2219 classes, and the body of its definition. Additionally, add its name to
2220 the current scope.
2221 """
2222 for deco in node.decorator_list:
2223 self.handleNode(deco, node)
2224 for baseNode in node.bases:
2225 self.handleNode(baseNode, node)
2226 if not PY2:
2227 for keywordNode in node.keywords:
2228 self.handleNode(keywordNode, node)
2229 self.pushScope(ClassScope)
2230 # doctest does not process doctest within a doctest
2231 # classes within classes are processed.
2232 if (self.withDoctest and
2233 not self._in_doctest() and
2234 not isinstance(self.scope, FunctionScope)):
2235 self.deferFunction(lambda: self.handleDoctests(node))
2236 for stmt in node.body:
2237 self.handleNode(stmt, node)
2238 self.popScope()
2239 self.addBinding(node, ClassDefinition(node.name, node))
2240
2241 def AUGASSIGN(self, node):
2242 self.handleNodeLoad(node.target)
2243 self.handleNode(node.value, node)
2244 self.handleNode(node.target, node)
2245
2246 def TUPLE(self, node):
2247 if not PY2 and isinstance(node.ctx, ast.Store):
2248 # Python 3 advanced tuple unpacking: a, *b, c = d.
2249 # Only one starred expression is allowed, and no more than 1<<8
2250 # assignments are allowed before a stared expression. There is
2251 # also a limit of 1<<24 expressions after the starred expression,
2252 # which is impossible to test due to memory restrictions, but we
2253 # add it here anyway
2254 has_starred = False
2255 star_loc = -1
2256 for i, n in enumerate(node.elts):
2257 if isinstance(n, ast.Starred):
2258 if has_starred:
2259 self.report(messages.TwoStarredExpressions, node)
2260 # The SyntaxError doesn't distinguish two from more
2261 # than two.
2262 break
2263 has_starred = True
2264 star_loc = i
2265 if star_loc >= 1 << 8 or len(node.elts) - star_loc - 1 >= 1 << 24:
2266 self.report(messages.TooManyExpressionsInStarredAssignment, node)
2267 self.handleChildren(node)
2268
2269 LIST = TUPLE
2270
2271 def IMPORT(self, node):
2272 for alias in node.names:
2273 if '.' in alias.name and not alias.asname:
2274 importation = SubmoduleImportation(alias.name, node)
2275 else:
2276 name = alias.asname or alias.name
2277 importation = Importation(name, node, alias.name)
2278 self.addBinding(node, importation)
2279
2280 def IMPORTFROM(self, node):
2281 if node.module == '__future__':
2282 if not self.futuresAllowed:
2283 self.report(messages.LateFutureImport,
2284 node, [n.name for n in node.names])
2285 else:
2286 self.futuresAllowed = False
2287
2288 module = ('.' * node.level) + (node.module or '')
2289
2290 for alias in node.names:
2291 name = alias.asname or alias.name
2292 if node.module == '__future__':
2293 importation = FutureImportation(name, node, self.scope)
2294 if alias.name not in __future__.all_feature_names:
2295 self.report(messages.FutureFeatureNotDefined,
2296 node, alias.name)
2297 if alias.name == 'annotations':
2298 self.annotationsFutureEnabled = True
2299 elif alias.name == '*':
2300 # Only Python 2, local import * is a SyntaxWarning
2301 if not PY2 and not isinstance(self.scope, ModuleScope):
2302 self.report(messages.ImportStarNotPermitted,
2303 node, module)
2304 continue
2305
2306 self.scope.importStarred = True
2307 self.report(messages.ImportStarUsed, node, module)
2308 importation = StarImportation(module, node)
2309 else:
2310 importation = ImportationFrom(name, node,
2311 module, alias.name)
2312 self.addBinding(node, importation)
2313
2314 def TRY(self, node):
2315 handler_names = []
2316 # List the exception handlers
2317 for i, handler in enumerate(node.handlers):
2318 if isinstance(handler.type, ast.Tuple):
2319 for exc_type in handler.type.elts:
2320 handler_names.append(getNodeName(exc_type))
2321 elif handler.type:
2322 handler_names.append(getNodeName(handler.type))
2323
2324 if handler.type is None and i < len(node.handlers) - 1:
2325 self.report(messages.DefaultExceptNotLast, handler)
2326 # Memorize the except handlers and process the body
2327 self.exceptHandlers.append(handler_names)
2328 for child in node.body:
2329 self.handleNode(child, node)
2330 self.exceptHandlers.pop()
2331 # Process the other nodes: "except:", "else:", "finally:"
2332 self.handleChildren(node, omit='body')
2333
2334 TRYEXCEPT = TRY
2335
2336 def EXCEPTHANDLER(self, node):
2337 if PY2 or node.name is None:
2338 self.handleChildren(node)
2339 return
2340
2341 # If the name already exists in the scope, modify state of existing
2342 # binding.
2343 if node.name in self.scope:
2344 self.handleNodeStore(node)
2345
2346 # 3.x: the name of the exception, which is not a Name node, but a
2347 # simple string, creates a local that is only bound within the scope of
2348 # the except: block. As such, temporarily remove the existing binding
2349 # to more accurately determine if the name is used in the except:
2350 # block.
2351
2352 try:
2353 prev_definition = self.scope.pop(node.name)
2354 except KeyError:
2355 prev_definition = None
2356
2357 self.handleNodeStore(node)
2358 self.handleChildren(node)
2359
2360 # See discussion on https://github.com/PyCQA/pyflakes/pull/59
2361
2362 # We're removing the local name since it's being unbound after leaving
2363 # the except: block and it's always unbound if the except: block is
2364 # never entered. This will cause an "undefined name" error raised if
2365 # the checked code tries to use the name afterwards.
2366 #
2367 # Unless it's been removed already. Then do nothing.
2368
2369 try:
2370 binding = self.scope.pop(node.name)
2371 except KeyError:
2372 pass
2373 else:
2374 if not binding.used:
2375 self.report(messages.UnusedVariable, node, node.name)
2376
2377 # Restore.
2378 if prev_definition:
2379 self.scope[node.name] = prev_definition
2380
2381 def ANNASSIGN(self, node):
2382 self.handleNode(node.target, node)
2383 self.handleAnnotation(node.annotation, node)
2384 if node.value:
2385 # If the assignment has value, handle the *value* now.
2386 self.handleNode(node.value, node)
2387
2388 def COMPARE(self, node):
2389 left = node.left
2390 for op, right in zip(node.ops, node.comparators):
2391 if (
2392 isinstance(op, (ast.Is, ast.IsNot)) and (
2393 _is_const_non_singleton(left) or
2394 _is_const_non_singleton(right)
2395 )
2396 ):
2397 self.report(messages.IsLiteral, node)
2398 left = right
2399
2400 self.handleChildren(node)
2401
2402 MATCH = MATCH_CASE = MATCHCLASS = MATCHOR = MATCHSEQUENCE = handleChildren
2403 MATCHSINGLETON = MATCHVALUE = handleChildren
2404
2405 def _match_target(self, node):
2406 self.handleNodeStore(node)
2407 self.handleChildren(node)
2408
2409 MATCHAS = MATCHMAPPING = MATCHSTAR = _match_target

eric ide

mercurial