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

branch
eric7
changeset 9376
e143a7e7254b
parent 9209
b99e7fd55fd3
child 9593
89f885d857e4
--- a/src/eric7/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py	Sat Oct 01 19:42:50 2022 +0200
+++ b/src/eric7/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py	Sat Oct 01 20:06:27 2022 +0200
@@ -12,6 +12,7 @@
 Also, it models the Bindings and Scopes.
 """
 import __future__
+import builtins
 import ast
 import bisect
 import collections
@@ -26,70 +27,22 @@
 
 from . import messages
 
-PY2 = sys.version_info < (3, 0)
-PY35_PLUS = sys.version_info >= (3, 5)    # Python 3.5 and above
-PY36_PLUS = sys.version_info >= (3, 6)    # Python 3.6 and above
 PY38_PLUS = sys.version_info >= (3, 8)
-try:
-    sys.pypy_version_info
-    PYPY = True
-except AttributeError:
-    PYPY = False
+PYPY = hasattr(sys, 'pypy_version_info')
 
-builtin_vars = dir(__import__('__builtin__' if PY2 else 'builtins'))
+builtin_vars = dir(builtins)
 
 parse_format_string = string.Formatter().parse
 
-if PY2:
-    tokenize_tokenize = tokenize.generate_tokens
-else:
-    tokenize_tokenize = tokenize.tokenize
-
-if PY2:
-    def getNodeType(node_class):
-        # workaround str.upper() which is locale-dependent
-        return str(unicode(node_class.__name__).upper())  # __IGNORE_WARNING__
-
-    def get_raise_argument(node):
-        return node.type
-
-else:
-    def getNodeType(node_class):
-        return node_class.__name__.upper()
-
-    def get_raise_argument(node):
-        return node.exc
-
-    # Silence `pyflakes` from reporting `undefined name 'unicode'` in Python 3.
-    unicode = str
 
-# Python >= 3.3 uses ast.Try instead of (ast.TryExcept + ast.TryFinally)
-if PY2:
-    def getAlternatives(n):
-        if isinstance(n, (ast.If, ast.TryFinally)):
-            return [n.body]
-        if isinstance(n, ast.TryExcept):
-            return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
-else:
-    def getAlternatives(n):
-        if isinstance(n, ast.If):
-            return [n.body]
-        if isinstance(n, ast.Try):
-            return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
+def getAlternatives(n):
+    if isinstance(n, ast.If):
+        return [n.body]
+    if isinstance(n, ast.Try):
+        return [n.body + n.orelse] + [[hdl] for hdl in n.handlers]
 
-if PY35_PLUS:
-    FOR_TYPES = (ast.For, ast.AsyncFor)
-    LOOP_TYPES = (ast.While, ast.For, ast.AsyncFor)
-    FUNCTION_TYPES = (ast.FunctionDef, ast.AsyncFunctionDef)
-else:
-    FOR_TYPES = (ast.For,)
-    LOOP_TYPES = (ast.While, ast.For)
-    FUNCTION_TYPES = (ast.FunctionDef,)
 
-if PY36_PLUS:
-    ANNASSIGN_TYPES = (ast.AnnAssign,)
-else:
-    ANNASSIGN_TYPES = ()
+FOR_TYPES = (ast.For, ast.AsyncFor)
 
 if PY38_PLUS:
     def _is_singleton(node):  # type: (ast.AST) -> bool
@@ -97,15 +50,9 @@
             isinstance(node, ast.Constant) and
             isinstance(node.value, (bool, type(Ellipsis), type(None)))
         )
-elif not PY2:
-    def _is_singleton(node):  # type: (ast.AST) -> bool
-        return isinstance(node, (ast.NameConstant, ast.Ellipsis))
 else:
     def _is_singleton(node):  # type: (ast.AST) -> bool
-        return (
-            isinstance(node, ast.Name) and
-            node.id in {'True', 'False', 'Ellipsis', 'None'}
-        )
+        return isinstance(node, (ast.NameConstant, ast.Ellipsis))
 
 
 def _is_tuple_constant(node):  # type: (ast.AST) -> bool
@@ -119,13 +66,9 @@
     def _is_constant(node):
         return isinstance(node, ast.Constant) or _is_tuple_constant(node)
 else:
-    _const_tps = (ast.Str, ast.Num)
-    if not PY2:
-        _const_tps += (ast.Bytes,)
-
     def _is_constant(node):
         return (
-            isinstance(node, _const_tps) or
+            isinstance(node, (ast.Str, ast.Num, ast.Bytes)) or
             _is_singleton(node) or
             _is_tuple_constant(node)
         )
@@ -135,7 +78,7 @@
     return _is_constant(node) and not _is_singleton(node)
 
 
-def _is_name_or_attr(node, name):  # type: (ast.Ast, str) -> bool
+def _is_name_or_attr(node, name):  # type: (ast.AST, str) -> bool
     return (
         (isinstance(node, ast.Name) and node.id == name) or
         (isinstance(node, ast.Attribute) and node.attr == name)
@@ -147,7 +90,7 @@
 # https://github.com/python/typed_ast/blob/1.4.0/ast27/Parser/tokenizer.c#L1408-L1413
 ASCII_NON_ALNUM = ''.join([chr(i) for i in range(128) if not chr(i).isalnum()])
 TYPE_IGNORE_RE = re.compile(
-    TYPE_COMMENT_RE.pattern + r'ignore([{}]|$)'.format(ASCII_NON_ALNUM))
+    TYPE_COMMENT_RE.pattern + fr'ignore([{ASCII_NON_ALNUM}]|$)')
 # https://github.com/python/typed_ast/blob/1.4.0/ast27/Grammar/Grammar#L147
 TYPE_FUNC_RE = re.compile(r'^(\(.*?\))\s*->\s*(.*)$')
 
@@ -162,20 +105,18 @@
 
 
 def _must_match(regex, string, pos):
-    # type: (Pattern[str], str, int) -> Match[str]
     match = regex.match(string, pos)
     assert match is not None
     return match
 
 
-def parse_percent_format(s):  # type: (str) -> Tuple[PercentFormat, ...]
+def parse_percent_format(s):
     """Parses the string component of a `'...' % ...` format call
 
     Copied from https://github.com/asottile/pyupgrade at v1.20.1
     """
 
     def _parse_inner():
-        # type: () -> Generator[PercentFormat, None, None]
         string_start = 0
         string_end = 0
         in_fmt = False
@@ -195,7 +136,7 @@
             else:
                 key_match = MAPPING_KEY_RE.match(s, i)
                 if key_match:
-                    key = key_match.group(1)  # type: Optional[str]
+                    key = key_match.group(1)
                     i = key_match.end()
                 else:
                     key = None
@@ -306,8 +247,7 @@
             result.name,
             result,
         )
-    elif (not PY2) and isinstance(item, ast.NameConstant):
-        # None, True, False are nameconstants in python3, but names in 2
+    elif isinstance(item, ast.NameConstant):
         return item.value
     else:
         return UnhandledKeyType()
@@ -317,7 +257,7 @@
     return isinstance(node, ast.Name) and getNodeName(node) == 'NotImplemented'
 
 
-class Binding(object):
+class Binding:
     """
     Represents the binding of a value to a name.
 
@@ -338,10 +278,12 @@
         return self.name
 
     def __repr__(self):
-        return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
-                                                        self.name,
-                                                        self.source.lineno,
-                                                        id(self))
+        return '<{} object {!r} from line {!r} at 0x{:x}>'.format(
+            self.__class__.__name__,
+            self.name,
+            self.source.lineno,
+            id(self),
+        )
 
     def redefines(self, other):
         return isinstance(other, Definition) and self.name == other.name
@@ -360,18 +302,20 @@
         super().__init__(name, None)
 
     def __repr__(self):
-        return '<%s object %r at 0x%x>' % (self.__class__.__name__,
-                                           self.name,
-                                           id(self))
+        return '<{} object {!r} at 0x{:x}>'.format(
+            self.__class__.__name__,
+            self.name,
+            id(self)
+        )
 
 
-class UnhandledKeyType(object):
+class UnhandledKeyType:
     """
     A dictionary key of a type that we cannot or do not check for duplicates.
     """
 
 
-class VariableKey(object):
+class VariableKey:
     """
     A dictionary key which is a variable.
 
@@ -418,7 +362,7 @@
     def source_statement(self):
         """Generate a source statement equivalent to the import."""
         if self._has_alias():
-            return 'import %s as %s' % (self.fullName, self.name)
+            return f'import {self.fullName} as {self.name}'
         else:
             return 'import %s' % self.fullName
 
@@ -490,11 +434,9 @@
     @property
     def source_statement(self):
         if self.real_name != self.name:
-            return 'from %s import %s as %s' % (self.module,
-                                                self.real_name,
-                                                self.name)
+            return f'from {self.module} import {self.real_name} as {self.name}'
         else:
-            return 'from %s import %s' % (self.module, self.name)
+            return f'from {self.module} import {self.name}'
 
 
 class StarImportation(Importation):
@@ -547,6 +489,12 @@
     """
 
 
+class NamedExprAssignment(Assignment):
+    """
+    Represents binding a name with an assignment expression.
+    """
+
+
 class Annotation(Binding):
     """
     Represents binding a name to a type without an associated value.
@@ -623,7 +571,7 @@
 
     def __repr__(self):
         scope_cls = self.__class__.__name__
-        return '<%s at 0x%x %s>' % (scope_cls, id(self), dict.__repr__(self))
+        return f'<{scope_cls} at 0x{id(self):x} {dict.__repr__(self)}>'
 
 
 class ClassScope(Scope):
@@ -674,7 +622,7 @@
     """Scope for a doctest."""
 
 
-class DummyNode(object):
+class DummyNode:
     """Used in place of an `ast.AST` to set error message positions"""
     def __init__(self, lineno, col_offset):
         self.lineno = lineno
@@ -687,10 +635,7 @@
 
 # Globally defined names which are not attributes of the builtins module, or
 # are only present on some platforms.
-_MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
-# module scope annotation will store in `__annotations__`, see also PEP 526.
-if PY36_PLUS:
-    _MAGIC_GLOBALS.append('__annotations__')
+_MAGIC_GLOBALS = ['__file__', '__builtins__', '__annotations__', 'WindowsError']
 
 
 def getNodeName(node):
@@ -773,7 +718,7 @@
 
 def is_typing_overload(value, scope_stack):
     return (
-        isinstance(value.source, FUNCTION_TYPES) and
+        isinstance(value.source, (ast.FunctionDef, ast.AsyncFunctionDef)) and
         any(
             _is_typing(dec, 'overload', scope_stack)
             for dec in value.source.decorator_list
@@ -809,7 +754,7 @@
         code = code.encode('UTF-8')
     lines = iter(code.splitlines(True))
     # next(lines, b'') is to prevent an error in pypy3
-    return tuple(tokenize_tokenize(lambda: next(lines, b'')))
+    return tuple(tokenize.tokenize(lambda: next(lines, b'')))
 
 
 class _TypeableVisitor(ast.NodeVisitor):
@@ -819,8 +764,8 @@
     https://www.python.org/dev/peps/pep-0484/#type-comments
     """
     def __init__(self):
-        self.typeable_lines = []  # type: List[int]
-        self.typeable_nodes = {}  # type: Dict[int, ast.AST]
+        self.typeable_lines = []
+        self.typeable_nodes = {}
 
     def _typeable(self, node):
         # if there is more than one typeable thing on a line last one wins
@@ -860,7 +805,7 @@
     return type_comments
 
 
-class Checker(object):
+class Checker:
     """
     I check the cleanliness and sanity of Python code.
 
@@ -877,14 +822,13 @@
         ast.Module: ModuleScope,
         ast.ClassDef: ClassScope,
         ast.FunctionDef: FunctionScope,
+        ast.AsyncFunctionDef: FunctionScope,
         ast.Lambda: FunctionScope,
         ast.ListComp: GeneratorScope,
         ast.SetComp: GeneratorScope,
         ast.GeneratorExp: GeneratorScope,
         ast.DictComp: GeneratorScope,
     }
-    if PY35_PLUS:
-        _ast_node_scope[ast.AsyncFunctionDef] = FunctionScope
 
     nodeDepth = 0
     offset = None
@@ -1145,16 +1089,13 @@
                             node, value.name, existing.source)
 
             elif scope is self.scope:
-                if (isinstance(parent_stmt, ast.comprehension) and
-                        not isinstance(self.getParent(existing.source),
-                                       (FOR_TYPES, ast.comprehension))):
-                    self.report(messages.RedefinedInListComp,
+                if (
+                        (not existing.used and value.redefines(existing)) and
+                        (value.name != '_' or isinstance(existing, Importation)) and
+                        not is_typing_overload(existing, self.scopeStack)
+                ):
+                    self.report(messages.RedefinedWhileUnused,
                                 node, value.name, existing.source)
-                elif not existing.used and value.redefines(existing):
-                    if value.name != '_' or isinstance(existing, Importation):
-                        if not is_typing_overload(existing, self.scopeStack):
-                            self.report(messages.RedefinedWhileUnused,
-                                        node, value.name, existing.source)
 
             elif isinstance(existing, Importation) and value.redefines(existing):
                 existing.redefined.append(node)
@@ -1166,7 +1107,14 @@
         # don't treat annotations as assignments if there is an existing value
         # in scope
         if value.name not in self.scope or not isinstance(value, Annotation):
-            self.scope[value.name] = value
+            cur_scope_pos = -1
+            # As per PEP 572, use scope in which outermost generator is defined
+            while (
+                isinstance(value, NamedExprAssignment) and
+                isinstance(self.scopeStack[cur_scope_pos], GeneratorScope)
+            ):
+                cur_scope_pos -= 1
+            self.scopeStack[cur_scope_pos][value.name] = value
 
     def _unknown_handler(self, node):
         # this environment variable configures whether to error on unknown
@@ -1180,7 +1128,7 @@
         # in the pyflakes testsuite (so more specific handling can be added if
         # needed).
         if os.environ.get('PYFLAKES_ERROR_UNKNOWN'):
-            raise NotImplementedError('Unexpected type: {}'.format(type(node)))
+            raise NotImplementedError(f'Unexpected type: {type(node)}')
         else:
             self.handleChildren(node)
 
@@ -1188,7 +1136,7 @@
         try:
             return self._nodeHandlers[node_class]
         except KeyError:
-            nodeType = getNodeType(node_class)
+            nodeType = node_class.__name__.upper()
         self._nodeHandlers[node_class] = handler = getattr(
             self, nodeType, self._unknown_handler,
         )
@@ -1205,7 +1153,7 @@
         # try enclosing function scopes and global scope
         for scope in self.scopeStack[-1::-1]:
             if isinstance(scope, ClassScope):
-                if not PY2 and name == '__class__':
+                if name == '__class__':
                     return
                 elif in_generators is False:
                     # only generators used in a class scope can access the
@@ -1292,16 +1240,23 @@
                     break
 
         parent_stmt = self.getParent(node)
-        if isinstance(parent_stmt, ANNASSIGN_TYPES) and parent_stmt.value is None:
+        if isinstance(parent_stmt, ast.AnnAssign) and parent_stmt.value is None:
             binding = Annotation(name, node)
         elif isinstance(parent_stmt, (FOR_TYPES, ast.comprehension)) or (
                 parent_stmt != node._pyflakes_parent and
                 not self.isLiteralTupleUnpacking(parent_stmt)):
             binding = Binding(name, node)
-        elif name == '__all__' and isinstance(self.scope, ModuleScope):
+        elif (
+                name == '__all__' and
+                isinstance(self.scope, ModuleScope) and
+                isinstance(
+                    node._pyflakes_parent,
+                    (ast.Assign, ast.AugAssign, ast.AnnAssign)
+                )
+        ):
             binding = ExportBinding(name, node._pyflakes_parent, self.scope)
-        elif PY2 and isinstance(getattr(node, 'ctx', None), ast.Param):
-            binding = Argument(name, self.getScopeNode(node))
+        elif PY38_PLUS and isinstance(parent_stmt, ast.NamedExpr):
+            binding = NamedExprAssignment(name, node)
         else:
             binding = Assignment(name, node)
         self.addBinding(node, binding)
@@ -1364,8 +1319,6 @@
                 parts = (comment,)
 
             for part in parts:
-                if PY2:
-                    part = part.replace('...', 'Ellipsis')
                 self.deferFunction(functools.partial(
                     self.handleStringAnnotation,
                     part, DummyNode(lineno, col_offset), lineno, col_offset,
@@ -1428,19 +1381,7 @@
 
     def handleDoctests(self, node):
         try:
-            if hasattr(node, 'docstring'):
-                docstring = node.docstring
-
-                # This is just a reasonable guess. In Python 3.7, docstrings no
-                # longer have line numbers associated with them. This will be
-                # incorrect if there are empty lines between the beginning
-                # of the function and the docstring.
-                node_lineno = node.lineno
-                if hasattr(node, 'args'):
-                    node_lineno = max([node_lineno] +
-                                      [arg.lineno for arg in node.args.args])
-            else:
-                (docstring, node_lineno) = self.getDocstring(node.body[0])
+            (docstring, node_lineno) = self.getDocstring(node.body[0])
             examples = docstring and self._getDoctestExamples(docstring)
         except (ValueError, IndexError):
             # e.g. line 6 of the docstring for <string> has inconsistent
@@ -1459,10 +1400,7 @@
         for example in examples:
             try:
                 tree = ast.parse(example.source, "<doctest>")
-            except SyntaxError:
-                e = sys.exc_info()[1]
-                if PYPY:
-                    e.offset += 1
+            except SyntaxError as e:
                 position = (node_lineno + example.lineno + e.lineno,
                             example.indent + 4 + (e.offset or 0))
                 self.report(messages.DoctestSyntaxError, node, position)
@@ -1520,16 +1458,14 @@
         pass
 
     # "stmt" type nodes
-    DELETE = PRINT = FOR = ASYNCFOR = WHILE = WITH = WITHITEM = \
-        ASYNCWITH = ASYNCWITHITEM = TRYFINALLY = EXEC = \
+    DELETE = FOR = ASYNCFOR = WHILE = WITH = WITHITEM = ASYNCWITH = \
         EXPR = ASSIGN = handleChildren
 
     PASS = ignore
 
     # "expr" type nodes
-    BOOLOP = UNARYOP = SET = \
-        REPR = ATTRIBUTE = \
-        STARRED = NAMECONSTANT = NAMEDEXPR = handleChildren
+    BOOLOP = UNARYOP = SET = ATTRIBUTE = STARRED = NAMECONSTANT = \
+        NAMEDEXPR = handleChildren
 
     def SUBSCRIPT(self, node):
         if _is_name_or_attr(node.value, 'Literal'):
@@ -1576,15 +1512,16 @@
             self.report(messages.StringDotFormatInvalidFormat, node, e)
             return
 
-        class state:  # py2-compatible `nonlocal`
-            auto = None
-            next_auto = 0
+        auto = None
+        next_auto = 0
 
         placeholder_positional = set()
         placeholder_named = set()
 
         def _add_key(fmtkey):
             """Returns True if there is an error which should early-exit"""
+            nonlocal auto, next_auto
+
             if fmtkey is None:  # end of string or `{` / `}` escapes
                 return False
 
@@ -1597,21 +1534,21 @@
             except ValueError:
                 pass
             else:  # fmtkey was an integer
-                if state.auto is True:
+                if auto is True:
                     self.report(messages.StringDotFormatMixingAutomatic, node)
                     return True
                 else:
-                    state.auto = False
+                    auto = False
 
             if fmtkey == '':
-                if state.auto is False:
+                if auto is False:
                     self.report(messages.StringDotFormatMixingAutomatic, node)
                     return True
                 else:
-                    state.auto = True
+                    auto = True
 
-                fmtkey = state.next_auto
-                state.next_auto += 1
+                fmtkey = next_auto
+                next_auto += 1
 
             if isinstance(fmtkey, int):
                 placeholder_positional.add(fmtkey)
@@ -1646,15 +1583,9 @@
 
         # bail early if there is *args or **kwargs
         if (
-                # python 2.x *args / **kwargs
-                getattr(node, 'starargs', None) or
-                getattr(node, 'kwargs', None) or
-                # python 3.x *args
-                any(
-                    isinstance(arg, getattr(ast, 'Starred', ()))
-                    for arg in node.args
-                ) or
-                # python 3.x **kwargs
+                # *args
+                any(isinstance(arg, ast.Starred) for arg in node.args) or
+                # **kwargs
                 any(kwd.arg is None for kwd in node.keywords)
         ):
             return
@@ -1835,7 +1766,7 @@
                 isinstance(node.right, (ast.List, ast.Tuple)) and
                 # does not have any *splats (py35+ feature)
                 not any(
-                    isinstance(elt, getattr(ast, 'Starred', ()))
+                    isinstance(elt, ast.Starred)
                     for elt in node.right.elts
                 )
         ):
@@ -1919,7 +1850,7 @@
     def RAISE(self, node):
         self.handleChildren(node)
 
-        arg = get_raise_argument(node)
+        arg = node.exc
 
         if isinstance(arg, ast.Call):
             if is_notimplemented_name_node(arg.func):
@@ -2034,9 +1965,7 @@
         self.handleChildren(node)
         self.popScope()
 
-    LISTCOMP = handleChildren if PY2 else GENERATOREXP
-
-    DICTCOMP = SETCOMP = GENERATOREXP
+    LISTCOMP = DICTCOMP = SETCOMP = GENERATOREXP
 
     def NAME(self, node):
         """
@@ -2051,13 +1980,11 @@
                 self.scope.usesLocals = True
         elif isinstance(node.ctx, ast.Store):
             self.handleNodeStore(node)
-        elif PY2 and isinstance(node.ctx, ast.Param):
-            self.handleNodeStore(node)
         elif isinstance(node.ctx, ast.Del):
             self.handleNodeDelete(node)
         else:
             # Unknown context
-            raise RuntimeError("Got impossible expression context: %r" % (node.ctx,))
+            raise RuntimeError(f"Got impossible expression context: {node.ctx!r}")
 
     def CONTINUE(self, node):
         # Walk the tree up until we see a loop (OK), a function or class
@@ -2066,7 +1993,7 @@
         n = node
         while hasattr(n, '_pyflakes_parent'):
             n, n_child = n._pyflakes_parent, n
-            if isinstance(n, LOOP_TYPES):
+            if isinstance(n, (ast.While, ast.For, ast.AsyncFor)):
                 # Doesn't apply unless it's in the loop itself
                 if n_child not in n.orelse:
                     return
@@ -2125,41 +2052,26 @@
         args = []
         annotations = []
 
-        if PY2:
-            def addArgs(arglist):
-                for arg in arglist:
-                    if isinstance(arg, ast.Tuple):
-                        addArgs(arg.elts)
-                    else:
-                        args.append(arg.id)
-            addArgs(node.args.args)
-            defaults = node.args.defaults
-        else:
-            if PY38_PLUS:
-                for arg in node.args.posonlyargs:
-                    args.append(arg.arg)
-                    annotations.append(arg.annotation)
-            for arg in node.args.args + node.args.kwonlyargs:
+        if PY38_PLUS:
+            for arg in node.args.posonlyargs:
                 args.append(arg.arg)
                 annotations.append(arg.annotation)
-            defaults = node.args.defaults + node.args.kw_defaults
+        for arg in node.args.args + node.args.kwonlyargs:
+            args.append(arg.arg)
+            annotations.append(arg.annotation)
+        defaults = node.args.defaults + node.args.kw_defaults
 
-        # Only for Python3 FunctionDefs
-        is_py3_func = hasattr(node, 'returns')
+        has_annotations = not isinstance(node, ast.Lambda)
 
         for arg_name in ('vararg', 'kwarg'):
             wildcard = getattr(node.args, arg_name)
             if not wildcard:
                 continue
-            args.append(wildcard if PY2 else wildcard.arg)
-            if is_py3_func:
-                if PY2:  # Python 2.7
-                    argannotation = arg_name + 'annotation'
-                    annotations.append(getattr(node.args, argannotation))
-                else:     # Python >= 3.4
-                    annotations.append(wildcard.annotation)
+            args.append(wildcard.arg)
+            if has_annotations:
+                annotations.append(wildcard.annotation)
 
-        if is_py3_func:
+        if has_annotations:
             annotations.append(node.returns)
 
         if len(set(args)) < len(args):
@@ -2187,28 +2099,12 @@
                     self.report(messages.UnusedVariable, binding.source, name)
             self.deferAssignment(checkUnusedAssignments)
 
-            if PY2:
-                def checkReturnWithArgumentInsideGenerator():
-                    """
-                    Check to see if there is any return statement with
-                    arguments but the function is a generator.
-                    """
-                    if self.scope.isGenerator and self.scope.returnValue:
-                        self.report(messages.ReturnWithArgsInsideGenerator,
-                                    self.scope.returnValue)
-                self.deferAssignment(checkReturnWithArgumentInsideGenerator)
             self.popScope()
 
         self.deferFunction(runFunction)
 
     def ARGUMENTS(self, node):
         self.handleChildren(node, omit=('defaults', 'kw_defaults'))
-        if PY2:
-            scope_node = self.getScopeNode(node)
-            if node.vararg:
-                self.addBinding(node, Argument(node.vararg, scope_node))
-            if node.kwarg:
-                self.addBinding(node, Argument(node.kwarg, scope_node))
 
     def ARG(self, node):
         self.addBinding(node, Argument(node.arg, self.getScopeNode(node)))
@@ -2223,9 +2119,8 @@
             self.handleNode(deco, node)
         for baseNode in node.bases:
             self.handleNode(baseNode, node)
-        if not PY2:
-            for keywordNode in node.keywords:
-                self.handleNode(keywordNode, node)
+        for keywordNode in node.keywords:
+            self.handleNode(keywordNode, node)
         self.pushScope(ClassScope)
         # doctest does not process doctest within a doctest
         # classes within classes are processed.
@@ -2244,7 +2139,7 @@
         self.handleNode(node.target, node)
 
     def TUPLE(self, node):
-        if not PY2 and isinstance(node.ctx, ast.Store):
+        if isinstance(node.ctx, ast.Store):
             # Python 3 advanced tuple unpacking: a, *b, c = d.
             # Only one starred expression is allowed, and no more than 1<<8
             # assignments are allowed before a stared expression. There is
@@ -2280,8 +2175,7 @@
     def IMPORTFROM(self, node):
         if node.module == '__future__':
             if not self.futuresAllowed:
-                self.report(messages.LateFutureImport,
-                            node, [n.name for n in node.names])
+                self.report(messages.LateFutureImport, node)
         else:
             self.futuresAllowed = False
 
@@ -2297,8 +2191,7 @@
                 if alias.name == 'annotations':
                     self.annotationsFutureEnabled = True
             elif alias.name == '*':
-                # Only Python 2, local import * is a SyntaxWarning
-                if not PY2 and not isinstance(self.scope, ModuleScope):
+                if not isinstance(self.scope, ModuleScope):
                     self.report(messages.ImportStarNotPermitted,
                                 node, module)
                     continue
@@ -2331,10 +2224,10 @@
         # Process the other nodes: "except:", "else:", "finally:"
         self.handleChildren(node, omit='body')
 
-    TRYEXCEPT = TRY
+    TRYSTAR = TRY
 
     def EXCEPTHANDLER(self, node):
-        if PY2 or node.name is None:
+        if node.name is None:
             self.handleChildren(node)
             return
 
@@ -2381,9 +2274,13 @@
     def ANNASSIGN(self, node):
         self.handleNode(node.target, node)
         self.handleAnnotation(node.annotation, node)
+        # If the assignment has value, handle the *value* now.
         if node.value:
-            # If the assignment has value, handle the *value* now.
-            self.handleNode(node.value, node)
+            # If the annotation is `TypeAlias`, handle the *value* as an annotation.
+            if _is_typing(node.annotation, 'TypeAlias', self.scopeStack):
+                self.handleAnnotation(node.value, node)
+            else:
+                self.handleNode(node.value, node)
 
     def COMPARE(self, node):
         left = node.left

eric ide

mercurial