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__) )
def translate_literal(expr, inline_metadata: bool = False) -> str: op = expr.op() value = op.value if IS_SHAPELY_AVAILABLE and isinstance(value, shapely.geometry.base.BaseGeometry): result = value.wkt elif isinstance(expr, ir.PointScalar): result = translate_point(value) elif isinstance(expr, ir.LineStringScalar): result = translate_linestring(value) elif isinstance(expr, ir.PolygonScalar): result = translate_polygon(value) elif isinstance(expr, ir.MultiPolygonScalar): result = translate_multipolygon(value) else: raise ex.UnboundExpressionError('Geo Spatial type not supported.') return _format_geo_metadata(op, result, inline_metadata)
def translate_literal(expr, inline_metadata: bool = False) -> str: op = expr.op() value = op.value if isinstance(value, dt._WellKnownText): result = value.text elif isinstance(expr, ir.PointScalar): result = translate_point(value) elif isinstance(expr, ir.LineStringScalar): result = translate_linestring(value) elif isinstance(expr, ir.PolygonScalar): result = translate_polygon(value) elif isinstance(expr, ir.MultiLineStringScalar): result = translate_multilinestring(value) elif isinstance(expr, ir.MultiPointScalar): result = translate_multipoint(value) elif isinstance(expr, ir.MultiPolygonScalar): result = translate_multipolygon(value) else: raise ex.UnboundExpressionError('Geo Spatial type not supported.') return _format_geo_metadata(op, result, inline_metadata)
def execute_until_in_scope( expr, scope: Scope, timecontext: Optional[TimeContext] = None, aggcontext=None, clients=None, post_execute_=None, **kwargs, ) -> Scope: """Execute until our op is in `scope`. Parameters ---------- expr : ibis.expr.types.Expr scope : Scope timecontext : Optional[TimeContext] aggcontext : Optional[AggregationContext] clients : List[ibis.client.Client] kwargs : Mapping """ # these should never be None assert aggcontext is not None, 'aggcontext is None' assert clients is not None, 'clients is None' assert post_execute_ is not None, 'post_execute_ is None' # base case: our op has been computed (or is a leaf data node), so # return the corresponding value op = expr.op() if scope.get_value(op, timecontext) is not None: return scope if isinstance(op, ops.Literal): # special case literals to avoid the overhead of dispatching # execute_node return Scope( { op: execute_literal( op, op.value, expr.type(), aggcontext=aggcontext, **kwargs) }, timecontext, ) # 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)] # pre_executed_states is a list of states with same the length of # computable_args, these states are passed to each arg if timecontext: arg_timecontexts = compute_time_context( op, num_args=len(computable_args), timecontext=timecontext, clients=clients, ) else: arg_timecontexts = [None] * len(computable_args) pre_executed_scope = pre_execute( op, *clients, scope=scope, timecontext=timecontext, aggcontext=aggcontext, **kwargs, ) new_scope = scope.merge_scope(pre_executed_scope) # Short circuit: if pre_execute puts op in scope, then we don't need to # execute its computable_args if new_scope.get_value(op, timecontext) is not None: return new_scope # recursively compute each node's arguments until we've changed type. # compute_time_context should return with a list with the same length # as computable_args, the two lists will be zipping together for # further execution if len(arg_timecontexts) != len(computable_args): raise com.IbisError( 'arg_timecontexts differ with computable_arg in length ' f'for type:\n{type(op).__name__}.') scopes = [ execute_until_in_scope( arg, new_scope, timecontext=timecontext, aggcontext=aggcontext, post_execute_=post_execute_, clients=clients, **kwargs, ) if hasattr(arg, 'op') else Scope({arg: arg}, timecontext) for (arg, timecontext) in zip(computable_args, arg_timecontexts) ] # if we're unable to find data then raise an exception if not scopes and computable_args: 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 = new_scope.merge_scopes(scopes) # pass our computed arguments to this node's execute_node implementation data = [ new_scope.get_value(arg.op(), timecontext) if hasattr(arg, 'op') else arg for arg in computable_args ] result = execute_node( op, *data, scope=scope, timecontext=timecontext, aggcontext=aggcontext, clients=clients, **kwargs, ) computed = post_execute_(op, result, timecontext=timecontext) return Scope({op: computed}, timecontext)
def execute_until_in_scope(expr, scope, aggcontext=None, clients=None, post_execute_=None, **kwargs): """Execute until our op is in `scope`. Parameters ---------- expr : ibis.expr.types.Expr scope : Mapping aggcontext : Optional[AggregationContext] clients : List[ibis.client.Client] kwargs : Mapping """ # these should never be None assert aggcontext is not None, 'aggcontext is None' assert clients is not None, 'clients is None' assert post_execute_ is not None, 'post_execute_ is None' # base case: our op has been computed (or is a leaf data node), so # return the corresponding value op = expr.op() 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) } pre_executed_scope = pre_execute(op, *clients, scope=scope, aggcontext=aggcontext, **kwargs) new_scope = toolz.merge(scope, pre_executed_scope) # Short circuit: if pre_execute puts op in scope, then we don't need to # execute its computable_args if op in new_scope: return new_scope # 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_until_in_scope( arg, new_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 and computable_args: 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(new_scope, *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}
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 and computable_args: 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}