|
17 | 17 | from typing import Any, Hashable, Literal, TYPE_CHECKING |
18 | 18 |
|
19 | 19 | import bigframes_vendored.pandas.core.col as pd_col |
| 20 | +import numpy |
20 | 21 |
|
21 | 22 | from bigframes.core import agg_expressions, window_spec |
22 | 23 | import bigframes.core.expression as bf_expression |
@@ -56,14 +57,10 @@ def _apply_binary_op( |
56 | 57 | alignment: Literal["outer", "left"] = "outer", |
57 | 58 | reverse: bool = False, |
58 | 59 | ): |
59 | | - if isinstance(other, Expression): |
60 | | - other_value = other._value |
61 | | - else: |
62 | | - other_value = bf_expression.const(other) |
63 | 60 | if reverse: |
64 | | - return Expression(op.as_expr(other_value, self._value)) |
| 61 | + return Expression(op.as_expr(_as_bf_expr(other), self._value)) |
65 | 62 | else: |
66 | | - return Expression(op.as_expr(self._value, other_value)) |
| 63 | + return Expression(op.as_expr(self._value, _as_bf_expr(other))) |
67 | 64 |
|
68 | 65 | def __add__(self, other: Any) -> Expression: |
69 | 66 | return self._apply_binary_op(other, bf_ops.add_op) |
@@ -170,6 +167,34 @@ def str(self) -> strings.StringMethods: |
170 | 167 |
|
171 | 168 | return strings.StringMethods(self) |
172 | 169 |
|
| 170 | + def __array_ufunc__( |
| 171 | + self, ufunc: numpy.ufunc, method: __builtins__.str, *inputs, **kwargs |
| 172 | + ) -> Expression: |
| 173 | + """Used to support numpy ufuncs. |
| 174 | + See: https://numpy.org/doc/stable/reference/ufuncs.html |
| 175 | + """ |
| 176 | + # Only __call__ supported with zero arguments |
| 177 | + if method != "__call__" or len(inputs) > 2 or len(kwargs) > 0: |
| 178 | + return NotImplemented |
| 179 | + |
| 180 | + if len(inputs) == 1 and ufunc in bf_ops.NUMPY_TO_OP: |
| 181 | + op = bf_ops.NUMPY_TO_OP[ufunc] |
| 182 | + return Expression(op.as_expr(self._value)) |
| 183 | + if len(inputs) == 2 and ufunc in bf_ops.NUMPY_TO_BINOP: |
| 184 | + binop = bf_ops.NUMPY_TO_BINOP[ufunc] |
| 185 | + if inputs[0] is self: |
| 186 | + return Expression(binop.as_expr(self._value, _as_bf_expr(inputs[1]))) |
| 187 | + else: |
| 188 | + return Expression(binop.as_expr(_as_bf_expr(inputs[0]), self._value)) |
| 189 | + |
| 190 | + return NotImplemented |
| 191 | + |
| 192 | + |
| 193 | +def _as_bf_expr(arg: Any) -> bf_expression.Expression: |
| 194 | + if isinstance(arg, Expression): |
| 195 | + return arg._value |
| 196 | + return bf_expression.const(arg) |
| 197 | + |
173 | 198 |
|
174 | 199 | def col(col_name: Hashable) -> Expression: |
175 | 200 | return Expression(bf_expression.free_var(col_name)) |
|
0 commit comments