diff --git a/pyiceberg/expressions/__init__.py b/pyiceberg/expressions/__init__.py index d0824cc315..0b7a12ee58 100644 --- a/pyiceberg/expressions/__init__.py +++ b/pyiceberg/expressions/__init__.py @@ -341,12 +341,18 @@ def __getnewargs__(self) -> Tuple[BooleanExpression, BooleanExpression]: return (self.left, self.right) -class Not(BooleanExpression): +class Not(IcebergBaseModel, BooleanExpression): """NOT operation expression - logical negation.""" - child: BooleanExpression + model_config = ConfigDict(arbitrary_types_allowed=True) + + type: TypingLiteral["not"] = Field(default="not") + child: BooleanExpression = Field() + + def __init__(self, child: BooleanExpression, **_: Any) -> None: + super().__init__(child=child) - def __new__(cls, child: BooleanExpression) -> BooleanExpression: # type: ignore + def __new__(cls, child: BooleanExpression, **_: Any) -> BooleanExpression: # type: ignore if child is AlwaysTrue(): return AlwaysFalse() elif child is AlwaysFalse(): @@ -354,9 +360,12 @@ def __new__(cls, child: BooleanExpression) -> BooleanExpression: # type: ignore elif isinstance(child, Not): return child.child obj = super().__new__(cls) - obj.child = child return obj + def __str__(self) -> str: + """Return the string representation of the Not class.""" + return f"Not(child={self.child})" + def __repr__(self) -> str: """Return the string representation of the Not class.""" return f"Not(child={repr(self.child)})" diff --git a/tests/expressions/test_expressions.py b/tests/expressions/test_expressions.py index 5a0c8c9241..16bd7c273a 100644 --- a/tests/expressions/test_expressions.py +++ b/tests/expressions/test_expressions.py @@ -738,6 +738,12 @@ def test_not() -> None: assert not_ == pickle.loads(pickle.dumps(not_)) +def test_not_json_serialization_and_deserialization() -> None: + not_expr = Not(GreaterThan("a", 22)) + json_str = not_expr.model_dump_json() + assert json_str == """{"type":"not","child":{"term":"a","type":"gt","value":22}}""" + + def test_always_true() -> None: always_true = AlwaysTrue() assert always_true.model_dump_json() == '"true"'