def _validate_nodes_and_get_names(
    node: ast.AST, source: str, *, ignore_names: Collection[str] = tuple()
) -> Iterator[ast.Name]:
    """
    Walk the ast from the given node and yield all of the encountered Name nodes
    except function names from Call nodes, or variables scoped to a comprehension or
    lambda.

    Also raise if any of the banned_node_types are encountered.
    """
    banned_node_types = (
        getattr(ast, "NamedExpr", NoInstance),
        ast.Await,
        ast.Yield,
        ast.YieldFrom,
    )

    if isinstance(node, ast.Name) and node.id not in ignore_names:
        yield node

    elif isinstance(node, ast.Call):
        # skip function names

        func_ref = node.func
        while isinstance(func_ref, ast.Attribute):
            func_ref = func_ref.value
        if not isinstance(func_ref, ast.Name):
            # a function can be an attribute of the result of an expression
            yield from _validate_nodes_and_get_names(
                func_ref, source, ignore_names=ignore_names
            )

        for arg in node.args:
            yield from _validate_nodes_and_get_names(
                arg, source, ignore_names=ignore_names
            )
        for kwarg in node.keywords:
            yield from _validate_nodes_and_get_names(
                kwarg, source, ignore_names=ignore_names
            )

    elif isinstance(node, ast.Lambda):
        # ignore lambda arguments
        lambda_args = {a.arg for a in node.args.args} | set(ignore_names)
        yield from _validate_nodes_and_get_names(
            node.body, source, ignore_names=lambda_args
        )

    elif isinstance(node, (ast.ListComp, ast.SetComp, ast.GeneratorExp, ast.DictComp)):
        # ignore comprehension/generator scoped variables

        comp_vars = {
            gen_node.id
            for comp_node in node.generators
            for gen_node in ast.walk(comp_node.target)
            if isinstance(gen_node, ast.Name)
        } | set(ignore_names)

        if isinstance(node, ast.DictComp):
            yield from _validate_nodes_and_get_names(
                node.key, source, ignore_names=comp_vars
            )
        else:
            yield from _validate_nodes_and_get_names(
                node.elt, source, ignore_names=comp_vars
            )
        for comp_node in node.generators:
            yield from _validate_nodes_and_get_names(
                comp_node, source, ignore_names=comp_vars
            )

    elif isinstance(node, banned_node_types):
        if isinstance(
            node,
            getattr(ast, "NamedExpr", NoInstance),
        ):
            raise ExpressionParseError(
                f"Expression should not include named expressions: {source}"
            )
        if isinstance(node, ast.Await):
            raise ExpressionParseError(f"Expression should not include await: {source}")
        raise ExpressionParseError(f"Expression should not include yield: {source}")

    elif node:
        for child_node in ast.iter_child_nodes(node):
            yield from _validate_nodes_and_get_names(
                child_node, source, ignore_names=ignore_names
            )

    Walk the ast from the given node and yield all of the encountered Name nodes
    except function names from Call nodes, or variables scoped to a comprehension or
    lambda.

    Also raise if any of the banned_node_types are encountered.
    
poethepoet/helpers/python.py