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

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

eric ide

mercurial