Skip to content

Commit 95fd03e

Browse files
committed
Align upgrade path with the Java implementation
Support upgrading via the format-version table property in set_properties, matching TableMetadata.replaceProperties in Java: the property triggers UpgradeFormatVersionUpdate instead of being stored. Add tests for parity with TestTableMetadata and TestRowLineageMetadata: direct v1-to-v3 upgrade, same-version no-op, and property-based upgrade.
1 parent 44631e0 commit 95fd03e

2 files changed

Lines changed: 50 additions & 3 deletions

File tree

pyiceberg/table/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from functools import cached_property
2727
from itertools import chain
2828
from types import TracebackType
29-
from typing import TYPE_CHECKING, Any, TypeVar
29+
from typing import TYPE_CHECKING, Any, TypeVar, cast
3030

3131
from pydantic import Field
3232

@@ -316,6 +316,9 @@ def set_properties(self, properties: Properties = EMPTY_DICT, **kwargs: Any) ->
316316
317317
When a property is already set, it will be overwritten.
318318
319+
Setting the `format-version` property upgrades the table to that format
320+
version instead of storing it as a property.
321+
319322
Args:
320323
properties: The properties set on the table.
321324
kwargs: properties can also be pass as kwargs.
@@ -325,8 +328,12 @@ def set_properties(self, properties: Properties = EMPTY_DICT, **kwargs: Any) ->
325328
"""
326329
if properties and kwargs:
327330
raise ValueError("Cannot pass both properties and kwargs")
328-
updates = properties or kwargs
329-
return self._apply((SetPropertiesUpdate(updates=updates),))
331+
updates = dict(properties or kwargs)
332+
if (new_format_version := updates.pop(TableProperties.FORMAT_VERSION, None)) is not None:
333+
self.upgrade_table_version(format_version=cast(TableVersion, int(new_format_version)))
334+
if updates:
335+
return self._apply((SetPropertiesUpdate(updates=updates),))
336+
return self
330337

331338
def _set_ref_snapshot(
332339
self,

tests/table/test_init.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,46 @@ def test_update_metadata_upgrade_to_v3(table_v2: Table) -> None:
12551255
assert validated.next_row_id == 0
12561256

12571257

1258+
def test_update_metadata_upgrade_v1_to_v3(table_v1: Table) -> None:
1259+
from pyiceberg.table.metadata import TableMetadataV3
1260+
1261+
new_metadata = update_table_metadata(table_v1.metadata, (UpgradeFormatVersionUpdate(format_version=3),))
1262+
assert isinstance(new_metadata, TableMetadataV3)
1263+
assert new_metadata.format_version == 3
1264+
assert new_metadata.next_row_id == 0
1265+
1266+
# rebuild the metadata to trigger validation
1267+
validated = TableMetadataUtil.parse_obj(copy(new_metadata.model_dump()))
1268+
assert validated.format_version == 3
1269+
assert validated.next_row_id == 0
1270+
1271+
1272+
def test_update_metadata_upgrade_same_version_is_noop(table_v2: Table) -> None:
1273+
new_metadata = update_table_metadata(table_v2.metadata, (UpgradeFormatVersionUpdate(format_version=2),))
1274+
assert new_metadata == table_v2.metadata
1275+
assert new_metadata.format_version == 2
1276+
1277+
1278+
def test_set_properties_format_version_upgrades(table_v2: Table) -> None:
1279+
transaction = table_v2.transaction()
1280+
transaction.set_properties({"format-version": "3", "owner": "test"})
1281+
1282+
assert transaction.table_metadata.format_version == 3
1283+
assert transaction.table_metadata.next_row_id == 0
1284+
assert transaction.table_metadata.properties["owner"] == "test"
1285+
assert "format-version" not in transaction.table_metadata.properties
1286+
assert UpgradeFormatVersionUpdate(format_version=3) in transaction._updates
1287+
1288+
1289+
def test_set_properties_same_format_version_is_noop(table_v2: Table) -> None:
1290+
transaction = table_v2.transaction()
1291+
transaction.set_properties({"format-version": "2"})
1292+
1293+
assert transaction.table_metadata.format_version == 2
1294+
assert "format-version" not in transaction.table_metadata.properties
1295+
assert transaction._updates == ()
1296+
1297+
12581298
def test_update_metadata_schema_immutability(
12591299
table_v2_with_fixed_and_decimal_types: TableMetadataV2,
12601300
) -> None:

0 commit comments

Comments
 (0)