Beispiel #1
0
def _get_first_import(node, context, name, base, level, alias):
    """return the node where [base.]<name> is imported or None if not found
    """
    fullname = '%s.%s' % (base, name) if base else name

    first = None
    found = False
    for first in context.body:
        if first is node:
            continue
        if first.scope() is node.scope(
        ) and first.fromlineno > node.fromlineno:
            continue
        if isinstance(first, astroid.Import):
            if any(fullname == iname[0] for iname in first.names):
                found = True
                break
        elif isinstance(first, astroid.ImportFrom):
            if level == first.level:
                for imported_name, imported_alias in first.names:
                    if fullname == '%s.%s' % (first.modname, imported_name):
                        found = True
                        break
                    if name != '*' and name == imported_name and not (
                            alias or imported_alias):
                        found = True
                        break
                if found:
                    break
    if found and not are_exclusive(first, node):
        return first
    return None
Beispiel #2
0
 def _check_redefinition(self, redeftype, node):
     """check for redefinition of a function / method / class name"""
     defined_self = node.parent.frame()[node.name]
     if defined_self is not node and not are_exclusive(node, defined_self):
         self.add_message('function-redefined',
                          node=node,
                          args=(redeftype, defined_self.fromlineno))
Beispiel #3
0
def _get_first_import(node, context, name, base, level, alias):
    """return the node where [base.]<name> is imported or None if not found
    """
    fullname = '%s.%s' % (base, name) if base else name

    first = None
    found = False
    for first in context.body:
        if first is node:
            continue
        if first.scope() is node.scope() and first.fromlineno > node.fromlineno:
            continue
        if isinstance(first, astroid.Import):
            if any(fullname == iname[0] for iname in first.names):
                found = True
                break
        elif isinstance(first, astroid.ImportFrom):
            if level == first.level:
                for imported_name, imported_alias in first.names:
                    if fullname == '%s.%s' % (first.modname, imported_name):
                        found = True
                        break
                    if name != '*' and name == imported_name and not (alias or imported_alias):
                        found = True
                        break
                if found:
                    break
    if found and not are_exclusive(first, node):
        return first
Beispiel #4
0
 def _check_accessed_members(self, node, accessed):
     """check that accessed members are defined"""
     # XXX refactor, probably much simpler now that E0201 is in type checker
     for attr, nodes in six.iteritems(accessed):
         # deactivate "except doesn't do anything", that's expected
         # pylint: disable=W0704
         try:
             # is it a class attribute ?
             node.local_attr(attr)
             # yes, stop here
             continue
         except astroid.NotFoundError:
             pass
         # is it an instance attribute of a parent class ?
         try:
             next(node.instance_attr_ancestors(attr))
             # yes, stop here
             continue
         except StopIteration:
             pass
         # is it an instance attribute ?
         try:
             defstmts = node.instance_attr(attr)
         except astroid.NotFoundError:
             pass
         else:
             # filter out augment assignment nodes
             defstmts = [stmt for stmt in defstmts if stmt not in nodes]
             if not defstmts:
                 # only augment assignment for this node, no-member should be
                 # triggered by the typecheck checker
                 continue
             # filter defstmts to only pick the first one when there are
             # several assignments in the same scope
             scope = defstmts[0].scope()
             defstmts = [
                 stmt for i, stmt in enumerate(defstmts)
                 if i == 0 or stmt.scope() is not scope
             ]
             # if there are still more than one, don't attempt to be smarter
             # than we can be
             if len(defstmts) == 1:
                 defstmt = defstmts[0]
                 # check that if the node is accessed in the same method as
                 # it's defined, it's accessed after the initial assignment
                 frame = defstmt.frame()
                 lno = defstmt.fromlineno
                 for _node in nodes:
                     if _node.frame() is frame and _node.fromlineno < lno \
                        and not are_exclusive(_node.statement(), defstmt,
                                              ('AttributeError', 'Exception', 'BaseException')):
                         self.add_message('access-member-before-definition',
                                          node=_node,
                                          args=(attr, lno))
 def _check_accessed_members(self, node, accessed):
     """check that accessed members are defined"""
     # XXX refactor, probably much simpler now that E0201 is in type checker
     for attr, nodes in accessed.iteritems():
         # deactivate "except doesn't do anything", that's expected
         # pylint: disable=W0704
         try:
             # is it a class attribute ?
             node.local_attr(attr)
             # yes, stop here
             continue
         except astroid.NotFoundError:
             pass
         # is it an instance attribute of a parent class ?
         try:
             node.instance_attr_ancestors(attr).next()
             # yes, stop here
             continue
         except StopIteration:
             pass
         # is it an instance attribute ?
         try:
             defstmts = node.instance_attr(attr)
         except astroid.NotFoundError:
             pass
         else:
             # filter out augment assignment nodes
             defstmts = [stmt for stmt in defstmts if stmt not in nodes]
             if not defstmts:
                 # only augment assignment for this node, no-member should be
                 # triggered by the typecheck checker
                 continue
             # filter defstmts to only pick the first one when there are
             # several assignments in the same scope
             scope = defstmts[0].scope()
             defstmts = [stmt for i, stmt in enumerate(defstmts) if i == 0 or stmt.scope() is not scope]
             # if there are still more than one, don't attempt to be smarter
             # than we can be
             if len(defstmts) == 1:
                 defstmt = defstmts[0]
                 # check that if the node is accessed in the same method as
                 # it's defined, it's accessed after the initial assignment
                 frame = defstmt.frame()
                 lno = defstmt.fromlineno
                 for _node in nodes:
                     if (
                         _node.frame() is frame
                         and _node.fromlineno < lno
                         and not are_exclusive(
                             _node.statement(), defstmt, ("AttributeError", "Exception", "BaseException")
                         )
                     ):
                         self.add_message("access-member-before-definition", node=_node, args=(attr, lno))
Beispiel #6
0
 def _check_accessed_members(self, node, accessed):
     """check that accessed members are defined"""
     # XXX refactor, probably much simpler now that E0201 is in type checker
     for attr, nodes in accessed.iteritems():
         # deactivate "except doesn't do anything", that's expected
         # pylint: disable=W0704
         # is it a class attribute ?
         try:
             node.local_attr(attr)
             # yes, stop here
             continue
         except astroid.NotFoundError:
             pass
         # is it an instance attribute of a parent class ?
         try:
             node.instance_attr_ancestors(attr).next()
             # yes, stop here
             continue
         except StopIteration:
             pass
         # is it an instance attribute ?
         try:
             defstmts = node.instance_attr(attr)
         except astroid.NotFoundError:
             pass
         else:
             if len(defstmts) == 1:
                 defstmt = defstmts[0]
                 # check that if the node is accessed in the same method as
                 # it's defined, it's accessed after the initial assignment
                 frame = defstmt.frame()
                 lno = defstmt.fromlineno
                 for _node in nodes:
                     if _node.frame() is frame and _node.fromlineno < lno \
                        and not are_exclusive(_node.statement(), defstmt, ('AttributeError', 'Exception', 'BaseException')):
                         self.add_message('E0203',
                                          node=_node,
                                          args=(attr, lno))
Beispiel #7
0
 def _check_accessed_members(self, node, accessed):
     """check that accessed members are defined"""
     # XXX refactor, probably much simpler now that E0201 is in type checker
     for attr, nodes in accessed.iteritems():
         # deactivate "except doesn't do anything", that's expected
         # pylint: disable=W0704
         # is it a class attribute ?
         try:
             node.local_attr(attr)
             # yes, stop here
             continue
         except astroid.NotFoundError:
             pass
         # is it an instance attribute of a parent class ?
         try:
             node.instance_attr_ancestors(attr).next()
             # yes, stop here
             continue
         except StopIteration:
             pass
         # is it an instance attribute ?
         try:
             defstmts = node.instance_attr(attr)
         except astroid.NotFoundError:
             pass
         else:
             if len(defstmts) == 1:
                 defstmt = defstmts[0]
                 # check that if the node is accessed in the same method as
                 # it's defined, it's accessed after the initial assignment
                 frame = defstmt.frame()
                 lno = defstmt.fromlineno
                 for _node in nodes:
                     if _node.frame() is frame and _node.fromlineno < lno \
                        and not are_exclusive(_node.statement(), defstmt, ('AttributeError', 'Exception', 'BaseException')):
                         self.add_message('E0203', node=_node,
                                          args=(attr, lno))
Beispiel #8
0
    def visit_name(self, node):
        """check that a name is defined if the current scope and doesn't
        redefine a built-in
        """
        stmt = node.statement()
        if stmt.fromlineno is None:
            # name node from a astroid built from live code, skip
            assert not stmt.root().file.endswith('.py')
            return
        name = node.name
        frame = stmt.scope()
        # if the name node is used as a function default argument's value or as
        # a decorator, then start from the parent frame of the function instead
        # of the function frame - and thus open an inner class scope
        if (is_func_default(node) or is_func_decorator(node)
                or is_ancestor_name(frame, node)):
            start_index = len(self._to_consume) - 2
        else:
            start_index = len(self._to_consume) - 1
        # iterates through parent scopes, from the inner to the outer
        base_scope_type = self._to_consume[start_index][-1]
        for i in range(start_index, -1, -1):
            to_consume, consumed, scope_type = self._to_consume[i]
            # if the current scope is a class scope but it's not the inner
            # scope, ignore it. This prevents to access this scope instead of
            # the globals one in function members when there are some common
            # names. The only exception is when the starting scope is a
            # comprehension and its direct outer scope is a class
            if scope_type == 'class' and i != start_index and not (
                    base_scope_type == 'comprehension' and i == start_index-1):
                # Detect if we are in a local class scope, as an assignment.
                # For example, the following is fair game.
                #
                # class A:
                #    b = 1
                #    c = lambda b=b: b * b
                #
                # class B:
                #    tp = 1
                #    def func(self, arg: tp):
                #        ...

                in_annotation = (
                    PY3K and isinstance(frame, astroid.Function)
                    and node.statement() is frame and
                    (node in frame.args.annotations
                     or node is frame.args.varargannotation
                     or node is frame.args.kwargannotation))
                if in_annotation:
                    frame_locals = frame.parent.scope().locals
                else:
                    frame_locals = frame.locals
                if not ((isinstance(frame, astroid.Class) or in_annotation)
                        and name in frame_locals):
                    continue
            # the name has already been consumed, only check it's not a loop
            # variable used outside the loop
            if name in consumed:
                defnode = assign_parent(consumed[name][0])
                self._check_late_binding_closure(node, defnode)
                self._loopvar_name(node, name)
                break
            # mark the name as consumed if it's defined in this scope
            # (i.e. no KeyError is raised by "to_consume[name]")
            try:
                consumed[name] = to_consume[name]
            except KeyError:
                continue
            # checks for use before assignment
            defnode = assign_parent(to_consume[name][0])
            if defnode is not None:
                self._check_late_binding_closure(node, defnode)
                defstmt = defnode.statement()
                defframe = defstmt.frame()
                maybee0601 = True
                if not frame is defframe:
                    maybee0601 = _detect_global_scope(node, frame, defframe)
                elif defframe.parent is None:
                    # we are at the module level, check the name is not
                    # defined in builtins
                    if name in defframe.scope_attrs or builtin_lookup(name)[1]:
                        maybee0601 = False
                else:
                    # we are in a local scope, check the name is not
                    # defined in global or builtin scope
                    if defframe.root().lookup(name)[1]:
                        maybee0601 = False
                    else:
                        # check if we have a nonlocal
                        if name in defframe.locals:
                            maybee0601 = not any(isinstance(child, astroid.Nonlocal)
                                                 and name in child.names
                                                 for child in defframe.get_children())

                # Handle a couple of class scoping issues.
                annotation_return = False
                # The class reuses itself in the class scope.
                recursive_klass = (frame is defframe and
                                   defframe.parent_of(node) and
                                   isinstance(defframe, astroid.Class) and
                                   node.name == defframe.name)
                if (self._to_consume[-1][-1] == 'lambda' and
                        isinstance(frame, astroid.Class)
                        and name in frame.locals):
                    maybee0601 = True
                elif (isinstance(defframe, astroid.Class) and
                      isinstance(frame, astroid.Function)):
                    # Special rule for function return annotations,
                    # which uses the same name as the class where
                    # the function lives.
                    if (PY3K and node is frame.returns and
                            defframe.parent_of(frame.returns)):
                        maybee0601 = annotation_return = True

                    if (maybee0601 and defframe.name in defframe.locals and
                            defframe.locals[name][0].lineno < frame.lineno):
                        # Detect class assignments with the same
                        # name as the class. In this case, no warning
                        # should be raised.
                        maybee0601 = False
                elif recursive_klass:
                    maybee0601 = True
                else:
                    maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.fromlineno

                if (maybee0601
                        and not is_defined_before(node)
                        and not are_exclusive(stmt, defstmt, ('NameError',
                                                              'Exception',
                                                              'BaseException'))):
                    if recursive_klass or (defstmt is stmt and
                                           isinstance(node, (astroid.DelName,
                                                             astroid.AssName))):
                        self.add_message('undefined-variable', args=name, node=node)
                    elif annotation_return:
                        self.add_message('undefined-variable', args=name, node=node)
                    elif self._to_consume[-1][-1] != 'lambda':
                        # E0601 may *not* occurs in lambda scope.
                        self.add_message('used-before-assignment', args=name, node=node)
                    elif self._to_consume[-1][-1] == 'lambda':
                        # E0601 can occur in class-level scope in lambdas, as in
                        # the following example:
                        #   class A:
                        #      x = lambda attr: f + attr
                        #      f = 42
                        if isinstance(frame, astroid.Class) and name in frame.locals:
                            if isinstance(node.parent, astroid.Arguments):
                                # Doing the following is fine:
                                #   class A:
                                #      x = 42
                                #      y = lambda attr=x: attr
                                if stmt.fromlineno <= defstmt.fromlineno:
                                    self.add_message('used-before-assignment',
                                                     args=name, node=node)
                            else:
                                self.add_message('undefined-variable',
                                                 args=name, node=node)

            if isinstance(node, astroid.AssName): # Aug AssName
                del consumed[name]
            else:
                del to_consume[name]
            # check it's not a loop variable used outside the loop
            self._loopvar_name(node, name)
            break
        else:
            # we have not found the name, if it isn't a builtin, that's an
            # undefined name !
            if not (name in astroid.Module.scope_attrs or is_builtin(name)
                    or name in self.config.additional_builtins):
                self.add_message('undefined-variable', args=name, node=node)
Beispiel #9
0
 def visit_name(self, node):
     """check that a name is defined if the current scope and doesn't
     redefine a built-in
     """
     stmt = node.statement()
     if stmt.fromlineno is None:
         # name node from a astroid built from live code, skip
         assert not stmt.root().file.endswith('.py')
         return
     name = node.name
     frame = stmt.scope()
     # if the name node is used as a function default argument's value or as
     # a decorator, then start from the parent frame of the function instead
     # of the function frame - and thus open an inner class scope
     if (is_func_default(node) or is_func_decorator(node)
         or is_ancestor_name(frame, node)):
         start_index = len(self._to_consume) - 2
     else:
         start_index = len(self._to_consume) - 1
     # iterates through parent scopes, from the inner to the outer
     base_scope_type = self._to_consume[start_index][-1]
     for i in range(start_index, -1, -1):
         to_consume, consumed, scope_type = self._to_consume[i]
         # if the current scope is a class scope but it's not the inner
         # scope, ignore it. This prevents to access this scope instead of
         # the globals one in function members when there are some common
         # names. The only exception is when the starting scope is a
         # comprehension and its direct outer scope is a class
         if scope_type == 'class' and i != start_index and not (
             base_scope_type == 'comprehension' and i == start_index-1):
             # XXX find a way to handle class scope in a smoother way
             continue
         # the name has already been consumed, only check it's not a loop
         # variable used outside the loop
         if name in consumed:
             defnode = assign_parent(consumed[name][0])
             self._check_late_binding_closure(node, defnode, scope_type)
             self._loopvar_name(node, name)
             break
         # mark the name as consumed if it's defined in this scope
         # (i.e. no KeyError is raised by "to_consume[name]")
         try:
             consumed[name] = to_consume[name]
         except KeyError:
             continue
         # checks for use before assignment
         defnode = assign_parent(to_consume[name][0])
         if defnode is not None:
             self._check_late_binding_closure(node, defnode, scope_type)
             defstmt = defnode.statement()
             defframe = defstmt.frame()
             maybee0601 = True
             if not frame is defframe:
                 maybee0601 = False
             elif defframe.parent is None:
                 # we are at the module level, check the name is not
                 # defined in builtins
                 if name in defframe.scope_attrs or builtin_lookup(name)[1]:
                     maybee0601 = False
             else:
                 # we are in a local scope, check the name is not
                 # defined in global or builtin scope
                 if defframe.root().lookup(name)[1]:
                     maybee0601 = False
                 else:
                     # check if we have a nonlocal
                     if name in defframe.locals:
                         maybee0601 = not any(isinstance(child, astroid.Nonlocal)
                                              and name in child.names
                                              for child in defframe.get_children())
             if (maybee0601
                 and stmt.fromlineno <= defstmt.fromlineno
                 and not is_defined_before(node)
                 and not are_exclusive(stmt, defstmt, ('NameError', 'Exception', 'BaseException'))):
                 if defstmt is stmt and isinstance(node, (astroid.DelName,
                                                          astroid.AssName)):
                     self.add_message('undefined-variable', args=name, node=node)
                 elif self._to_consume[-1][-1] != 'lambda':
                     # E0601 may *not* occurs in lambda scope
                     self.add_message('used-before-assignment', args=name, node=node)
         if isinstance(node, astroid.AssName): # Aug AssName
             del consumed[name]
         else:
             del to_consume[name]
         # check it's not a loop variable used outside the loop
         self._loopvar_name(node, name)
         break
     else:
         # we have not found the name, if it isn't a builtin, that's an
         # undefined name !
         if not (name in astroid.Module.scope_attrs or is_builtin(name)
                 or name in self.config.additional_builtins):
             self.add_message('undefined-variable', args=name, node=node)
Beispiel #10
0
 def _is_fallback_import(node, imports):
     imports = [import_node for (import_node, _) in imports]
     return any(
         astroid.are_exclusive(import_node, node)
         for import_node in imports)
Beispiel #11
0
 def _is_fallback_import(node, imports):
     imports = [import_node for (import_node, _) in imports]
     return any(astroid.are_exclusive(import_node, node)
                for import_node in imports)
Beispiel #12
0
 def _check_redefinition(self, redeftype, node):
     """check for redefinition of a function / method / class name"""
     defined_self = node.parent.frame()[node.name]
     if defined_self is not node and not are_exclusive(node, defined_self):
         self.add_message('function-redefined', node=node,
                          args=(redeftype, defined_self.fromlineno))
Beispiel #13
0
    def visit_name(self, node):
        """check that a name is defined if the current scope and doesn't
        redefine a built-in
        """
        stmt = node.statement()
        if stmt.fromlineno is None:
            # name node from a astroid built from live code, skip
            assert not stmt.root().file.endswith('.py')
            return
        name = node.name
        frame = stmt.scope()
        # if the name node is used as a function default argument's value or as
        # a decorator, then start from the parent frame of the function instead
        # of the function frame - and thus open an inner class scope
        if (is_func_default(node) or is_func_decorator(node)
                or is_ancestor_name(frame, node)):
            start_index = len(self._to_consume) - 2
        else:
            start_index = len(self._to_consume) - 1
        # iterates through parent scopes, from the inner to the outer
        base_scope_type = self._to_consume[start_index][-1]
        for i in range(start_index, -1, -1):
            to_consume, consumed, scope_type = self._to_consume[i]
            # if the current scope is a class scope but it's not the inner
            # scope, ignore it. This prevents to access this scope instead of
            # the globals one in function members when there are some common
            # names. The only exception is when the starting scope is a
            # comprehension and its direct outer scope is a class
            if scope_type == 'class' and i != start_index and not (
                    base_scope_type == 'comprehension'
                    and i == start_index - 1):
                # Detect if we are in a local class scope, as an assignment.
                # For example, the following is fair game.
                # class A:
                #    b = 1
                #    c = lambda b=b: b * b
                class_assignment = (isinstance(frame, astroid.Class)
                                    and name in frame.locals)
                if not class_assignment:
                    continue
            # the name has already been consumed, only check it's not a loop
            # variable used outside the loop
            if name in consumed:
                defnode = assign_parent(consumed[name][0])
                self._check_late_binding_closure(node, defnode, scope_type)
                self._loopvar_name(node, name)
                break
            # mark the name as consumed if it's defined in this scope
            # (i.e. no KeyError is raised by "to_consume[name]")
            try:
                consumed[name] = to_consume[name]
            except KeyError:
                continue
            # checks for use before assignment
            defnode = assign_parent(to_consume[name][0])
            if defnode is not None:
                self._check_late_binding_closure(node, defnode, scope_type)
                defstmt = defnode.statement()
                defframe = defstmt.frame()
                maybee0601 = True
                if not frame is defframe:
                    maybee0601 = _detect_global_scope(node, frame, defframe)
                elif defframe.parent is None:
                    # we are at the module level, check the name is not
                    # defined in builtins
                    if name in defframe.scope_attrs or builtin_lookup(name)[1]:
                        maybee0601 = False
                else:
                    # we are in a local scope, check the name is not
                    # defined in global or builtin scope
                    if defframe.root().lookup(name)[1]:
                        maybee0601 = False
                    else:
                        # check if we have a nonlocal
                        if name in defframe.locals:
                            maybee0601 = not any(
                                isinstance(child, astroid.Nonlocal)
                                and name in child.names
                                for child in defframe.get_children())
                if (self._to_consume[-1][-1] == 'lambda'
                        and isinstance(frame, astroid.Class)
                        and name in frame.locals):
                    maybee0601 = True
                else:
                    maybee0601 = maybee0601 and stmt.fromlineno <= defstmt.fromlineno

                if (maybee0601
                        and not is_defined_before(node) and not are_exclusive(
                            stmt, defstmt,
                            ('NameError', 'Exception', 'BaseException'))):
                    if defstmt is stmt and isinstance(
                            node, (astroid.DelName, astroid.AssName)):
                        self.add_message('undefined-variable',
                                         args=name,
                                         node=node)
                    elif self._to_consume[-1][-1] != 'lambda':
                        # E0601 may *not* occurs in lambda scope.
                        self.add_message('used-before-assignment',
                                         args=name,
                                         node=node)
                    elif self._to_consume[-1][-1] == 'lambda':
                        # E0601 can occur in class-level scope in lambdas, as in
                        # the following example:
                        #   class A:
                        #      x = lambda attr: f + attr
                        #      f = 42
                        if isinstance(frame,
                                      astroid.Class) and name in frame.locals:
                            if isinstance(node.parent, astroid.Arguments):
                                # Doing the following is fine:
                                #   class A:
                                #      x = 42
                                #      y = lambda attr=x: attr
                                if stmt.fromlineno <= defstmt.fromlineno:
                                    self.add_message('used-before-assignment',
                                                     args=name,
                                                     node=node)
                            else:
                                self.add_message('undefined-variable',
                                                 args=name,
                                                 node=node)

            if isinstance(node, astroid.AssName):  # Aug AssName
                del consumed[name]
            else:
                del to_consume[name]
            # check it's not a loop variable used outside the loop
            self._loopvar_name(node, name)
            break
        else:
            # we have not found the name, if it isn't a builtin, that's an
            # undefined name !
            if not (name in astroid.Module.scope_attrs or is_builtin(name)
                    or name in self.config.additional_builtins):
                self.add_message('undefined-variable', args=name, node=node)
Beispiel #14
0
 def visit_name(self, node):
     """check that a name is defined if the current scope and doesn't
     redefine a built-in
     """
     stmt = node.statement()
     if stmt.fromlineno is None:
         # name node from a astroid built from live code, skip
         assert not stmt.root().file.endswith('.py')
         return
     name = node.name
     frame = stmt.scope()
     # if the name node is used as a function default argument's value or as
     # a decorator, then start from the parent frame of the function instead
     # of the function frame - and thus open an inner class scope
     if (is_func_default(node) or is_func_decorator(node)
             or is_ancestor_name(frame, node)):
         start_index = len(self._to_consume) - 2
     else:
         start_index = len(self._to_consume) - 1
     # iterates through parent scopes, from the inner to the outer
     base_scope_type = self._to_consume[start_index][-1]
     for i in range(start_index, -1, -1):
         to_consume, consumed, scope_type = self._to_consume[i]
         # if the current scope is a class scope but it's not the inner
         # scope, ignore it. This prevents to access this scope instead of
         # the globals one in function members when there are some common
         # names. The only exception is when the starting scope is a
         # comprehension and its direct outer scope is a class
         if scope_type == 'class' and i != start_index and not (
                 base_scope_type == 'comprehension'
                 and i == start_index - 1):
             # XXX find a way to handle class scope in a smoother way
             continue
         # the name has already been consumed, only check it's not a loop
         # variable used outside the loop
         if name in consumed:
             self._loopvar_name(node, name)
             break
         # mark the name as consumed if it's defined in this scope
         # (i.e. no KeyError is raised by "to_consume[name]")
         try:
             consumed[name] = to_consume[name]
         except KeyError:
             continue
         # checks for use before assignment
         defnode = assign_parent(to_consume[name][0])
         if defnode is not None:
             defstmt = defnode.statement()
             defframe = defstmt.frame()
             maybee0601 = True
             if not frame is defframe:
                 maybee0601 = False
             elif defframe.parent is None:
                 # we are at the module level, check the name is not
                 # defined in builtins
                 if name in defframe.scope_attrs or builtin_lookup(name)[1]:
                     maybee0601 = False
             else:
                 # we are in a local scope, check the name is not
                 # defined in global or builtin scope
                 if defframe.root().lookup(name)[1]:
                     maybee0601 = False
             if (maybee0601 and stmt.fromlineno <= defstmt.fromlineno
                     and not is_defined_before(node) and not are_exclusive(
                         stmt, defstmt,
                         ('NameError', 'Exception', 'BaseException'))):
                 if defstmt is stmt and isinstance(
                         node, (astroid.DelName, astroid.AssName)):
                     self.add_message('E0602', args=name, node=node)
                 elif self._to_consume[-1][-1] != 'lambda':
                     # E0601 may *not* occurs in lambda scope
                     self.add_message('E0601', args=name, node=node)
         if not isinstance(node, astroid.AssName):  # Aug AssName
             del to_consume[name]
         else:
             del consumed[name]
         # check it's not a loop variable used outside the loop
         self._loopvar_name(node, name)
         break
     else:
         # we have not found the name, if it isn't a builtin, that's an
         # undefined name !
         if not (name in astroid.Module.scope_attrs or is_builtin(name)
                 or name in self.config.additional_builtins):
             self.add_message('E0602', args=name, node=node)
Beispiel #15
0
    def _check_redefinition(self, redeftype, node):
        """Check for redefinition of a function / method / class name."""
        parent_frame = node.parent.frame(future=True)

        # Ignore function stubs created for type information
        redefinitions = [
            i for i in parent_frame.locals[node.name]
            if not (isinstance(i.parent, nodes.AnnAssign) and i.parent.simple)
        ]
        defined_self = next(
            (local
             for local in redefinitions if not utils.is_overload_stub(local)),
            node,
        )
        if defined_self is not node and not astroid.are_exclusive(
                node, defined_self):
            # Additional checks for methods which are not considered
            # redefined, since they are already part of the base API.
            if (isinstance(parent_frame, nodes.ClassDef)
                    and node.name in REDEFINABLE_METHODS):
                return

            # Skip typing.overload() functions.
            if utils.is_overload_stub(node):
                return

            # Exempt functions redefined on a condition.
            if isinstance(node.parent, nodes.If):
                # Exempt "if not <func>" cases
                if (isinstance(node.parent.test, nodes.UnaryOp)
                        and node.parent.test.op == "not"
                        and isinstance(node.parent.test.operand, nodes.Name)
                        and node.parent.test.operand.name == node.name):
                    return

                # Exempt "if <func> is not None" cases
                # pylint: disable=too-many-boolean-expressions
                if (isinstance(node.parent.test, nodes.Compare)
                        and isinstance(node.parent.test.left, nodes.Name)
                        and node.parent.test.left.name == node.name
                        and node.parent.test.ops[0][0] == "is"
                        and isinstance(node.parent.test.ops[0][1], nodes.Const)
                        and node.parent.test.ops[0][1].value is None):
                    return

            # Check if we have forward references for this node.
            try:
                redefinition_index = redefinitions.index(node)
            except ValueError:
                pass
            else:
                for redefinition in redefinitions[:redefinition_index]:
                    inferred = utils.safe_infer(redefinition)
                    if (inferred and isinstance(inferred, astroid.Instance)
                            and inferred.qname() == TYPING_FORWARD_REF_QNAME):
                        return

            dummy_variables_rgx = lint_utils.get_global_option(
                self, "dummy-variables-rgx", default=None)
            if dummy_variables_rgx and dummy_variables_rgx.match(node.name):
                return
            self.add_message(
                "function-redefined",
                node=node,
                args=(redeftype, defined_self.fromlineno),
            )