Пример #1
0
def execute_node_without_scope(node, **kwargs):
    raise com.UnboundExpressionError(
        (
            'Node of type {!r} has no data bound to it. '
            'You probably tried to execute an expression without a data '
            'source.'
        ).format(type(node).__name__)
    )
Пример #2
0
def execute_bottom_up(expr,
                      scope,
                      aggcontext=None,
                      post_execute_=None,
                      clients=None,
                      **kwargs):
    """Execute `expr` bottom-up.

    Parameters
    ----------
    expr : ibis.expr.types.Expr
    scope : Mapping[ibis.expr.operations.Node, object]
    aggcontext : Optional[ibis.pandas.aggcontext.AggregationContext]
    kwargs : Dict[str, object]

    Returns
    -------
    result : Mapping[
        ibis.expr.operations.Node,
        Union[pandas.Series, pandas.DataFrame, scalar_types]
    ]
        A mapping from node to the computed result of that Node
    """
    assert post_execute_ is not None, 'post_execute_ is None'
    op = expr.op()

    # if we're in scope then return the scope, this will then be passed back
    # into execute_bottom_up, which will then terminate
    if op in scope:
        return scope
    elif isinstance(op, ops.Literal):
        # special case literals to avoid the overhead of dispatching
        # execute_node
        return {
            op:
            execute_literal(op,
                            op.value,
                            expr.type(),
                            aggcontext=aggcontext,
                            **kwargs)
        }

    # figure out what arguments we're able to compute on based on the
    # expressions inputs. things like expressions, None, and scalar types are
    # computable whereas ``list``s are not
    computable_args = [arg for arg in op.inputs if is_computable_input(arg)]

    # recursively compute each node's arguments until we've changed type
    scopes = [
        execute_bottom_up(
            arg,
            scope,
            aggcontext=aggcontext,
            post_execute_=post_execute_,
            clients=clients,
            **kwargs,
        ) if hasattr(arg, 'op') else {
            arg: arg
        } for arg in computable_args
    ]

    # if we're unable to find data then raise an exception
    if not scopes:
        raise com.UnboundExpressionError(
            'Unable to find data for expression:\n{}'.format(repr(expr)))

    # there should be exactly one dictionary per computable argument
    assert len(computable_args) == len(scopes)

    new_scope = toolz.merge(scopes)

    # pass our computed arguments to this node's execute_node implementation
    data = [
        new_scope[arg.op()] if hasattr(arg, 'op') else arg
        for arg in computable_args
    ]
    result = execute_node(
        op,
        *data,
        scope=scope,
        aggcontext=aggcontext,
        clients=clients,
        **kwargs,
    )
    computed = post_execute_(op, result)
    return {op: computed}