From a01f9982b7633093c64d357e86d9cf0e62928325 Mon Sep 17 00:00:00 2001 From: Fokko Date: Fri, 21 Feb 2025 09:44:53 +0100 Subject: [PATCH] Add syntactic sugar for `and` and `or` operation I got inspired by Arrow that also allows for this. --- pyiceberg/expressions/__init__.py | 14 ++++++++++++++ tests/expressions/test_expressions.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/pyiceberg/expressions/__init__.py b/pyiceberg/expressions/__init__.py index 830637aa99..8b006a28f1 100644 --- a/pyiceberg/expressions/__init__.py +++ b/pyiceberg/expressions/__init__.py @@ -64,6 +64,20 @@ class BooleanExpression(ABC): def __invert__(self) -> BooleanExpression: """Transform the Expression into its negated version.""" + def __and__(self, other: BooleanExpression) -> BooleanExpression: + """Perform and operation on another expression.""" + if not isinstance(other, BooleanExpression): + raise ValueError(f"Expected BooleanExpression, got: {other}") + + return And(self, other) + + def __or__(self, other: BooleanExpression) -> BooleanExpression: + """Perform or operation on another expression.""" + if not isinstance(other, BooleanExpression): + raise ValueError(f"Expected BooleanExpression, got: {other}") + + return Or(self, other) + class Term(Generic[L], ABC): """A simple expression that evaluates to a value.""" diff --git a/tests/expressions/test_expressions.py b/tests/expressions/test_expressions.py index 87856a04f6..e8ca7fdd0a 100644 --- a/tests/expressions/test_expressions.py +++ b/tests/expressions/test_expressions.py @@ -698,21 +698,35 @@ def test_and() -> None: null = IsNull(Reference("a")) nan = IsNaN(Reference("b")) and_ = And(null, nan) + + # Some syntactic sugar + assert and_ == null & nan + assert str(and_) == f"And(left={str(null)}, right={str(nan)})" assert repr(and_) == f"And(left={repr(null)}, right={repr(nan)})" assert and_ == eval(repr(and_)) assert and_ == pickle.loads(pickle.dumps(and_)) + with pytest.raises(ValueError, match="Expected BooleanExpression, got: abc"): + null & "abc" # type: ignore + def test_or() -> None: null = IsNull(Reference("a")) nan = IsNaN(Reference("b")) or_ = Or(null, nan) + + # Some syntactic sugar + assert or_ == null | nan + assert str(or_) == f"Or(left={str(null)}, right={str(nan)})" assert repr(or_) == f"Or(left={repr(null)}, right={repr(nan)})" assert or_ == eval(repr(or_)) assert or_ == pickle.loads(pickle.dumps(or_)) + with pytest.raises(ValueError, match="Expected BooleanExpression, got: abc"): + null | "abc" # type: ignore + def test_not() -> None: null = IsNull(Reference("a"))