|
10 | 10 | import ibis.expr.builders as bl |
11 | 11 | import ibis.expr.datatypes as dt |
12 | 12 | import ibis.expr.operations as ops |
| 13 | +from ibis.common.annotations import ValidationError |
13 | 14 | from ibis.common.deferred import Deferred, _, deferrable |
14 | 15 | from ibis.common.grounds import Singleton |
15 | 16 | from ibis.expr.rewrites import rewrite_window_input |
16 | | -from ibis.expr.types.core import Expr, _binop |
| 17 | +from ibis.expr.types.core import Expr |
17 | 18 | from ibis.expr.types.rich import FixedTextJupyterMixin, to_rich |
18 | 19 | from ibis.util import deprecated, experimental, promote_list |
19 | 20 |
|
@@ -3119,6 +3120,57 @@ def _is_null_literal(value: Any) -> bool: |
3119 | 3120 | ) |
3120 | 3121 |
|
3121 | 3122 |
|
| 3123 | +def _binop(op_class: type[ops.Value], left: Value | Any, right: Value | Any) -> Value: |
| 3124 | + """Try to construct a binary operation between two Values. |
| 3125 | +
|
| 3126 | + Parameters |
| 3127 | + ---------- |
| 3128 | + op_class |
| 3129 | + An ops.Value that accepts two Value positional operands. |
| 3130 | + Not necessarily a ops.Binary subclass, |
| 3131 | + eg this works with ops.Repeat for string repetition. |
| 3132 | + left |
| 3133 | + Left operand. Can be a Value, or something coercible to a Value. |
| 3134 | + right |
| 3135 | + Right operand. Can be a Value, or something coercible to a Value. |
| 3136 | +
|
| 3137 | + Returns |
| 3138 | + ------- |
| 3139 | + ir.Value |
| 3140 | + A value expression |
| 3141 | +
|
| 3142 | + Examples |
| 3143 | + -------- |
| 3144 | + >>> import ibis |
| 3145 | + >>> import ibis.expr.operations as ops |
| 3146 | + >>> _binop(ops.TimeAdd, ibis.time("01:00"), ibis.interval(hours=1)) |
| 3147 | + TimeAdd(datetime.time(1, 0), 1h): datetime.time(1, 0) + 1 h |
| 3148 | + >>> _binop(ops.TimeAdd, 1, ibis.interval(hours=1)) |
| 3149 | + TimeAdd(datetime.time(0, 0, 1), 1h): datetime.time(0, 0, 1) + 1 h |
| 3150 | + >>> _binop(ops.Equals, 5, 2) |
| 3151 | + Equals(5, 2): 5 == 2 |
| 3152 | +
|
| 3153 | + This raises if the operation is known to be invalid between the two operands: |
| 3154 | +
|
| 3155 | + >>> _binop(ops.Equals, ibis.literal("foo"), 2) # quartodoc: +EXPECTED_FAILURE |
| 3156 | + Traceback (most recent call last): |
| 3157 | + ... |
| 3158 | + IbisTypeError: Arguments Literal(foo):string and Literal(2):int8 are not comparable |
| 3159 | +
|
| 3160 | + But returns NotImplemented if we aren't sure: |
| 3161 | +
|
| 3162 | + >>> _binop(ops.Equals, 5, ibis.table({"a": "int"})) |
| 3163 | + NotImplemented |
| 3164 | + """ |
| 3165 | + assert issubclass(op_class, ops.Value) |
| 3166 | + try: |
| 3167 | + node = op_class(left, right) |
| 3168 | + except (ValidationError, NotImplementedError): |
| 3169 | + return NotImplemented |
| 3170 | + else: |
| 3171 | + return node.to_expr() |
| 3172 | + |
| 3173 | + |
3122 | 3174 | public( |
3123 | 3175 | ValueExpr=Value, |
3124 | 3176 | ScalarExpr=Scalar, |
|
0 commit comments