Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
971258c
Make SetPredicate and subclasses JSON serializable with Pydantic
Aniketsy Oct 2, 2025
8211bd0
Make SetPredicate and subclasses JSON serializable with Pydantic
Aniketsy Oct 2, 2025
4392e29
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
5ed46a8
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
22edad4
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
75532f9
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
6913b11
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
52768e2
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
0db2562
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
ed61130
Update tests/expressions/test_expressions.py
Aniketsy Oct 2, 2025
ebaf94f
Update tests/expressions/test_expressions.py
Aniketsy Oct 2, 2025
77e00b2
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
92cec6f
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
f09ba02
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
f196a72
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 2, 2025
3146904
Update pyiceberg/expressions/__init__.py
Aniketsy Oct 3, 2025
f922d17
Apply Ruff formatting fixes
Aniketsy Oct 3, 2025
45f07e4
Merge branch 'main' into fix/setpredicate-json-serialization
Aniketsy Oct 5, 2025
6482846
Fixed import error
Aniketsy Oct 6, 2025
110e4e3
Make SetPredicate and subclasses JSON serializable
Aniketsy Oct 8, 2025
d6d6423
Revert unrelated change
Fokko Oct 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions pyiceberg/expressions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
from pyiceberg.typedef import L, StructProtocol
from pyiceberg.types import DoubleType, FloatType, NestedField
from pyiceberg.utils.singleton import Singleton
from pyiceberg.typedef import IcebergBaseModel
from pydantic import Field


def _to_unbound_term(term: Union[str, UnboundTerm[Any]]) -> UnboundTerm[Any]:
Expand Down Expand Up @@ -559,8 +561,9 @@ def as_bound(self) -> Type[BoundNotNaN[L]]:
return BoundNotNaN[L]


class SetPredicate(UnboundPredicate[L], ABC):
literals: Set[Literal[L]]
class SetPredicate(UnboundPredicate[L], IcebergBaseModel, ABC):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class and init should be:

class SetPredicate(IcebergBaseModel, UnboundPredicate[L], ABC):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    type: TypingLiteral["in", "not-in"] = Field(default="in")
    literals: Set[Literal[L]] = Field(alias="items")

    def __init__(self, term: Union[str, UnboundTerm[Any]], literals: Union[Iterable[L], Iterable[Literal[L]]]):
        super().__init__(term=_to_unbound_term(term), items=_to_literal_set(literals))

type: str = Field(default="in", alias="type")
literals: Set[Literal[L]] = Field(alias="items")

def __init__(self, term: Union[str, UnboundTerm[Any]], literals: Union[Iterable[L], Iterable[Literal[L]]]):
super().__init__(term)
Expand Down Expand Up @@ -676,6 +679,8 @@ def as_unbound(self) -> Type[NotIn[L]]:


class In(SetPredicate[L]):
type: Literal["in"] = Field(default="in", alias="type")

def __new__( # type: ignore # pylint: disable=W0221
cls, term: Union[str, UnboundTerm[Any]], literals: Union[Iterable[L], Iterable[Literal[L]]]
) -> BooleanExpression:
Expand All @@ -698,6 +703,8 @@ def as_bound(self) -> Type[BoundIn[L]]:


class NotIn(SetPredicate[L], ABC):
type: str = Field(default="not-in", alias="type")

def __new__( # type: ignore # pylint: disable=W0221
cls, term: Union[str, UnboundTerm[Any]], literals: Union[Iterable[L], Iterable[Literal[L]]]
) -> BooleanExpression:
Expand All @@ -712,7 +719,7 @@ def __new__( # type: ignore # pylint: disable=W0221

def __invert__(self) -> In[L]:
"""Transform the Expression into its negated version."""
return In[L](self.term, self.literals)
return NotIn[L](self.term, self.literals)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be reverted:

Suggested change
return NotIn[L](self.term, self.literals)
return In[L](self.term, self.literals)


@property
def as_bound(self) -> Type[BoundNotIn[L]]:
Expand Down
7 changes: 7 additions & 0 deletions tests/expressions/test_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,13 @@ def test_not_in() -> None:
assert not_in == eval(repr(not_in))
assert not_in == pickle.loads(pickle.dumps(not_in))

def test_serialize_in() -> None:
pred = In(term="foo", literals=[1, 2, 3])
assert pred.model_dump_json() == '{"type":"in","term":"foo","value":[1,2,3]}'

def test_serialize_not_in() -> None:
pred = NotIn(term="foo", literals=[1, 2, 3])
assert pred.model_dump_json() == '{"type":"not-in","term":"foo","value":[1,2,3]}'

def test_bound_equal_to(term: BoundReference[Any]) -> None:
bound_equal_to = BoundEqualTo(term, literal("a"))
Expand Down