def adjust_context_window(op, timecontext: Optional[TimeContext], **kwargs): new_timecontexts = [ timecontext for arg in op.inputs if is_computable_input(arg) ] if not timecontext: return new_timecontexts # adjust time context by preceding and following begin, end = timecontext result = [begin, end] preceding = op.window.preceding following = op.window.following if preceding is not None: if isinstance(preceding, ir.IntervalScalar): new_preceding = execute(preceding) else: new_preceding = preceding if new_preceding: result[0] = begin - new_preceding if following is not None: if isinstance(following, ir.IntervalScalar): new_following = execute(following) else: new_following = following if new_following: result[1] = end + new_following new_timecontexts = [ result for arg in op.inputs if is_computable_input(arg) ] return new_timecontexts
def test_is_computable_input(): class MyObject: def __init__(self, value: float) -> None: self.value = value def __getattr__(self, name: str) -> Any: return getattr(self.value, name) def __hash__(self) -> int: return hash((type(self), self.value)) def __eq__(self, other): return (isinstance(other, type(self)) and isinstance(self, type(other)) and self.value == other.value) def __float__(self) -> float: return self.value @execute_node.register(ops.Add, int, MyObject) def add_int_my_object(op, left, right, **kwargs): return left + right.value # This multimethod must be implemented to play nicely with other value # types like columns and literals. In other words, for a custom # non-expression object to play nicely it must somehow map to one of the # types in ibis/expr/datatypes.py @dt.infer.register(MyObject) def infer_my_object(_, **kwargs): return dt.float64 @is_computable_input.register(MyObject) def is_computable_input_my_object(_): return True one = ibis.literal(1) two = MyObject(2.0) assert is_computable_input(two) three = one + two four = three + 1 result = ibis.pandas.execute(four) assert result == 4.0 del execute_node[ops.Add, int, MyObject] execute_node.reorder() execute_node._cache.clear() del dt.infer.funcs[(MyObject, )] dt.infer.reorder() dt.infer._cache.clear()
def adjust_context_asof_join(op, timecontext: Optional[TimeContext], **kwargs): new_timecontexts = [ timecontext for arg in op.inputs if is_computable_input(arg) ] if not timecontext: return new_timecontexts begin, end = timecontext tolerance = op.tolerance if tolerance is not None: timedelta = execute(tolerance) # only backwards and adjust begin time only new_begin = begin - timedelta new_end = end # right table is the second node in children new_timecontexts[1] = (new_begin, new_end) return new_timecontexts