Skip to content

Commit b0380fc

Browse files
committed
Add replace_tag to ManageSnapshots
1 parent 58749a3 commit b0380fc

2 files changed

Lines changed: 80 additions & 1 deletion

File tree

pyiceberg/table/update/snapshot.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,36 @@ def remove_tag(self, tag_name: str) -> ManageSnapshots:
10981098
"""
10991099
return self._remove_ref_snapshot(ref_name=tag_name)
11001100

1101+
def replace_tag(self, tag_name: str, snapshot_id: int) -> ManageSnapshots:
1102+
"""
1103+
Replace the tag with the given name to point to the specified snapshot.
1104+
1105+
Args:
1106+
tag_name (str): Tag to replace
1107+
snapshot_id (int): new snapshot id for the given tag
1108+
Returns:
1109+
This for method chaining
1110+
"""
1111+
self._commit_if_ref_updates_exist()
1112+
1113+
refs = self._transaction.table_metadata.refs
1114+
if tag_name not in refs:
1115+
raise ValueError(f"Tag does not exist: {tag_name}")
1116+
1117+
ref = refs[tag_name]
1118+
if ref.snapshot_ref_type != SnapshotRefType.TAG:
1119+
raise ValueError(f"Ref {tag_name} is not a tag")
1120+
1121+
update, requirement = self._transaction._set_ref_snapshot(
1122+
snapshot_id=snapshot_id,
1123+
ref_name=tag_name,
1124+
type=SnapshotRefType.TAG,
1125+
max_ref_age_ms=ref.max_ref_age_ms,
1126+
)
1127+
self._updates += update
1128+
self._requirements += requirement
1129+
return self
1130+
11011131
def create_branch(
11021132
self,
11031133
snapshot_id: int,

tests/integration/test_snapshot_operations.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
from pyiceberg.catalog import Catalog
2525
from pyiceberg.table import Table
26-
from pyiceberg.table.refs import SnapshotRef
26+
from pyiceberg.table.refs import SnapshotRef, SnapshotRefType
2727

2828

2929
@pytest.fixture
@@ -107,6 +107,55 @@ def test_remove_branch(catalog: Catalog) -> None:
107107
assert tbl.metadata.refs.get(branch_name, None) is None
108108

109109

110+
@pytest.mark.integration
111+
@pytest.mark.parametrize("catalog", [lf("session_catalog_hive"), lf("session_catalog")])
112+
def test_replace_tag(catalog: Catalog) -> None:
113+
identifier = "default.test_table_snapshot_operations"
114+
tbl = catalog.load_table(identifier)
115+
assert len(tbl.history()) > 2
116+
117+
current_snapshot_id = tbl.history()[-1].snapshot_id
118+
older_snapshot_id = tbl.history()[-2].snapshot_id
119+
120+
tag_name = "my-tag"
121+
tbl.manage_snapshots().create_tag(older_snapshot_id, tag_name, 1).commit()
122+
tag = tbl.metadata.refs.get(tag_name)
123+
assert tag is not None
124+
assert tag.snapshot_id == older_snapshot_id
125+
assert tag.snapshot_ref_type == SnapshotRefType.TAG
126+
assert tag.max_ref_age_ms == 1
127+
128+
tbl.manage_snapshots().replace_tag(tag_name=tag_name, snapshot_id=current_snapshot_id).commit()
129+
130+
tag = tbl.metadata.refs.get(tag_name)
131+
assert tag is not None
132+
assert tag.snapshot_id == current_snapshot_id
133+
assert tag.snapshot_ref_type == SnapshotRefType.TAG
134+
assert tag.max_ref_age_ms == 1
135+
136+
137+
@pytest.mark.integration
138+
@pytest.mark.parametrize("catalog", [lf("session_catalog_hive"), lf("session_catalog")])
139+
def test_replace_missing_tag(catalog: Catalog) -> None:
140+
identifier = "default.test_table_snapshot_operations"
141+
tbl = catalog.load_table(identifier)
142+
snapshot_id = tbl.history()[-1].snapshot_id
143+
144+
with pytest.raises(ValueError, match="Tag does not exist: test"):
145+
tbl.manage_snapshots().replace_tag(tag_name="test", snapshot_id=snapshot_id).commit()
146+
147+
148+
@pytest.mark.integration
149+
@pytest.mark.parametrize("catalog", [lf("session_catalog_hive"), lf("session_catalog")])
150+
def test_replace_tag_with_branch(catalog: Catalog) -> None:
151+
identifier = "default.test_table_snapshot_operations"
152+
tbl = catalog.load_table(identifier)
153+
snapshot_id = tbl.history()[-1].snapshot_id
154+
155+
with pytest.raises(ValueError, match="Ref main is not a tag"):
156+
tbl.manage_snapshots().replace_tag(tag_name="main", snapshot_id=snapshot_id).commit()
157+
158+
110159
@pytest.mark.integration
111160
@pytest.mark.parametrize("catalog", [lf("session_catalog_hive"), lf("session_catalog")])
112161
def test_set_current_snapshot(catalog: Catalog) -> None:

0 commit comments

Comments
 (0)