From 383d5cf4b439fd0df5e2b56072a399d53fbbc069 Mon Sep 17 00:00:00 2001 From: Alex Stephen Date: Tue, 5 Aug 2025 14:49:19 -0700 Subject: [PATCH] Change __repr__ method to only print if non-None --- pyiceberg/types.py | 19 +++++++++++++++++-- tests/test_types.py | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/pyiceberg/types.py b/pyiceberg/types.py index 5822597952..6872663f84 100644 --- a/pyiceberg/types.py +++ b/pyiceberg/types.py @@ -340,8 +340,8 @@ class NestedField(IcebergType): field_type: SerializeAsAny[IcebergType] = Field(alias="type") required: bool = Field(default=False) doc: Optional[str] = Field(default=None, repr=False) - initial_default: Optional[DefaultValue] = Field(alias="initial-default", default=None, repr=False) # type: ignore - write_default: Optional[DefaultValue] = Field(alias="write-default", default=None, repr=False) # type: ignore + initial_default: Optional[DefaultValue] = Field(alias="initial-default", default=None, repr=True) # type: ignore + write_default: Optional[DefaultValue] = Field(alias="write-default", default=None, repr=True) # type: ignore @field_validator("field_type", mode="before") def convert_field_type(cls, v: Any) -> IcebergType: @@ -401,6 +401,21 @@ def __str__(self) -> str: req = "required" if self.required else "optional" return f"{self.field_id}: {self.name}: {req} {self.field_type}{doc}" + def __repr__(self) -> str: + """Return the string representation of the NestedField class.""" + parts = [ + f"field_id={self.field_id}", + f"name={self.name!r}", + f"field_type={self.field_type!r}", + f"required={self.required}", + ] + if self.initial_default is not None: + parts.append(f"initial_default={self.initial_default!r}") + if self.write_default is not None: + parts.append(f"write_default={self.write_default!r}") + + return f"NestedField({', '.join(parts)})" + def __getnewargs__(self) -> Tuple[int, str, IcebergType, bool, Optional[str]]: """Pickle the NestedField class.""" return (self.field_id, self.name, self.field_type, self.required, self.doc) diff --git a/tests/test_types.py b/tests/test_types.py index 2527f0e822..18eb909d09 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -525,6 +525,21 @@ def test_repr_decimal() -> None: assert repr(DecimalType(19, 25)) == "DecimalType(precision=19, scale=25)" +def test_repr_nested_field_default_nones_should_not_appear() -> None: + assert ( + repr(NestedField(1, "required_field", StringType(), required=False, initial_default=None, write_default=None)) + == "NestedField(field_id=1, name='required_field', field_type=StringType(), required=False)" + ) + assert ( + repr(NestedField(1, "required_field", StringType(), required=False, initial_default="hello", write_default=None)) + == "NestedField(field_id=1, name='required_field', field_type=StringType(), required=False, initial_default='hello')" + ) + assert ( + repr(NestedField(1, "required_field", StringType(), required=False, initial_default="hello", write_default="bye")) + == "NestedField(field_id=1, name='required_field', field_type=StringType(), required=False, initial_default='hello', write_default='bye')" + ) + + def test_serialization_nestedfield() -> None: expected = '{"id":1,"name":"required_field","type":"string","required":true,"doc":"this is a doc"}' actual = NestedField(1, "required_field", StringType(), True, "this is a doc").model_dump_json()