This is an automated email from the ASF dual-hosted git repository.

kevinjqliu 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 045dd10a feat: add support for setting and removing table properties 
on console (#2153)
045dd10a is described below

commit 045dd10a45cbf0b82b095b5bde47f4731a3bf88b
Author: Sébastien Brochet <[email protected]>
AuthorDate: Mon Jul 7 00:42:41 2025 +0200

    feat: add support for setting and removing table properties on console 
(#2153)
    
    <!--
    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 #${GITHUB_ISSUE_ID} -->
    
    # Rationale for this change
    
    Hello!
    
    Setting or removing table properties on console currently raise a
    `Writing is WIP` error. This PR adds the code to set and remove table
    properties.
    
    # Are these changes tested?
    
    Yes
    
    # Are there any user-facing changes?
    
    Yes, setting and removing table properties on console now works.
    
    <!-- In the case of user-facing changes, please add the changelog label.
    -->
---
 mkdocs/docs/cli.md        | 16 ++++++++++++++++
 pyiceberg/cli/console.py  | 12 +++++++-----
 tests/cli/test_console.py | 16 ++++++++--------
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/mkdocs/docs/cli.md b/mkdocs/docs/cli.md
index 28e44955..984e0df4 100644
--- a/mkdocs/docs/cli.md
+++ b/mkdocs/docs/cli.md
@@ -219,3 +219,19 @@ Or output in JSON for automation:
   }
 }
 ```
+
+You can also add, update or remove properties on tables or namespaces:
+
+```sh
+➜  pyiceberg properties set table nyc.taxis 
write.metadata.delete-after-commit.enabled true
+Set write.metadata.delete-after-commit.enabled=true on nyc.taxis
+
+➜  pyiceberg properties get table nyc.taxis
+write.metadata.delete-after-commit.enabled  true
+
+➜  pyiceberg properties remove table nyc.taxis 
write.metadata.delete-after-commit.enabled
+Property write.metadata.delete-after-commit.enabled removed from nyc.taxis
+
+➜  pyiceberg properties get table nyc.taxis 
write.metadata.delete-after-commit.enabled
+Could not find property write.metadata.delete-after-commit.enabled on nyc.taxis
+```
diff --git a/pyiceberg/cli/console.py b/pyiceberg/cli/console.py
index 3fbd9c9f..d918f879 100644
--- a/pyiceberg/cli/console.py
+++ b/pyiceberg/cli/console.py
@@ -361,9 +361,10 @@ def table(ctx: Context, identifier: str, property_name: 
str, property_value: str
     catalog, output = _catalog_and_output(ctx)
     identifier_tuple = Catalog.identifier_to_tuple(identifier)
 
-    _ = catalog.load_table(identifier_tuple)
-    output.text(f"Setting {property_name}={property_value} on {identifier}")
-    raise NotImplementedError("Writing is WIP")
+    table = catalog.load_table(identifier_tuple)
+    with table.transaction() as tx:
+        tx.set_properties({property_name: property_value})
+    output.text(f"Set {property_name}={property_value} on {identifier}")
 
 
 @properties.group()
@@ -398,8 +399,9 @@ def table(ctx: Context, identifier: str, property_name: 
str) -> None:  # noqa: F
     catalog, output = _catalog_and_output(ctx)
     table = catalog.load_table(identifier)
     if property_name in table.metadata.properties:
-        output.exception(NotImplementedError("Writing is WIP"))
-        ctx.exit(1)
+        with table.transaction() as tx:
+            tx.remove_properties(property_name)
+        output.text(f"Property {property_name} removed from {identifier}")
     else:
         raise NoSuchPropertyException(f"Property {property_name} does not 
exist on {identifier}")
 
diff --git a/tests/cli/test_console.py b/tests/cli/test_console.py
index fe375eb2..a0e95522 100644
--- a/tests/cli/test_console.py
+++ b/tests/cli/test_console.py
@@ -476,8 +476,8 @@ def test_properties_set_table(catalog: InMemoryCatalog) -> 
None:
 
     runner = CliRunner()
     result = runner.invoke(run, ["properties", "set", "table", 
"default.my_table", "location", "s3://new_location"])
-    assert result.exit_code == 1
-    assert "Writing is WIP" in result.output
+    assert result.exit_code == 0
+    assert result.output == "Set location=s3://new_location on 
default.my_table\n"
 
 
 def test_properties_set_table_does_not_exist(catalog: InMemoryCatalog) -> None:
@@ -518,8 +518,8 @@ def test_properties_remove_table(catalog: InMemoryCatalog) 
-> None:
 
     runner = CliRunner()
     result = runner.invoke(run, ["properties", "remove", "table", 
"default.my_table", "read.split.target.size"])
-    assert result.exit_code == 1
-    assert "Writing is WIP" in result.output
+    assert result.exit_code == 0
+    assert result.output == "Property read.split.target.size removed from 
default.my_table\n"
 
 
 def test_properties_remove_table_property_does_not_exists(catalog: 
InMemoryCatalog) -> None:
@@ -894,8 +894,8 @@ def test_json_properties_set_table(catalog: 
InMemoryCatalog) -> None:
     result = runner.invoke(
         run, ["--output=json", "properties", "set", "table", 
"default.my_table", "location", "s3://new_location"]
     )
-    assert result.exit_code == 1
-    assert "Writing is WIP" in result.output
+    assert result.exit_code == 0
+    assert result.output == """"Set location=s3://new_location on 
default.my_table"\n"""
 
 
 def test_json_properties_set_table_does_not_exist(catalog: InMemoryCatalog) -> 
None:
@@ -938,8 +938,8 @@ def test_json_properties_remove_table(catalog: 
InMemoryCatalog) -> None:
 
     runner = CliRunner()
     result = runner.invoke(run, ["--output=json", "properties", "remove", 
"table", "default.my_table", "read.split.target.size"])
-    assert result.exit_code == 1
-    assert "Writing is WIP" in result.output
+    assert result.exit_code == 0
+    assert result.output == """"Property read.split.target.size removed from 
default.my_table"\n"""
 
 
 def test_json_properties_remove_table_property_does_not_exists(catalog: 
InMemoryCatalog) -> None:

Reply via email to