pylint/checkers/python3.py
def visit_excepthandler(self, node):
        """Visit an except handler block and check for exception unpacking."""

        def _is_used_in_except_block(node):
            scope = node.scope()
            current = node
            while (
                current
                and current != scope
                and not isinstance(current, astroid.ExceptHandler)
            ):
                current = current.parent
            return isinstance(current, astroid.ExceptHandler) and current.type != node

        if isinstance(node.name, (astroid.Tuple, astroid.List)):
            self.add_message("unpacking-in-except", node=node)
            return

        if not node.name:
            return

        # Find any names
        scope = node.parent.scope()
        scope_names = scope.nodes_of_class(astroid.Name, skip_klass=astroid.FunctionDef)
        scope_names = list(scope_names)
        potential_leaked_names = [
            scope_name
            for scope_name in scope_names
            if scope_name.name == node.name.name
            and scope_name.lineno > node.lineno
            and not _is_used_in_except_block(scope_name)
        ]
        reassignments_for_same_name = {
            assign_name.lineno
            for assign_name in scope.nodes_of_class(
                astroid.AssignName, skip_klass=astroid.FunctionDef
            )
            if assign_name.name == node.name.name
        }
        for leaked_name in potential_leaked_names:
            if any(
                node.lineno < elem < leaked_name.lineno
                for elem in reassignments_for_same_name
            ):
                continue
            self.add_message("exception-escape", node=leaked_name)
def visit_excepthandler(self, node):
        """Visit an except handler block and check for exception unpacking."""

        def _is_used_in_except_block(node):
            scope = node.scope()
            current = node
            while (
                current
                and current != scope
                and not isinstance(current, astroid.ExceptHandler)
            ):
                current = current.parent
            return isinstance(current, astroid.ExceptHandler) and current.type != node

        if isinstance(node.name, (astroid.Tuple, astroid.List)):
            self.add_message("unpacking-in-except", node=node)
            return

        if not node.name:
            return

        # Find any names
        scope = node.parent.scope()
        scope_names = scope.nodes_of_class(astroid.Name, skip_klass=astroid.FunctionDef)
        scope_names = list(scope_names)
        potential_leaked_names = [
            scope_name
            for scope_name in scope_names
            if scope_name.name == node.name.name
            and scope_name.lineno > node.lineno
            and not _is_used_in_except_block(scope_name)
        ]
        reassignments_for_same_name = {
            assign_name.lineno
            for assign_name in scope.nodes_of_class(
                astroid.AssignName, skip_klass=astroid.FunctionDef
            )
            if assign_name.name == node.name.name
        }
        for leaked_name in potential_leaked_names:
            if any(
                node.lineno < elem < leaked_name.lineno
                for elem in reassignments_for_same_name
            ):
                continue
            self.add_message("exception-escape", node=leaked_name)
Visit an except handler block and check for exception unpacking.