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 dab25362 Update `__repr__` for `initial-default` and `write-default` (#2287) dab25362 is described below commit dab25362831c9a2d6563b041b38f9698dc320d33 Author: Alex Stephen <1325798+ramblerap...@users.noreply.github.com> AuthorDate: Thu Aug 7 14:01:57 2025 -0700 Update `__repr__` for `initial-default` and `write-default` (#2287) <!-- 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 #1853 This adds a new repr function that ensures that `initial-default` and `write-default` will not appear if they are None. Unfortunately, this functionality isn't baked into Pydantic. # Rationale for this change __repr__ changes may be breaking. # Are these changes tested? Tests included. # Are there any user-facing changes? <!-- In the case of user-facing changes, please add the changelog label. --> --- 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 58225979..6872663f 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 @@ class NestedField(IcebergType): 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 2527f0e8..18eb909d 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()