Skip to content

Commit

Permalink
fix(api): treat col == None or col == ibis.NA as col.isnull()
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrist committed May 3, 2024
1 parent 4e7a00c commit 74ce469
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 5 deletions.
10 changes: 10 additions & 0 deletions ibis/expr/types/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,3 +737,13 @@ def _binop(op_class: type[ops.Binary], left: ir.Value, right: ir.Value) -> ir.Va
return NotImplemented
else:
return node.to_expr()


def _is_null_literal(value: Any) -> bool:
"""Detect whether `value` will be treated by ibis as a null literal."""
if value is None:
return True
if isinstance(value, Expr):
op = value.op()
return isinstance(op, ops.Literal) and op.value is None
return False
10 changes: 5 additions & 5 deletions ibis/expr/types/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ibis.common.deferred import Deferred, _, deferrable
from ibis.common.grounds import Singleton
from ibis.expr.rewrites import rewrite_window_input
from ibis.expr.types.core import Expr, _binop, _FixedTextJupyterMixin
from ibis.expr.types.core import Expr, _binop, _FixedTextJupyterMixin, _is_null_literal
from ibis.expr.types.pretty import to_rich
from ibis.util import deprecated, warn_deprecated

Expand Down Expand Up @@ -1160,13 +1160,13 @@ def __hash__(self) -> int:
return super().__hash__()

def __eq__(self, other: Value) -> ir.BooleanValue:
if other is None:
return _binop(ops.IdenticalTo, self, other)
if _is_null_literal(other):
return self.isnull()
return _binop(ops.Equals, self, other)

def __ne__(self, other: Value) -> ir.BooleanValue:
if other is None:
return ~self.__eq__(other)
if _is_null_literal(other):
return self.notnull()
return _binop(ops.NotEquals, self, other)

def __ge__(self, other: Value) -> ir.BooleanValue:
Expand Down
14 changes: 14 additions & 0 deletions ibis/tests/expr/test_value_exprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,20 @@ def test_notnull(table):
assert isinstance(expr.op(), ops.NotNull)


@pytest.mark.parametrize(
"value",
[
param(lambda: None, id="none"),
param(lambda: ibis.NA, id="NA"),
param(lambda: ibis.literal(None, type="int32"), id="typed-null"),
],
)
def test_null_eq_and_ne(table, value):
other = value()
assert (table.a == other).equals(table.a.isnull())
assert (table.a != other).equals(table.a.notnull())


@pytest.mark.parametrize("column", ["e", "f"], ids=["float32", "double"])
def test_isnan_isinf_column(table, column):
expr = table[column].isnan()
Expand Down

0 comments on commit 74ce469

Please sign in to comment.