def parse_and_validate(
    source: str, call_only: bool = True, task_type: str = "script"
) -> ast.AST:
    """
    Parse the given source into an ast, validate that is consists of a expression and
    return the root node.

    If call_only is True then require the root node to be a function call.
    """

    try:
        module = ast.parse(source)
    except SyntaxError as error:
        raise ExpressionParseError(f"Invalid {task_type} content: {source}") from error

    if len(module.body) != 1 or not isinstance(module.body[0], ast.Expr):
        raise ExpressionParseError(
            f"Expected a single python expression, instead got: {source}"
        )

    root_node = module.body[0].value

    if call_only:
        if not isinstance(root_node, ast.Call):
            raise ExpressionParseError(
                f"Expected a function call, instead got: {source}"
            )

        node = root_node.func
        while isinstance(node, ast.Attribute):
            node = node.value
        if not isinstance(node, ast.Name):
            raise ExpressionParseError(f"Invalid function reference in: {source}")

    return root_node

    Parse the given source into an ast, validate that is consists of a expression and
    return the root node.

    If call_only is True then require the root node to be a function call.
    
poethepoet/helpers/python.py