4 Implement the central Checker class.
5 Also, it models the Bindings and Scopes.
20 from pyflakes
import messages
22 PYPY
= hasattr(sys
, 'pypy_version_info')
24 builtin_vars
= dir(builtins
)
26 parse_format_string
= string
.Formatter().parse
29 def getAlternatives(n
):
30 if isinstance(n
, ast
.If
):
32 elif isinstance(n
, ast
.Try
):
33 return [n
.body
+ n
.orelse
] + [[hdl
] for hdl
in n
.handlers
]
34 elif sys
.version_info
>= (3, 10) and isinstance(n
, ast
.Match
):
35 return [mc
.body
for mc
in n
.cases
]
38 FOR_TYPES
= (ast
.For
, ast
.AsyncFor
)
41 def _is_singleton(node
): # type: (ast.AST) -> bool
43 isinstance(node
, ast
.Constant
) and
44 isinstance(node
.value
, (bool, type(Ellipsis), type(None)))
48 def _is_tuple_constant(node
): # type: (ast.AST) -> bool
50 isinstance(node
, ast
.Tuple
) and
51 all(_is_constant(elt
) for elt
in node
.elts
)
55 def _is_constant(node
):
56 return isinstance(node
, ast
.Constant
) or _is_tuple_constant(node
)
59 def _is_const_non_singleton(node
): # type: (ast.AST) -> bool
60 return _is_constant(node
) and not _is_singleton(node
)
63 def _is_name_or_attr(node
, name
): # type: (ast.AST, str) -> bool
65 (isinstance(node
, ast
.Name
) and node
.id == name
) or
66 (isinstance(node
, ast
.Attribute
) and node
.attr
== name
)
70 MAPPING_KEY_RE
= re
.compile(r
'\(([^()]*)\)')
71 CONVERSION_FLAG_RE
= re
.compile('[#0+ -]*')
72 WIDTH_RE
= re
.compile(r
'(?:\*|\d*)')
73 PRECISION_RE
= re
.compile(r
'(?:\.(?:\*|\d*))?')
74 LENGTH_RE
= re
.compile('[hlL]?')
75 # https://docs.python.org/3/library/stdtypes.html#old-string-formatting
76 VALID_CONVERSIONS
= frozenset('diouxXeEfFgGcrsa%')
79 def _must_match(regex
, string
, pos
):
80 match
= regex
.match(string
, pos
)
81 assert match
is not None
85 def parse_percent_format(s
):
86 """Parses the string component of a `'...' % ...` format call
88 Copied from https://github.com/asottile/pyupgrade at v1.20.1
101 except ValueError: # no more % fields!
102 yield s
[string_start
:], None
109 key_match
= MAPPING_KEY_RE
.match(s
, i
)
111 key
= key_match
.group(1)
116 conversion_flag_match
= _must_match(CONVERSION_FLAG_RE
, s
, i
)
117 conversion_flag
= conversion_flag_match
.group() or None
118 i
= conversion_flag_match
.end()
120 width_match
= _must_match(WIDTH_RE
, s
, i
)
121 width
= width_match
.group() or None
122 i
= width_match
.end()
124 precision_match
= _must_match(PRECISION_RE
, s
, i
)
125 precision
= precision_match
.group() or None
126 i
= precision_match
.end()
128 # length modifier is ignored
129 i
= _must_match(LENGTH_RE
, s
, i
).end()
134 raise ValueError('end-of-string while parsing format')
137 fmt
= (key
, conversion_flag
, width
, precision
, conversion
)
138 yield s
[string_start
:string_end
], fmt
144 raise ValueError('end-of-string while parsing format')
146 return tuple(_parse_inner())
149 class _FieldsOrder(dict):
150 """Fix order of AST node fields."""
152 def _get_fields(self
, node_class
):
153 # handle iter before target, and generators before element
154 fields
= node_class
._fields
156 key_first
= 'iter'.find
157 elif 'generators' in fields
:
158 key_first
= 'generators'.find
160 key_first
= 'value'.find
161 return tuple(sorted(fields
, key
=key_first
, reverse
=True))
163 def __missing__(self
, node_class
):
164 self
[node_class
] = fields
= self
._get
_fields
(node_class
)
170 Simplest required implementation of collections.Counter. Required as 2.6
171 does not have Counter in collections.
175 results
[item
] = results
.get(item
, 0) + 1
179 def iter_child_nodes(node
, omit
=None, _fields_order
=_FieldsOrder()):
181 Yield all direct child nodes of *node*, that is, all fields that
182 are nodes and all items of fields that are lists of nodes.
184 :param node: AST node to be iterated upon
185 :param omit: String or tuple of strings denoting the
186 attributes of the node to be omitted from
188 :param _fields_order: Order of AST node fields
190 for name
in _fields_order
[node
.__class
__]:
191 if omit
and name
in omit
:
193 field
= getattr(node
, name
, None)
194 if isinstance(field
, ast
.AST
):
196 elif isinstance(field
, list):
198 if isinstance(item
, ast
.AST
):
202 def convert_to_value(item
):
203 if isinstance(item
, ast
.Constant
):
205 elif isinstance(item
, ast
.Tuple
):
206 return tuple(convert_to_value(i
) for i
in item
.elts
)
207 elif isinstance(item
, ast
.Name
):
208 return VariableKey(item
=item
)
210 return UnhandledKeyType()
213 def is_notimplemented_name_node(node
):
214 return isinstance(node
, ast
.Name
) and getNodeName(node
) == 'NotImplemented'
219 Represents the binding of a value to a name.
221 The checker uses this to keep track of which names have been bound and
222 which names have not. See L{Assignment} for a special type of binding that
223 is checked with stricter rules.
225 @ivar used: pair of (L{Scope}, node) indicating the scope and
226 the node that this binding was last used.
229 def __init__(self
, name
, source
):
238 return '<{} object {!r} from line {!r} at 0x{:x}>'.format(
239 self
.__class
__.__name
__,
245 def redefines(self
, other
):
246 return isinstance(other
, Definition
) and self
.name
== other
.name
249 class Definition(Binding
):
251 A binding that defines a function or a class.
253 def redefines(self
, other
):
255 super().redefines(other
) or
256 (isinstance(other
, Assignment
) and self
.name
== other
.name
)
260 class Builtin(Definition
):
261 """A definition created for all Python builtins."""
263 def __init__(self
, name
):
264 super().__init
__(name
, None)
267 return '<{} object {!r} at 0x{:x}>'.format(
268 self
.__class
__.__name
__,
274 class UnhandledKeyType
:
276 A dictionary key of a type that we cannot or do not check for duplicates.
282 A dictionary key which is a variable.
284 @ivar item: The variable AST object.
286 def __init__(self
, item
):
289 def __eq__(self
, compare
):
291 compare
.__class
__ == self
.__class
__ and
292 compare
.name
== self
.name
296 return hash(self
.name
)
299 class Importation(Definition
):
301 A binding created by an import statement.
303 @ivar fullName: The complete name given to the import statement,
304 possibly including multiple dotted components.
305 @type fullName: C{str}
308 def __init__(self
, name
, source
, full_name
=None):
309 self
.fullName
= full_name
or name
311 super().__init
__(name
, source
)
313 def redefines(self
, other
):
314 if isinstance(other
, SubmoduleImportation
):
315 # See note in SubmoduleImportation about RedefinedWhileUnused
316 return self
.fullName
== other
.fullName
317 return isinstance(other
, Definition
) and self
.name
== other
.name
319 def _has_alias(self
):
320 """Return whether importation needs an as clause."""
321 return not self
.fullName
.split('.')[-1] == self
.name
324 def source_statement(self
):
325 """Generate a source statement equivalent to the import."""
326 if self
._has
_alias
():
327 return f
'import {self.fullName} as {self.name}'
329 return 'import %s' % self
.fullName
332 """Return import full name with alias."""
333 if self
._has
_alias
():
334 return self
.fullName
+ ' as ' + self
.name
339 class SubmoduleImportation(Importation
):
341 A binding created by a submodule import statement.
343 A submodule import is a special case where the root module is implicitly
344 imported, without an 'as' clause, and the submodule is also imported.
345 Python does not restrict which attributes of the root module may be used.
347 This class is only used when the submodule import is without an 'as' clause.
349 pyflakes handles this case by registering the root module name in the scope,
350 allowing any attribute of the root module to be accessed.
352 RedefinedWhileUnused is suppressed in `redefines` unless the submodule
353 name is also the same, to avoid false positives.
356 def __init__(self
, name
, source
):
357 # A dot should only appear in the name when it is a submodule import
358 assert '.' in name
and (not source
or isinstance(source
, ast
.Import
))
359 package_name
= name
.split('.')[0]
360 super().__init
__(package_name
, source
)
363 def redefines(self
, other
):
364 if isinstance(other
, Importation
):
365 return self
.fullName
== other
.fullName
366 return super().redefines(other
)
372 def source_statement(self
):
373 return 'import ' + self
.fullName
376 class ImportationFrom(Importation
):
378 def __init__(self
, name
, source
, module
, real_name
=None):
380 self
.real_name
= real_name
or name
382 if module
.endswith('.'):
383 full_name
= module
+ self
.real_name
385 full_name
= module
+ '.' + self
.real_name
387 super().__init
__(name
, source
, full_name
)
390 """Return import full name with alias."""
391 if self
.real_name
!= self
.name
:
392 return self
.fullName
+ ' as ' + self
.name
397 def source_statement(self
):
398 if self
.real_name
!= self
.name
:
399 return f
'from {self.module} import {self.real_name} as {self.name}'
401 return f
'from {self.module} import {self.name}'
404 class StarImportation(Importation
):
405 """A binding created by a 'from x import *' statement."""
407 def __init__(self
, name
, source
):
408 super().__init
__('*', source
)
409 # Each star importation needs a unique name, and
410 # may not be the module name otherwise it will be deemed imported
411 self
.name
= name
+ '.*'
415 def source_statement(self
):
416 return 'from ' + self
.fullName
+ ' import *'
419 # When the module ends with a ., avoid the ambiguous '..*'
420 if self
.fullName
.endswith('.'):
421 return self
.source_statement
426 class FutureImportation(ImportationFrom
):
428 A binding created by a from `__future__` import statement.
430 `__future__` imports are implicitly used.
433 def __init__(self
, name
, source
, scope
):
434 super().__init
__(name
, source
, '__future__')
435 self
.used
= (scope
, source
)
438 class Argument(Binding
):
440 Represents binding a name as an argument.
444 class Assignment(Binding
):
446 Represents binding a name with an explicit assignment.
448 The checker will raise warnings for any Assignment that isn't used. Also,
449 the checker does not consider assignments in tuple/list unpacking to be
450 Assignments, rather it treats them as simple Bindings.
454 class NamedExprAssignment(Assignment
):
456 Represents binding a name with an assignment expression.
460 class Annotation(Binding
):
462 Represents binding a name to a type without an associated value.
464 As long as this name is not assigned a value in another binding, it is considered
465 undefined for most purposes. One notable exception is using the name as a type
469 def redefines(self
, other
):
470 """An Annotation doesn't define any name, so it cannot redefine one."""
474 class FunctionDefinition(Definition
):
478 class ClassDefinition(Definition
):
482 class ExportBinding(Binding
):
484 A binding created by an C{__all__} assignment. If the names in the list
485 can be determined statically, they will be treated as names for export and
486 additional checking applied to them.
488 The only recognized C{__all__} assignment via list/tuple concatenation is in the
491 __all__ = ['a'] + ['b'] + ['c']
493 Names which are imported and not otherwise used but appear in the value of
494 C{__all__} will not have an unused import warning reported for them.
497 def __init__(self
, name
, source
, scope
):
498 if '__all__' in scope
and isinstance(source
, ast
.AugAssign
):
499 self
.names
= list(scope
['__all__'].names
)
503 def _add_to_names(container
):
504 for node
in container
.elts
:
505 if isinstance(node
, ast
.Constant
) and isinstance(node
.value
, str):
506 self
.names
.append(node
.value
)
508 if isinstance(source
.value
, (ast
.List
, ast
.Tuple
)):
509 _add_to_names(source
.value
)
510 # If concatenating lists or tuples
511 elif isinstance(source
.value
, ast
.BinOp
):
512 currentValue
= source
.value
513 while isinstance(currentValue
.right
, (ast
.List
, ast
.Tuple
)):
514 left
= currentValue
.left
515 right
= currentValue
.right
517 # If more lists are being added
518 if isinstance(left
, ast
.BinOp
):
520 # If just two lists are being added
521 elif isinstance(left
, (ast
.List
, ast
.Tuple
)):
523 # All lists accounted for - done
525 # If not list concatenation
528 super().__init
__(name
, source
)
532 importStarred
= False # set to True when import * is found
535 scope_cls
= self
.__class
__.__name
__
536 return f
'<{scope_cls} at 0x{id(self):x} {dict.__repr__(self)}>'
539 class ClassScope(Scope
):
543 class FunctionScope(Scope
):
545 I represent a name scope for a function.
547 @ivar globals: Names declared 'global' in this function.
550 alwaysUsed
= {'__tracebackhide__', '__traceback_info__',
551 '__traceback_supplement__'}
555 # Simplify: manage the special locals as globals
556 self
.globals = self
.alwaysUsed
.copy()
557 self
.returnValue
= None # First non-empty return
559 def unused_assignments(self
):
561 Return a generator for the assignments which have not been used.
563 for name
, binding
in self
.items():
564 if (not binding
.used
and
565 name
!= '_' and # see issue #202
566 name
not in self
.globals and
567 not self
.usesLocals
and
568 isinstance(binding
, Assignment
)):
571 def unused_annotations(self
):
573 Return a generator for the annotations which have not been used.
575 for name
, binding
in self
.items():
576 if not binding
.used
and isinstance(binding
, Annotation
):
580 class TypeScope(Scope
):
584 class GeneratorScope(Scope
):
588 class ModuleScope(Scope
):
589 """Scope for a module."""
590 _futures_allowed
= True
591 _annotations_future_enabled
= False
594 class DoctestScope(ModuleScope
):
595 """Scope for a doctest."""
598 class DetectClassScopedMagic
:
602 # Globally defined names which are not attributes of the builtins module, or
603 # are only present on some platforms.
604 _MAGIC_GLOBALS
= ['__file__', '__builtins__', '__annotations__', 'WindowsError']
607 def getNodeName(node
):
608 # Returns node.id, or node.name, or None
609 if hasattr(node
, 'id'): # One of the many nodes with an id
611 if hasattr(node
, 'name'): # an ExceptHandler node
613 if hasattr(node
, 'rest'): # a MatchMapping node
617 TYPING_MODULES
= frozenset(('typing', 'typing_extensions'))
620 def _is_typing_helper(node
, is_name_match_fn
, scope_stack
):
622 Internal helper to determine whether or not something is a member of a
623 typing module. This is used as part of working out whether we are within a
624 type annotation context.
626 Note: you probably don't want to use this function directly. Instead see the
627 utils below which wrap it (`_is_typing` and `_is_any_typing_member`).
630 def _bare_name_is_attr(name
):
631 for scope
in reversed(scope_stack
):
634 isinstance(scope
[name
], ImportationFrom
) and
635 scope
[name
].module
in TYPING_MODULES
and
636 is_name_match_fn(scope
[name
].real_name
)
641 def _module_scope_is_typing(name
):
642 for scope
in reversed(scope_stack
):
645 isinstance(scope
[name
], Importation
) and
646 scope
[name
].fullName
in TYPING_MODULES
653 isinstance(node
, ast
.Name
) and
654 _bare_name_is_attr(node
.id)
656 isinstance(node
, ast
.Attribute
) and
657 isinstance(node
.value
, ast
.Name
) and
658 _module_scope_is_typing(node
.value
.id) and
659 is_name_match_fn(node
.attr
)
664 def _is_typing(node
, typing_attr
, scope_stack
):
666 Determine whether `node` represents the member of a typing module specified
669 This is used as part of working out whether we are within a type annotation
672 return _is_typing_helper(node
, lambda x
: x
== typing_attr
, scope_stack
)
675 def _is_any_typing_member(node
, scope_stack
):
677 Determine whether `node` represents any member of a typing module.
679 This is used as part of working out whether we are within a type annotation
682 return _is_typing_helper(node
, lambda x
: True, scope_stack
)
685 def is_typing_overload(value
, scope_stack
):
687 isinstance(value
.source
, (ast
.FunctionDef
, ast
.AsyncFunctionDef
)) and
689 _is_typing(dec
, 'overload', scope_stack
)
690 for dec
in value
.source
.decorator_list
695 class AnnotationState
:
701 def in_annotation(func
):
702 @functools.wraps(func
)
703 def in_annotation_func(self
, *args
, **kwargs
):
704 with self
._enter
_annotation
():
705 return func(self
, *args
, **kwargs
)
706 return in_annotation_func
709 def in_string_annotation(func
):
710 @functools.wraps(func
)
711 def in_annotation_func(self
, *args
, **kwargs
):
712 with self
._enter
_annotation
(AnnotationState
.STRING
):
713 return func(self
, *args
, **kwargs
)
714 return in_annotation_func
718 """I check the cleanliness and sanity of Python code."""
721 ast
.Module
: ModuleScope
,
722 ast
.ClassDef
: ClassScope
,
723 ast
.FunctionDef
: FunctionScope
,
724 ast
.AsyncFunctionDef
: FunctionScope
,
725 ast
.Lambda
: FunctionScope
,
726 ast
.ListComp
: GeneratorScope
,
727 ast
.SetComp
: GeneratorScope
,
728 ast
.GeneratorExp
: GeneratorScope
,
729 ast
.DictComp
: GeneratorScope
,
734 _in_annotation
= AnnotationState
.NONE
736 builtIns
= set(builtin_vars
).union(_MAGIC_GLOBALS
)
737 _customBuiltIns
= os
.environ
.get('PYFLAKES_BUILTINS')
739 builtIns
.update(_customBuiltIns
.split(','))
742 def __init__(self
, tree
, filename
='(none)', builtins
=None,
743 withDoctest
='PYFLAKES_DOCTEST' in os
.environ
, file_tokens
=()):
744 self
._nodeHandlers
= {}
745 self
._deferred
= collections
.deque()
748 self
.filename
= filename
750 self
.builtIns
= self
.builtIns
.union(builtins
)
751 self
.withDoctest
= withDoctest
752 self
.exceptHandlers
= [()]
757 scope_tp
= Checker
._ast
_node
_scope
[type(tree
)]
759 raise RuntimeError('No scope implemented for the node %r' % tree
)
761 with self
.in_scope(scope_tp
):
762 for builtin
in self
.builtIns
:
763 self
.addBinding(None, Builtin(builtin
))
764 self
.handleChildren(tree
)
767 self
.checkDeadScopes()
771 '`file_tokens` will be removed in a future version',
775 def deferFunction(self
, callable):
777 Schedule a function handler to be called just before completion.
779 This is used for handling function bodies, which must be deferred
780 because code later in the file might modify the global scope. When
781 `callable` is called, the scope at the time this is called will be
782 restored, however it will contain any new bindings added to it.
784 self
._deferred
.append((callable, self
.scopeStack
[:], self
.offset
))
786 def _run_deferred(self
):
787 orig
= (self
.scopeStack
, self
.offset
)
789 while self
._deferred
:
790 handler
, scope
, offset
= self
._deferred
.popleft()
791 self
.scopeStack
, self
.offset
= scope
, offset
794 self
.scopeStack
, self
.offset
= orig
796 def _in_doctest(self
):
797 return (len(self
.scopeStack
) >= 2 and
798 isinstance(self
.scopeStack
[1], DoctestScope
))
801 def futuresAllowed(self
):
802 if not all(isinstance(scope
, ModuleScope
)
803 for scope
in self
.scopeStack
):
806 return self
.scope
._futures
_allowed
808 @futuresAllowed.setter
809 def futuresAllowed(self
, value
):
810 assert value
is False
811 if isinstance(self
.scope
, ModuleScope
):
812 self
.scope
._futures
_allowed
= False
815 def annotationsFutureEnabled(self
):
816 scope
= self
.scopeStack
[0]
817 if not isinstance(scope
, ModuleScope
):
819 return scope
._annotations
_future
_enabled
821 @annotationsFutureEnabled.setter
822 def annotationsFutureEnabled(self
, value
):
824 assert isinstance(self
.scope
, ModuleScope
)
825 self
.scope
._annotations
_future
_enabled
= True
829 return self
.scopeStack
[-1]
831 @contextlib.contextmanager
832 def in_scope(self
, cls
):
833 self
.scopeStack
.append(cls())
837 self
.deadScopes
.append(self
.scopeStack
.pop())
839 def checkDeadScopes(self
):
841 Look at scopes which have been fully examined and report names in them
842 which were imported but unused.
844 for scope
in self
.deadScopes
:
845 # imports in classes are public members
846 if isinstance(scope
, ClassScope
):
849 if isinstance(scope
, FunctionScope
):
850 for name
, binding
in scope
.unused_assignments():
851 self
.report(messages
.UnusedVariable
, binding
.source
, name
)
852 for name
, binding
in scope
.unused_annotations():
853 self
.report(messages
.UnusedAnnotation
, binding
.source
, name
)
855 all_binding
= scope
.get('__all__')
856 if all_binding
and not isinstance(all_binding
, ExportBinding
):
860 all_names
= set(all_binding
.names
)
862 name
for name
in all_binding
.names
866 all_names
= undefined
= []
869 if not scope
.importStarred
and \
870 os
.path
.basename(self
.filename
) != '__init__.py':
871 # Look for possible mistakes in the export list
872 for name
in undefined
:
873 self
.report(messages
.UndefinedExport
,
874 scope
['__all__'].source
, name
)
876 # mark all import '*' as used by the undefined in __all__
877 if scope
.importStarred
:
879 for binding
in scope
.values():
880 if isinstance(binding
, StarImportation
):
881 binding
.used
= all_binding
882 from_list
.append(binding
.fullName
)
883 # report * usage, with a list of possible sources
884 from_list
= ', '.join(sorted(from_list
))
885 for name
in undefined
:
886 self
.report(messages
.ImportStarUsage
,
887 scope
['__all__'].source
, name
, from_list
)
889 # Look for imported names that aren't used.
890 for value
in scope
.values():
891 if isinstance(value
, Importation
):
892 used
= value
.used
or value
.name
in all_names
894 messg
= messages
.UnusedImport
895 self
.report(messg
, value
.source
, str(value
))
896 for node
in value
.redefined
:
897 if isinstance(self
.getParent(node
), FOR_TYPES
):
898 messg
= messages
.ImportShadowedByLoopVar
902 messg
= messages
.RedefinedWhileUnused
903 self
.report(messg
, node
, value
.name
, value
.source
)
905 def report(self
, messageClass
, *args
, **kwargs
):
906 self
.messages
.append(messageClass(self
.filename
, *args
, **kwargs
))
908 def getParent(self
, node
):
909 # Lookup the first parent which is not Tuple, List or Starred
911 node
= node
._pyflakes
_parent
912 if not hasattr(node
, 'elts') and not hasattr(node
, 'ctx'):
915 def getCommonAncestor(self
, lnode
, rnode
, stop
):
917 stop
in (lnode
, rnode
) or
919 hasattr(lnode
, '_pyflakes_parent') and
920 hasattr(rnode
, '_pyflakes_parent')
927 if (lnode
._pyflakes
_depth
> rnode
._pyflakes
_depth
):
928 return self
.getCommonAncestor(lnode
._pyflakes
_parent
, rnode
, stop
)
929 if (lnode
._pyflakes
_depth
< rnode
._pyflakes
_depth
):
930 return self
.getCommonAncestor(lnode
, rnode
._pyflakes
_parent
, stop
)
931 return self
.getCommonAncestor(
932 lnode
._pyflakes
_parent
,
933 rnode
._pyflakes
_parent
,
937 def descendantOf(self
, node
, ancestors
, stop
):
939 if self
.getCommonAncestor(node
, a
, stop
):
943 def _getAncestor(self
, node
, ancestor_type
):
946 if parent
is self
.root
:
948 parent
= self
.getParent(parent
)
949 if isinstance(parent
, ancestor_type
):
952 def getScopeNode(self
, node
):
953 return self
._getAncestor
(node
, tuple(Checker
._ast
_node
_scope
.keys()))
955 def differentForks(self
, lnode
, rnode
):
956 """True, if lnode and rnode are located on different forks of IF/TRY"""
957 ancestor
= self
.getCommonAncestor(lnode
, rnode
, self
.root
)
958 parts
= getAlternatives(ancestor
)
961 if self
.descendantOf(lnode
, items
, ancestor
) ^ \
962 self
.descendantOf(rnode
, items
, ancestor
):
966 def addBinding(self
, node
, value
):
968 Called when a binding is altered.
970 - `node` is the statement responsible for the change
971 - `value` is the new value, a Binding instance
973 # assert value.source in (node, node._pyflakes_parent):
974 for scope
in self
.scopeStack
[::-1]:
975 if value
.name
in scope
:
977 existing
= scope
.get(value
.name
)
979 if (existing
and not isinstance(existing
, Builtin
) and
980 not self
.differentForks(node
, existing
.source
)):
982 parent_stmt
= self
.getParent(value
.source
)
983 if isinstance(existing
, Importation
) and isinstance(parent_stmt
, FOR_TYPES
):
984 self
.report(messages
.ImportShadowedByLoopVar
,
985 node
, value
.name
, existing
.source
)
987 elif scope
is self
.scope
:
989 (not existing
.used
and value
.redefines(existing
)) and
990 (value
.name
!= '_' or isinstance(existing
, Importation
)) and
991 not is_typing_overload(existing
, self
.scopeStack
)
993 self
.report(messages
.RedefinedWhileUnused
,
994 node
, value
.name
, existing
.source
)
996 elif isinstance(existing
, Importation
) and value
.redefines(existing
):
997 existing
.redefined
.append(node
)
999 if value
.name
in self
.scope
:
1000 # then assume the rebound name is used as a global or within a loop
1001 value
.used
= self
.scope
[value
.name
].used
1003 # don't treat annotations as assignments if there is an existing value
1005 if value
.name
not in self
.scope
or not isinstance(value
, Annotation
):
1007 # As per PEP 572, use scope in which outermost generator is defined
1009 isinstance(value
, NamedExprAssignment
) and
1010 isinstance(self
.scopeStack
[cur_scope_pos
], GeneratorScope
)
1013 self
.scopeStack
[cur_scope_pos
][value
.name
] = value
1015 def _unknown_handler(self
, node
):
1016 # this environment variable configures whether to error on unknown
1019 # this is silent by default but the error is enabled for the pyflakes
1022 # this allows new syntax to be added to python without *requiring*
1023 # changes from the pyflakes side. but will still produce an error
1024 # in the pyflakes testsuite (so more specific handling can be added if
1026 if os
.environ
.get('PYFLAKES_ERROR_UNKNOWN'):
1027 raise NotImplementedError(f
'Unexpected type: {type(node)}')
1029 self
.handleChildren(node
)
1031 def getNodeHandler(self
, node_class
):
1033 return self
._nodeHandlers
[node_class
]
1035 nodeType
= node_class
.__name
__.upper()
1036 self
._nodeHandlers
[node_class
] = handler
= getattr(
1037 self
, nodeType
, self
._unknown
_handler
,
1041 def handleNodeLoad(self
, node
, parent
):
1042 name
= getNodeName(node
)
1046 # only the following can access class scoped variables (since classes
1047 # aren't really a scope)
1048 # - direct accesses (not within a nested scope)
1050 # - type annotations (for generics, etc.)
1051 can_access_class_vars
= None
1052 importStarred
= None
1054 # try enclosing function scopes and global scope
1055 for scope
in self
.scopeStack
[-1::-1]:
1056 if isinstance(scope
, ClassScope
):
1057 if name
== '__class__':
1059 elif can_access_class_vars
is False:
1060 # only generators used in a class scope can access the
1061 # names of the class. this is skipped during the first
1065 binding
= scope
.get(name
, None)
1066 if isinstance(binding
, Annotation
) and not self
._in
_postponed
_annotation
:
1067 scope
[name
].used
= (self
.scope
, node
)
1070 if name
== 'print' and isinstance(binding
, Builtin
):
1071 if (isinstance(parent
, ast
.BinOp
) and
1072 isinstance(parent
.op
, ast
.RShift
)):
1073 self
.report(messages
.InvalidPrintSyntax
, node
)
1076 scope
[name
].used
= (self
.scope
, node
)
1078 # if the name of SubImportation is same as
1079 # alias of other Importation and the alias
1080 # is used, SubImportation also should be marked as used.
1082 if isinstance(n
, Importation
) and n
._has
_alias
():
1084 scope
[n
.fullName
].used
= (self
.scope
, node
)
1092 importStarred
= importStarred
or scope
.importStarred
1094 if can_access_class_vars
is not False:
1095 can_access_class_vars
= isinstance(
1096 scope
, (TypeScope
, GeneratorScope
),
1102 for scope
in self
.scopeStack
[-1::-1]:
1103 for binding
in scope
.values():
1104 if isinstance(binding
, StarImportation
):
1105 # mark '*' imports as used for each scope
1106 binding
.used
= (self
.scope
, node
)
1107 from_list
.append(binding
.fullName
)
1109 # report * usage, with a list of possible sources
1110 from_list
= ', '.join(sorted(from_list
))
1111 self
.report(messages
.ImportStarUsage
, node
, name
, from_list
)
1114 if name
== '__path__' and os
.path
.basename(self
.filename
) == '__init__.py':
1115 # the special name __path__ is valid only in packages
1118 if name
in DetectClassScopedMagic
.names
and isinstance(self
.scope
, ClassScope
):
1121 # protected with a NameError handler?
1122 if 'NameError' not in self
.exceptHandlers
[-1]:
1123 self
.report(messages
.UndefinedName
, node
, name
)
1125 def handleNodeStore(self
, node
):
1126 name
= getNodeName(node
)
1129 # if the name hasn't already been defined in the current scope
1130 if isinstance(self
.scope
, FunctionScope
) and name
not in self
.scope
:
1131 # for each function or module scope above us
1132 for scope
in self
.scopeStack
[:-1]:
1133 if not isinstance(scope
, (FunctionScope
, ModuleScope
)):
1135 # if the name was defined in that scope, and the name has
1136 # been accessed already in the current scope, and hasn't
1137 # been declared global
1138 used
= name
in scope
and scope
[name
].used
1139 if used
and used
[0] is self
.scope
and name
not in self
.scope
.globals:
1140 # then it's probably a mistake
1141 self
.report(messages
.UndefinedLocal
,
1142 scope
[name
].used
[1], name
, scope
[name
].source
)
1145 parent_stmt
= self
.getParent(node
)
1146 if isinstance(parent_stmt
, ast
.AnnAssign
) and parent_stmt
.value
is None:
1147 binding
= Annotation(name
, node
)
1148 elif isinstance(parent_stmt
, (FOR_TYPES
, ast
.comprehension
)) or (
1149 parent_stmt
!= node
._pyflakes
_parent
and
1150 not self
.isLiteralTupleUnpacking(parent_stmt
)):
1151 binding
= Binding(name
, node
)
1153 name
== '__all__' and
1154 isinstance(self
.scope
, ModuleScope
) and
1156 node
._pyflakes
_parent
,
1157 (ast
.Assign
, ast
.AugAssign
, ast
.AnnAssign
)
1160 binding
= ExportBinding(name
, node
._pyflakes
_parent
, self
.scope
)
1161 elif isinstance(parent_stmt
, ast
.NamedExpr
):
1162 binding
= NamedExprAssignment(name
, node
)
1164 binding
= Assignment(name
, node
)
1165 self
.addBinding(node
, binding
)
1167 def handleNodeDelete(self
, node
):
1169 def on_conditional_branch():
1171 Return `True` if node is part of a conditional body.
1173 current
= getattr(node
, '_pyflakes_parent', None)
1175 if isinstance(current
, (ast
.If
, ast
.While
, ast
.IfExp
)):
1177 current
= getattr(current
, '_pyflakes_parent', None)
1180 name
= getNodeName(node
)
1184 if on_conditional_branch():
1185 # We cannot predict if this conditional branch is going to
1189 if isinstance(self
.scope
, FunctionScope
) and name
in self
.scope
.globals:
1190 self
.scope
.globals.remove(name
)
1193 del self
.scope
[name
]
1195 self
.report(messages
.UndefinedName
, node
, name
)
1197 @contextlib.contextmanager
1198 def _enter_annotation(self
, ann_type
=AnnotationState
.BARE
):
1199 orig
, self
._in
_annotation
= self
._in
_annotation
, ann_type
1203 self
._in
_annotation
= orig
1206 def _in_postponed_annotation(self
):
1208 self
._in
_annotation
== AnnotationState
.STRING
or
1209 self
.annotationsFutureEnabled
1212 def handleChildren(self
, tree
, omit
=None):
1213 for node
in iter_child_nodes(tree
, omit
=omit
):
1214 self
.handleNode(node
, tree
)
1216 def isLiteralTupleUnpacking(self
, node
):
1217 if isinstance(node
, ast
.Assign
):
1218 for child
in node
.targets
+ [node
.value
]:
1219 if not hasattr(child
, 'elts'):
1223 def isDocstring(self
, node
):
1225 Determine if the given node is a docstring, as long as it is at the
1226 correct place in the node tree.
1229 isinstance(node
, ast
.Expr
) and
1230 isinstance(node
.value
, ast
.Constant
) and
1231 isinstance(node
.value
.value
, str)
1234 def getDocstring(self
, node
):
1236 isinstance(node
, ast
.Expr
) and
1237 isinstance(node
.value
, ast
.Constant
) and
1238 isinstance(node
.value
.value
, str)
1240 return node
.value
.value
, node
.lineno
- 1
1244 def handleNode(self
, node
, parent
):
1247 if self
.offset
and getattr(node
, 'lineno', None) is not None:
1248 node
.lineno
+= self
.offset
[0]
1249 node
.col_offset
+= self
.offset
[1]
1251 self
.futuresAllowed
and
1252 self
.nodeDepth
== 0 and
1253 not isinstance(node
, ast
.ImportFrom
) and
1254 not self
.isDocstring(node
)
1256 self
.futuresAllowed
= False
1258 node
._pyflakes
_depth
= self
.nodeDepth
1259 node
._pyflakes
_parent
= parent
1261 handler
= self
.getNodeHandler(node
.__class
__)
1266 _getDoctestExamples
= doctest
.DocTestParser().get_examples
1268 def handleDoctests(self
, node
):
1270 (docstring
, node_lineno
) = self
.getDocstring(node
.body
[0])
1271 examples
= docstring
and self
._getDoctestExamples
(docstring
)
1272 except (ValueError, IndexError):
1273 # e.g. line 6 of the docstring for <string> has inconsistent
1274 # leading whitespace: ...
1279 # Place doctest in module scope
1280 saved_stack
= self
.scopeStack
1281 self
.scopeStack
= [self
.scopeStack
[0]]
1282 node_offset
= self
.offset
or (0, 0)
1283 with self
.in_scope(DoctestScope
):
1284 if '_' not in self
.scopeStack
[0]:
1285 self
.addBinding(None, Builtin('_'))
1286 for example
in examples
:
1288 tree
= ast
.parse(example
.source
, "<doctest>")
1289 except SyntaxError as e
:
1290 position
= (node_lineno
+ example
.lineno
+ e
.lineno
,
1291 example
.indent
+ 4 + (e
.offset
or 0))
1292 self
.report(messages
.DoctestSyntaxError
, node
, position
)
1294 self
.offset
= (node_offset
[0] + node_lineno
+ example
.lineno
,
1295 node_offset
[1] + example
.indent
+ 4)
1296 self
.handleChildren(tree
)
1297 self
.offset
= node_offset
1298 self
.scopeStack
= saved_stack
1300 @in_string_annotation
1301 def handleStringAnnotation(self
, s
, node
, ref_lineno
, ref_col_offset
, err
):
1305 self
.report(err
, node
, s
)
1309 if len(body
) != 1 or not isinstance(body
[0], ast
.Expr
):
1310 self
.report(err
, node
, s
)
1313 parsed_annotation
= tree
.body
[0].value
1314 for descendant
in ast
.walk(parsed_annotation
):
1316 'lineno' in descendant
._attributes
and
1317 'col_offset' in descendant
._attributes
1319 descendant
.lineno
= ref_lineno
1320 descendant
.col_offset
= ref_col_offset
1322 self
.handleNode(parsed_annotation
, node
)
1324 def handle_annotation_always_deferred(self
, annotation
, parent
):
1325 fn
= in_annotation(Checker
.handleNode
)
1326 self
.deferFunction(lambda: fn(self
, annotation
, parent
))
1329 def handleAnnotation(self
, annotation
, node
):
1331 isinstance(annotation
, ast
.Constant
) and
1332 isinstance(annotation
.value
, str)
1334 # Defer handling forward annotation.
1335 self
.deferFunction(functools
.partial(
1336 self
.handleStringAnnotation
,
1340 annotation
.col_offset
,
1341 messages
.ForwardAnnotationSyntaxError
,
1343 elif self
.annotationsFutureEnabled
:
1344 self
.handle_annotation_always_deferred(annotation
, node
)
1346 self
.handleNode(annotation
, node
)
1348 def ignore(self
, node
):
1352 DELETE
= FOR
= ASYNCFOR
= WHILE
= WITH
= WITHITEM
= ASYNCWITH
= \
1353 EXPR
= ASSIGN
= handleChildren
1358 BOOLOP
= UNARYOP
= SET
= ATTRIBUTE
= STARRED
= NAMECONSTANT
= \
1359 NAMEDEXPR
= handleChildren
1361 def SUBSCRIPT(self
, node
):
1362 if _is_name_or_attr(node
.value
, 'Literal'):
1363 with self
._enter
_annotation
(AnnotationState
.NONE
):
1364 self
.handleChildren(node
)
1365 elif _is_name_or_attr(node
.value
, 'Annotated'):
1366 self
.handleNode(node
.value
, node
)
1369 if isinstance(node
.slice, ast
.Tuple
):
1370 slice_tuple
= node
.slice
1373 isinstance(node
.slice, ast
.Index
) and
1374 isinstance(node
.slice.value
, ast
.Tuple
)
1376 slice_tuple
= node
.slice.value
1380 # not a multi-arg `Annotated`
1381 if slice_tuple
is None or len(slice_tuple
.elts
) < 2:
1382 self
.handleNode(node
.slice, node
)
1384 # the first argument is the type
1385 self
.handleNode(slice_tuple
.elts
[0], node
)
1386 # the rest of the arguments are not
1387 with self
._enter
_annotation
(AnnotationState
.NONE
):
1388 for arg
in slice_tuple
.elts
[1:]:
1389 self
.handleNode(arg
, node
)
1391 self
.handleNode(node
.ctx
, node
)
1393 if _is_any_typing_member(node
.value
, self
.scopeStack
):
1394 with self
._enter
_annotation
():
1395 self
.handleChildren(node
)
1397 self
.handleChildren(node
)
1399 def _handle_string_dot_format(self
, node
):
1401 placeholders
= tuple(parse_format_string(node
.func
.value
.value
))
1402 except ValueError as e
:
1403 self
.report(messages
.StringDotFormatInvalidFormat
, node
, e
)
1409 placeholder_positional
= set()
1410 placeholder_named
= set()
1412 def _add_key(fmtkey
):
1413 """Returns True if there is an error which should early-exit"""
1414 nonlocal auto
, next_auto
1416 if fmtkey
is None: # end of string or `{` / `}` escapes
1419 # attributes / indices are allowed in `.format(...)`
1420 fmtkey
, _
, _
= fmtkey
.partition('.')
1421 fmtkey
, _
, _
= fmtkey
.partition('[')
1424 fmtkey
= int(fmtkey
)
1427 else: # fmtkey was an integer
1429 self
.report(messages
.StringDotFormatMixingAutomatic
, node
)
1436 self
.report(messages
.StringDotFormatMixingAutomatic
, node
)
1444 if isinstance(fmtkey
, int):
1445 placeholder_positional
.add(fmtkey
)
1447 placeholder_named
.add(fmtkey
)
1451 for _
, fmtkey
, spec
, _
in placeholders
:
1452 if _add_key(fmtkey
):
1455 # spec can also contain format specifiers
1456 if spec
is not None:
1458 spec_placeholders
= tuple(parse_format_string(spec
))
1459 except ValueError as e
:
1460 self
.report(messages
.StringDotFormatInvalidFormat
, node
, e
)
1463 for _
, spec_fmtkey
, spec_spec
, _
in spec_placeholders
:
1464 # can't recurse again
1465 if spec_spec
is not None and '{' in spec_spec
:
1467 messages
.StringDotFormatInvalidFormat
,
1469 'Max string recursion exceeded',
1472 if _add_key(spec_fmtkey
):
1475 # bail early if there is *args or **kwargs
1478 any(isinstance(arg
, ast
.Starred
) for arg
in node
.args
) or
1480 any(kwd
.arg
is None for kwd
in node
.keywords
)
1484 substitution_positional
= set(range(len(node
.args
)))
1485 substitution_named
= {kwd
.arg
for kwd
in node
.keywords
}
1487 extra_positional
= substitution_positional
- placeholder_positional
1488 extra_named
= substitution_named
- placeholder_named
1490 missing_arguments
= (
1491 (placeholder_positional | placeholder_named
) -
1492 (substitution_positional | substitution_named
)
1495 if extra_positional
:
1497 messages
.StringDotFormatExtraPositionalArguments
,
1499 ', '.join(sorted(str(x
) for x
in extra_positional
)),
1503 messages
.StringDotFormatExtraNamedArguments
,
1505 ', '.join(sorted(extra_named
)),
1507 if missing_arguments
:
1509 messages
.StringDotFormatMissingArgument
,
1511 ', '.join(sorted(str(x
) for x
in missing_arguments
)),
1514 def CALL(self
, node
):
1516 isinstance(node
.func
, ast
.Attribute
) and
1517 isinstance(node
.func
.value
, ast
.Constant
) and
1518 isinstance(node
.func
.value
.value
, str) and
1519 node
.func
.attr
== 'format'
1521 self
._handle
_string
_dot
_format
(node
)
1528 _is_typing(node
.func
, 'cast', self
.scopeStack
) and
1531 with self
._enter
_annotation
():
1532 self
.handleNode(node
.args
[0], node
)
1534 elif _is_typing(node
.func
, 'TypeVar', self
.scopeStack
):
1536 # TypeVar("T", "int", "str")
1538 annotated
+= [arg
for arg
in node
.args
[1:]]
1540 # TypeVar("T", bound="str")
1541 omit
+= ["keywords"]
1542 annotated
+= [k
.value
for k
in node
.keywords
if k
.arg
== "bound"]
1544 (k
, ["value"] if k
.arg
== "bound" else None)
1545 for k
in node
.keywords
1548 elif _is_typing(node
.func
, "TypedDict", self
.scopeStack
):
1549 # TypedDict("a", {"a": int})
1550 if len(node
.args
) > 1 and isinstance(node
.args
[1], ast
.Dict
):
1552 annotated
+= node
.args
[1].values
1554 (arg
, ["values"] if i
== 1 else None)
1555 for i
, arg
in enumerate(node
.args
)
1558 # TypedDict("a", a=int)
1559 omit
+= ["keywords"]
1560 annotated
+= [k
.value
for k
in node
.keywords
]
1561 not_annotated
+= [(k
, ["value"]) for k
in node
.keywords
]
1563 elif _is_typing(node
.func
, "NamedTuple", self
.scopeStack
):
1564 # NamedTuple("a", [("a", int)])
1566 len(node
.args
) > 1 and
1567 isinstance(node
.args
[1], (ast
.Tuple
, ast
.List
)) and
1568 all(isinstance(x
, (ast
.Tuple
, ast
.List
)) and
1569 len(x
.elts
) == 2 for x
in node
.args
[1].elts
)
1572 annotated
+= [elt
.elts
[1] for elt
in node
.args
[1].elts
]
1573 not_annotated
+= [(elt
.elts
[0], None) for elt
in node
.args
[1].elts
]
1575 (arg
, ["elts"] if i
== 1 else None)
1576 for i
, arg
in enumerate(node
.args
)
1578 not_annotated
+= [(elt
, "elts") for elt
in node
.args
[1].elts
]
1580 # NamedTuple("a", a=int)
1581 omit
+= ["keywords"]
1582 annotated
+= [k
.value
for k
in node
.keywords
]
1583 not_annotated
+= [(k
, ["value"]) for k
in node
.keywords
]
1586 with self
._enter
_annotation
(AnnotationState
.NONE
):
1587 for na_node
, na_omit
in not_annotated
:
1588 self
.handleChildren(na_node
, omit
=na_omit
)
1589 self
.handleChildren(node
, omit
=omit
)
1591 with self
._enter
_annotation
():
1592 for annotated_node
in annotated
:
1593 self
.handleNode(annotated_node
, node
)
1595 self
.handleChildren(node
)
1597 def _handle_percent_format(self
, node
):
1599 placeholders
= parse_percent_format(node
.left
.value
)
1602 messages
.PercentFormatInvalidFormat
,
1604 'incomplete format',
1609 positional_count
= 0
1611 for _
, placeholder
in placeholders
:
1612 if placeholder
is None:
1614 name
, _
, width
, precision
, conversion
= placeholder
1616 if conversion
== '%':
1619 if conversion
not in VALID_CONVERSIONS
:
1621 messages
.PercentFormatUnsupportedFormatCharacter
,
1626 if positional
is None and conversion
:
1627 positional
= name
is None
1629 for part
in (width
, precision
):
1630 if part
is not None and '*' in part
:
1633 messages
.PercentFormatStarRequiresSequence
,
1637 positional_count
+= 1
1639 if positional
and name
is not None:
1641 messages
.PercentFormatMixedPositionalAndNamed
,
1645 elif not positional
and name
is None:
1647 messages
.PercentFormatMixedPositionalAndNamed
,
1653 positional_count
+= 1
1658 isinstance(node
.right
, (ast
.List
, ast
.Tuple
)) and
1659 # does not have any *splats (py35+ feature)
1661 isinstance(elt
, ast
.Starred
)
1662 for elt
in node
.right
.elts
1665 substitution_count
= len(node
.right
.elts
)
1666 if positional
and positional_count
!= substitution_count
:
1668 messages
.PercentFormatPositionalCountMismatch
,
1673 elif not positional
:
1674 self
.report(messages
.PercentFormatExpectedMapping
, node
)
1677 isinstance(node
.right
, ast
.Dict
) and
1679 isinstance(k
, ast
.Constant
) and isinstance(k
.value
, str)
1680 for k
in node
.right
.keys
1683 if positional
and positional_count
> 1:
1684 self
.report(messages
.PercentFormatExpectedSequence
, node
)
1687 substitution_keys
= {k
.value
for k
in node
.right
.keys
}
1688 extra_keys
= substitution_keys
- named
1689 missing_keys
= named
- substitution_keys
1690 if not positional
and extra_keys
:
1692 messages
.PercentFormatExtraNamedArguments
,
1694 ', '.join(sorted(extra_keys
)),
1696 if not positional
and missing_keys
:
1698 messages
.PercentFormatMissingArgument
,
1700 ', '.join(sorted(missing_keys
)),
1703 def BINOP(self
, node
):
1705 isinstance(node
.op
, ast
.Mod
) and
1706 isinstance(node
.left
, ast
.Constant
) and
1707 isinstance(node
.left
.value
, str)
1709 self
._handle
_percent
_format
(node
)
1710 self
.handleChildren(node
)
1712 def CONSTANT(self
, node
):
1713 if isinstance(node
.value
, str) and self
._in
_annotation
:
1714 fn
= functools
.partial(
1715 self
.handleStringAnnotation
,
1720 messages
.ForwardAnnotationSyntaxError
,
1722 self
.deferFunction(fn
)
1724 # "slice" type nodes
1725 SLICE
= EXTSLICE
= INDEX
= handleChildren
1727 # expression contexts are node instances too, though being constants
1728 LOAD
= STORE
= DEL
= AUGLOAD
= AUGSTORE
= PARAM
= ignore
1730 # same for operators
1731 AND
= OR
= ADD
= SUB
= MULT
= DIV
= MOD
= POW
= LSHIFT
= RSHIFT
= \
1732 BITOR
= BITXOR
= BITAND
= FLOORDIV
= INVERT
= NOT
= UADD
= USUB
= \
1733 EQ
= NOTEQ
= LT
= LTE
= GT
= GTE
= IS
= ISNOT
= IN
= NOTIN
= \
1736 def RAISE(self
, node
):
1737 self
.handleChildren(node
)
1741 if isinstance(arg
, ast
.Call
):
1742 if is_notimplemented_name_node(arg
.func
):
1743 # Handle "raise NotImplemented(...)"
1744 self
.report(messages
.RaiseNotImplemented
, node
)
1745 elif is_notimplemented_name_node(arg
):
1746 # Handle "raise NotImplemented"
1747 self
.report(messages
.RaiseNotImplemented
, node
)
1749 # additional node types
1750 COMPREHENSION
= KEYWORD
= FORMATTEDVALUE
= handleChildren
1754 def JOINEDSTR(self
, node
):
1756 # the conversion / etc. flags are parsed as f-strings without
1758 not self
._in
_fstring
and
1759 not any(isinstance(x
, ast
.FormattedValue
) for x
in node
.values
)
1761 self
.report(messages
.FStringMissingPlaceholders
, node
)
1763 self
._in
_fstring
, orig
= True, self
._in
_fstring
1765 self
.handleChildren(node
)
1767 self
._in
_fstring
= orig
1769 def DICT(self
, node
):
1770 # Complain if there are duplicate keys with different values
1771 # If they have the same value it's not going to cause potentially
1772 # unexpected behaviour so we'll not complain.
1774 convert_to_value(key
) for key
in node
.keys
1777 key_counts
= counter(keys
)
1779 key
for key
, count
in key_counts
.items()
1783 for key
in duplicate_keys
:
1784 key_indices
= [i
for i
, i_key
in enumerate(keys
) if i_key
== key
]
1787 convert_to_value(node
.values
[index
])
1788 for index
in key_indices
1790 if any(count
== 1 for value
, count
in values
.items()):
1791 for key_index
in key_indices
:
1792 key_node
= node
.keys
[key_index
]
1793 if isinstance(key
, VariableKey
):
1794 self
.report(messages
.MultiValueRepeatedKeyVariable
,
1799 messages
.MultiValueRepeatedKeyLiteral
,
1803 self
.handleChildren(node
)
1806 if isinstance(node
.test
, ast
.Tuple
) and node
.test
.elts
!= []:
1807 self
.report(messages
.IfTuple
, node
)
1808 self
.handleChildren(node
)
1812 def ASSERT(self
, node
):
1813 if isinstance(node
.test
, ast
.Tuple
) and node
.test
.elts
!= []:
1814 self
.report(messages
.AssertTuple
, node
)
1815 self
.handleChildren(node
)
1817 def GLOBAL(self
, node
):
1819 Keep track of globals declarations.
1821 global_scope_index
= 1 if self
._in
_doctest
() else 0
1822 global_scope
= self
.scopeStack
[global_scope_index
]
1824 # Ignore 'global' statement in global scope.
1825 if self
.scope
is not global_scope
:
1827 # One 'global' statement can bind multiple (comma-delimited) names.
1828 for node_name
in node
.names
:
1829 node_value
= Assignment(node_name
, node
)
1831 # Remove UndefinedName messages already reported for this name.
1832 # TODO: if the global is not used in this scope, it does not
1833 # become a globally defined name. See test_unused_global.
1835 m
for m
in self
.messages
if not
1836 isinstance(m
, messages
.UndefinedName
) or
1837 m
.message_args
[0] != node_name
]
1839 # Bind name to global scope if it doesn't exist already.
1840 global_scope
.setdefault(node_name
, node_value
)
1842 # Bind name to non-global scopes, but as already "used".
1843 node_value
.used
= (global_scope
, node
)
1844 for scope
in self
.scopeStack
[global_scope_index
+ 1:]:
1845 scope
[node_name
] = node_value
1849 def GENERATOREXP(self
, node
):
1850 with self
.in_scope(GeneratorScope
):
1851 self
.handleChildren(node
)
1853 LISTCOMP
= DICTCOMP
= SETCOMP
= GENERATOREXP
1855 def NAME(self
, node
):
1857 Handle occurrence of Name (which can be a load/store/delete access.)
1859 # Locate the name in locals / function / globals scopes.
1860 if isinstance(node
.ctx
, ast
.Load
):
1861 self
.handleNodeLoad(node
, self
.getParent(node
))
1862 if (node
.id == 'locals' and isinstance(self
.scope
, FunctionScope
) and
1863 isinstance(node
._pyflakes
_parent
, ast
.Call
)):
1864 # we are doing locals() call in current scope
1865 self
.scope
.usesLocals
= True
1866 elif isinstance(node
.ctx
, ast
.Store
):
1867 self
.handleNodeStore(node
)
1868 elif isinstance(node
.ctx
, ast
.Del
):
1869 self
.handleNodeDelete(node
)
1872 raise RuntimeError(f
"Got impossible expression context: {node.ctx!r}")
1874 def CONTINUE(self
, node
):
1875 # Walk the tree up until we see a loop (OK), a function or class
1876 # definition (not OK), for 'continue', a finally block (not OK), or
1877 # the top module scope (not OK)
1879 while hasattr(n
, '_pyflakes_parent'):
1880 n
, n_child
= n
._pyflakes
_parent
, n
1881 if isinstance(n
, (ast
.While
, ast
.For
, ast
.AsyncFor
)):
1882 # Doesn't apply unless it's in the loop itself
1883 if n_child
not in n
.orelse
:
1885 if isinstance(n
, (ast
.FunctionDef
, ast
.ClassDef
)):
1887 if isinstance(node
, ast
.Continue
):
1888 self
.report(messages
.ContinueOutsideLoop
, node
)
1890 self
.report(messages
.BreakOutsideLoop
, node
)
1894 def RETURN(self
, node
):
1895 if isinstance(self
.scope
, (ClassScope
, ModuleScope
)):
1896 self
.report(messages
.ReturnOutsideFunction
, node
)
1901 hasattr(self
.scope
, 'returnValue') and
1902 not self
.scope
.returnValue
1904 self
.scope
.returnValue
= node
.value
1905 self
.handleNode(node
.value
, node
)
1907 def YIELD(self
, node
):
1908 if isinstance(self
.scope
, (ClassScope
, ModuleScope
)):
1909 self
.report(messages
.YieldOutsideFunction
, node
)
1912 self
.handleNode(node
.value
, node
)
1914 AWAIT
= YIELDFROM
= YIELD
1916 def FUNCTIONDEF(self
, node
):
1917 for deco
in node
.decorator_list
:
1918 self
.handleNode(deco
, node
)
1920 with self
._type
_param
_scope
(node
):
1923 self
.addBinding(node
, FunctionDefinition(node
.name
, node
))
1924 # doctest does not process doctest within a doctest,
1925 # or in nested functions.
1926 if (self
.withDoctest
and
1927 not self
._in
_doctest
() and
1928 not isinstance(self
.scope
, FunctionScope
)):
1929 self
.deferFunction(lambda: self
.handleDoctests(node
))
1931 ASYNCFUNCTIONDEF
= FUNCTIONDEF
1933 def LAMBDA(self
, node
):
1937 for arg
in node
.args
.posonlyargs
:
1938 args
.append(arg
.arg
)
1939 annotations
.append(arg
.annotation
)
1940 for arg
in node
.args
.args
+ node
.args
.kwonlyargs
:
1941 args
.append(arg
.arg
)
1942 annotations
.append(arg
.annotation
)
1943 defaults
= node
.args
.defaults
+ node
.args
.kw_defaults
1945 has_annotations
= not isinstance(node
, ast
.Lambda
)
1947 for arg_name
in ('vararg', 'kwarg'):
1948 wildcard
= getattr(node
.args
, arg_name
)
1951 args
.append(wildcard
.arg
)
1953 annotations
.append(wildcard
.annotation
)
1956 annotations
.append(node
.returns
)
1958 if len(set(args
)) < len(args
):
1959 for (idx
, arg
) in enumerate(args
):
1960 if arg
in args
[:idx
]:
1961 self
.report(messages
.DuplicateArgument
, node
, arg
)
1963 for annotation
in annotations
:
1964 self
.handleAnnotation(annotation
, node
)
1966 for default
in defaults
:
1967 self
.handleNode(default
, node
)
1970 with self
.in_scope(FunctionScope
):
1971 self
.handleChildren(
1973 omit
=('decorator_list', 'returns', 'type_params'),
1976 self
.deferFunction(runFunction
)
1978 def ARGUMENTS(self
, node
):
1979 self
.handleChildren(node
, omit
=('defaults', 'kw_defaults'))
1981 def ARG(self
, node
):
1982 self
.addBinding(node
, Argument(node
.arg
, self
.getScopeNode(node
)))
1984 def CLASSDEF(self
, node
):
1986 Check names used in a class definition, including its decorators, base
1987 classes, and the body of its definition. Additionally, add its name to
1990 for deco
in node
.decorator_list
:
1991 self
.handleNode(deco
, node
)
1993 with self
._type
_param
_scope
(node
):
1994 for baseNode
in node
.bases
:
1995 self
.handleNode(baseNode
, node
)
1996 for keywordNode
in node
.keywords
:
1997 self
.handleNode(keywordNode
, node
)
1998 with self
.in_scope(ClassScope
):
1999 # doctest does not process doctest within a doctest
2000 # classes within classes are processed.
2001 if (self
.withDoctest
and
2002 not self
._in
_doctest
() and
2003 not isinstance(self
.scope
, FunctionScope
)):
2004 self
.deferFunction(lambda: self
.handleDoctests(node
))
2005 for stmt
in node
.body
:
2006 self
.handleNode(stmt
, node
)
2008 self
.addBinding(node
, ClassDefinition(node
.name
, node
))
2010 def AUGASSIGN(self
, node
):
2011 self
.handleNodeLoad(node
.target
, node
)
2012 self
.handleNode(node
.value
, node
)
2013 self
.handleNode(node
.target
, node
)
2015 def TUPLE(self
, node
):
2016 if isinstance(node
.ctx
, ast
.Store
):
2017 # Python 3 advanced tuple unpacking: a, *b, c = d.
2018 # Only one starred expression is allowed, and no more than 1<<8
2019 # assignments are allowed before a stared expression. There is
2020 # also a limit of 1<<24 expressions after the starred expression,
2021 # which is impossible to test due to memory restrictions, but we
2022 # add it here anyway
2025 for i
, n
in enumerate(node
.elts
):
2026 if isinstance(n
, ast
.Starred
):
2028 self
.report(messages
.TwoStarredExpressions
, node
)
2029 # The SyntaxError doesn't distinguish two from more
2034 if star_loc
>= 1 << 8 or len(node
.elts
) - star_loc
- 1 >= 1 << 24:
2035 self
.report(messages
.TooManyExpressionsInStarredAssignment
, node
)
2036 self
.handleChildren(node
)
2040 def IMPORT(self
, node
):
2041 for alias
in node
.names
:
2042 if '.' in alias
.name
and not alias
.asname
:
2043 importation
= SubmoduleImportation(alias
.name
, node
)
2045 name
= alias
.asname
or alias
.name
2046 importation
= Importation(name
, node
, alias
.name
)
2047 self
.addBinding(node
, importation
)
2049 def IMPORTFROM(self
, node
):
2050 if node
.module
== '__future__':
2051 if not self
.futuresAllowed
:
2052 self
.report(messages
.LateFutureImport
, node
)
2054 self
.futuresAllowed
= False
2056 module
= ('.' * node
.level
) + (node
.module
or '')
2058 for alias
in node
.names
:
2059 name
= alias
.asname
or alias
.name
2060 if node
.module
== '__future__':
2061 importation
= FutureImportation(name
, node
, self
.scope
)
2062 if alias
.name
not in __future__
.all_feature_names
:
2063 self
.report(messages
.FutureFeatureNotDefined
,
2065 if alias
.name
== 'annotations':
2066 self
.annotationsFutureEnabled
= True
2067 elif alias
.name
== '*':
2068 if not isinstance(self
.scope
, ModuleScope
):
2069 self
.report(messages
.ImportStarNotPermitted
,
2073 self
.scope
.importStarred
= True
2074 self
.report(messages
.ImportStarUsed
, node
, module
)
2075 importation
= StarImportation(module
, node
)
2077 importation
= ImportationFrom(name
, node
,
2079 self
.addBinding(node
, importation
)
2081 def TRY(self
, node
):
2083 # List the exception handlers
2084 for i
, handler
in enumerate(node
.handlers
):
2085 if isinstance(handler
.type, ast
.Tuple
):
2086 for exc_type
in handler
.type.elts
:
2087 handler_names
.append(getNodeName(exc_type
))
2089 handler_names
.append(getNodeName(handler
.type))
2091 if handler
.type is None and i
< len(node
.handlers
) - 1:
2092 self
.report(messages
.DefaultExceptNotLast
, handler
)
2093 # Memorize the except handlers and process the body
2094 self
.exceptHandlers
.append(handler_names
)
2095 for child
in node
.body
:
2096 self
.handleNode(child
, node
)
2097 self
.exceptHandlers
.pop()
2098 # Process the other nodes: "except:", "else:", "finally:"
2099 self
.handleChildren(node
, omit
='body')
2103 def EXCEPTHANDLER(self
, node
):
2104 if node
.name
is None:
2105 self
.handleChildren(node
)
2108 # If the name already exists in the scope, modify state of existing
2110 if node
.name
in self
.scope
:
2111 self
.handleNodeStore(node
)
2113 # 3.x: the name of the exception, which is not a Name node, but a
2114 # simple string, creates a local that is only bound within the scope of
2115 # the except: block. As such, temporarily remove the existing binding
2116 # to more accurately determine if the name is used in the except:
2120 prev_definition
= self
.scope
.pop(node
.name
)
2122 prev_definition
= None
2124 self
.handleNodeStore(node
)
2125 self
.handleChildren(node
)
2127 # See discussion on https://github.com/PyCQA/pyflakes/pull/59
2129 # We're removing the local name since it's being unbound after leaving
2130 # the except: block and it's always unbound if the except: block is
2131 # never entered. This will cause an "undefined name" error raised if
2132 # the checked code tries to use the name afterwards.
2134 # Unless it's been removed already. Then do nothing.
2137 binding
= self
.scope
.pop(node
.name
)
2141 if not binding
.used
:
2142 self
.report(messages
.UnusedVariable
, node
, node
.name
)
2146 self
.scope
[node
.name
] = prev_definition
2148 def ANNASSIGN(self
, node
):
2149 self
.handleAnnotation(node
.annotation
, node
)
2150 # If the assignment has value, handle the *value* now.
2152 # If the annotation is `TypeAlias`, handle the *value* as an annotation.
2153 if _is_typing(node
.annotation
, 'TypeAlias', self
.scopeStack
):
2154 self
.handleAnnotation(node
.value
, node
)
2156 self
.handleNode(node
.value
, node
)
2157 self
.handleNode(node
.target
, node
)
2159 def COMPARE(self
, node
):
2161 for op
, right
in zip(node
.ops
, node
.comparators
):
2163 isinstance(op
, (ast
.Is
, ast
.IsNot
)) and (
2164 _is_const_non_singleton(left
) or
2165 _is_const_non_singleton(right
)
2168 self
.report(messages
.IsLiteral
, node
)
2171 self
.handleChildren(node
)
2173 MATCH
= MATCH_CASE
= MATCHCLASS
= MATCHOR
= MATCHSEQUENCE
= handleChildren
2174 MATCHSINGLETON
= MATCHVALUE
= handleChildren
2176 def _match_target(self
, node
):
2177 self
.handleNodeStore(node
)
2178 self
.handleChildren(node
)
2180 MATCHAS
= MATCHMAPPING
= MATCHSTAR
= _match_target
2182 @contextlib.contextmanager
2183 def _type_param_scope(self
, node
):
2184 with contextlib
.ExitStack() as ctx
:
2185 if sys
.version_info
>= (3, 12):
2186 ctx
.enter_context(self
.in_scope(TypeScope
))
2187 for param
in node
.type_params
:
2188 self
.handleNode(param
, node
)
2191 def TYPEVAR(self
, node
):
2192 self
.handleNodeStore(node
)
2193 self
.handle_annotation_always_deferred(node
.bound
, node
)
2195 def TYPEALIAS(self
, node
):
2196 self
.handleNode(node
.name
, node
)
2197 with self
._type
_param
_scope
(node
):
2198 self
.handle_annotation_always_deferred(node
.value
, node
)