This is an automated email from the ASF dual-hosted git repository.
fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
The following commit(s) were added to refs/heads/main by this push:
new 9ce7619c Feat/json serialize or expression (#2565)
9ce7619c is described below
commit 9ce7619cc8f1fe2e184f0b3d384f9a70193f19f6
Author: Jaime Fernández <[email protected]>
AuthorDate: Wed Oct 22 17:44:29 2025 +0200
Feat/json serialize or expression (#2565)
<!--
Thanks for opening a pull request!
-->
<!-- In the case this PR will resolve an issue, please replace
${GITHUB_ISSUE_ID} below with the actual Github issue id. -->
Closes https://github.com/apache/iceberg-python/issues/2519
# Rationale for this change
## Are these changes tested?
yes
## Are there any user-facing changes?
<!-- In the case of user-facing changes, please add the changelog label.
-->
---
pyiceberg/expressions/__init__.py | 17 +++++++++++++----
tests/expressions/test_expressions.py | 11 +++++++++++
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/pyiceberg/expressions/__init__.py
b/pyiceberg/expressions/__init__.py
index 16210bae..339fd9cd 100644
--- a/pyiceberg/expressions/__init__.py
+++ b/pyiceberg/expressions/__init__.py
@@ -33,7 +33,7 @@ from typing import (
)
from typing import Literal as TypingLiteral
-from pydantic import Field
+from pydantic import ConfigDict, Field
from pyiceberg.expressions.literals import (
AboveMax,
@@ -302,12 +302,19 @@ class And(BooleanExpression):
return (self.left, self.right)
-class Or(BooleanExpression):
+class Or(IcebergBaseModel, BooleanExpression):
"""OR operation expression - logical disjunction."""
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+ type: TypingLiteral["or"] = Field(default="or", alias="type")
left: BooleanExpression
right: BooleanExpression
+ def __init__(self, left: BooleanExpression, right: BooleanExpression,
*rest: BooleanExpression) -> None:
+ if isinstance(self, Or) and not hasattr(self, "left") and not
hasattr(self, "right"):
+ super().__init__(left=left, right=right)
+
def __new__(cls, left: BooleanExpression, right: BooleanExpression, *rest:
BooleanExpression) -> BooleanExpression: # type: ignore
if rest:
return _build_balanced_tree(Or, (left, right, *rest))
@@ -319,10 +326,12 @@ class Or(BooleanExpression):
return left
else:
obj = super().__new__(cls)
- obj.left = left
- obj.right = right
return obj
+ def __str__(self) -> str:
+ """Return the string representation of the Or class."""
+ return f"{str(self.__class__.__name__)}(left={repr(self.left)},
right={repr(self.right)})"
+
def __eq__(self, other: Any) -> bool:
"""Return the equality of two instances of the Or class."""
return self.left == other.left and self.right == other.right if
isinstance(other, Or) else False
diff --git a/tests/expressions/test_expressions.py
b/tests/expressions/test_expressions.py
index 63673fda..2a57fb66 100644
--- a/tests/expressions/test_expressions.py
+++ b/tests/expressions/test_expressions.py
@@ -714,6 +714,17 @@ def test_or() -> None:
null | "abc" # type: ignore
+def test_or_serialization() -> None:
+ left = EqualTo("a", 10)
+ right = EqualTo("b", 20)
+ or_ = Or(left, right)
+
+ assert (
+ or_.model_dump_json()
+ ==
'{"type":"or","left":{"term":"a","type":"eq","value":10},"right":{"term":"b","type":"eq","value":20}}'
+ )
+
+
def test_not() -> None:
null = IsNull(Reference("a"))
not_ = Not(null)