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
…9114)

Co-authored-by: Phillip Cloud <[email protected]>
  • Loading branch information
jcrist and cpcloud committed May 6, 2024
1 parent 829e0fd commit 711bf9f
Show file tree
Hide file tree
Showing 3 changed files with 31 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
14 changes: 9 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,17 @@ 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()
elif _is_null_literal(self):
return other.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()
elif _is_null_literal(self):
return other.notnull()
return _binop(ops.NotEquals, self, other)

def __ge__(self, other: Value) -> ir.BooleanValue:
Expand Down
12 changes: 12 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,18 @@ def test_notnull(table):
assert isinstance(expr.op(), ops.NotNull)


@pytest.mark.parametrize(
"value",
[None, ibis.NA, ibis.literal(None, type="int32")],
ids=["none", "NA", "typed-null"],
)
def test_null_eq_and_ne(table, value):
assert (table.a == value).equals(table.a.isnull())
assert (value == table.a).equals(table.a.isnull())
assert (table.a != value).equals(table.a.notnull())
assert (value != table.a).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 711bf9f

Please sign in to comment.