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

github-merge-queue[bot] 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 e2c1e787c CLI: Show metadata location in `describe view` (#4153)
e2c1e787c is described below

commit e2c1e787c65e55c736b742da2ef8d6ca405641ed
Author: Kevin Liu <[email protected]>
AuthorDate: Sun Oct 25 04:23:40 2026 +0000

    CLI: Show metadata location in `describe view` (#4153)
    
    CLI: show metadata location in describe view
    
    Match describe table text output by including the view's metadata location,
    and document the view CLI commands.
    
    Co-authored-by: Copilot App <[email protected]>
---
 mkdocs/docs/cli.md        | 26 +++++++++++++++++++++++++-
 pyiceberg/cli/output.py   |  1 +
 tests/cli/test_console.py | 22 +++++++++++++++++++---
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/mkdocs/docs/cli.md b/mkdocs/docs/cli.md
index 7160c2e0d..c19924888 100644
--- a/mkdocs/docs/cli.md
+++ b/mkdocs/docs/cli.md
@@ -44,11 +44,12 @@ Options:
 
 Commands:
   create      Operation to create a namespace.
-  describe    Describe a namespace or a table.
+  describe    Describe a namespace, a table, or a view.
   drop        Operations to drop a namespace or table.
   files       List all the files of the table.
   list        List tables or namespaces.
   list-refs   List all the refs in the provided table.
+  list-views  List all views in a namespace.
   location    Return the location of the table.
   properties  Properties on tables/namespaces.
   rename      Rename a table.
@@ -254,3 +255,26 @@ To request purge for the underlying table files through 
the configured catalog,
 ➜  pyiceberg drop table nyc.taxis --purge
 Dropped table: nyc.taxis (purge requested)
 ```
+
+For catalogs that support views, you can also list, describe, and drop views:
+
+```sh
+➜  pyiceberg list-views nyc
+nyc.taxi_trips
+
+➜  pyiceberg describe --entity view nyc.taxi_trips
+View format version  1
+Metadata location    
s3://warehouse/nyc/taxi_trips/metadata/00001-b3a9c6e2-6c1f-4e47-9d4f-2f9a1d0e5c7b.metadata.json
+View UUID            fa6506c3-7681-40c8-86dc-e36561f83385
+Location             s3://warehouse/nyc/taxi_trips
+Current version      1
+Current schema       Schema, id=1
+                     ├── 1: VendorID: optional long
+                     └── 2: trip_distance: optional double
+SQL                  SQL representations
+                     └── spark: SELECT VendorID, trip_distance FROM nyc.taxis
+Properties           comment  Taxi trip distances
+
+➜  pyiceberg drop view nyc.taxi_trips
+Dropped view: nyc.taxi_trips
+```
diff --git a/pyiceberg/cli/output.py b/pyiceberg/cli/output.py
index 4a508d534..cb8e247bf 100644
--- a/pyiceberg/cli/output.py
+++ b/pyiceberg/cli/output.py
@@ -145,6 +145,7 @@ class ConsoleOutput(Output):
 
         output_table = self._table
         output_table.add_row("View format version", 
str(metadata.format_version))
+        output_table.add_row("Metadata location", view.metadata_location)
         output_table.add_row("View UUID", str(metadata.view_uuid))
         output_table.add_row("Location", metadata.location)
         output_table.add_row("Current version", 
str(metadata.current_version_id))
diff --git a/tests/cli/test_console.py b/tests/cli/test_console.py
index 2bf6651b7..ebf1a5a90 100644
--- a/tests/cli/test_console.py
+++ b/tests/cli/test_console.py
@@ -1209,7 +1209,11 @@ TEST_VIEW_METADATA: dict[str, Any] = {
 
 @pytest.fixture(name="catalog_with_view")
 def fixture_catalog_with_view(mocker: MockFixture, catalog: InMemoryCatalog) 
-> tuple[InMemoryCatalog, View]:
-    view = View(TEST_VIEW_IDENTIFIER, 
ViewMetadata.model_validate(TEST_VIEW_METADATA))
+    view = View(
+        TEST_VIEW_IDENTIFIER,
+        ViewMetadata.model_validate(TEST_VIEW_METADATA),
+        
metadata_location="s3://warehouse/default/my_view/metadata/metadata.json",
+    )
     catalog.list_views = MagicMock(return_value=[TEST_VIEW_IDENTIFIER])  # 
type: ignore
     catalog.load_view = MagicMock(return_value=view)  # type: ignore
     catalog.drop_view = MagicMock()  # type: ignore
@@ -1238,8 +1242,20 @@ def test_describe_view(catalog_with_view: 
tuple[InMemoryCatalog, View]) -> None:
     runner = CliRunner()
     result = runner.invoke(run, ["describe", "--entity=view", 
"default.my_view"])
     assert result.exit_code == 0
-    assert "b30125c8-7284-442c-9aea-15fee620737c" in result.output
-    assert "spark: SELECT * FROM my_table" in result.output
+    assert (
+        "\n".join([line.rstrip() for line in result.output.split("\n")])
+        == """View format version  1
+Metadata location    s3://warehouse/default/my_view/metadata/metadata.json
+View UUID            b30125c8-7284-442c-9aea-15fee620737c
+Location             s3://warehouse/default/my_view
+Current version      1
+Current schema       Schema, id=1
+                     └── 1: x: required long
+SQL                  SQL representations
+                     └── spark: SELECT * FROM my_table
+Properties
+"""
+    )
 
 
 def test_describe_view_does_not_exist(catalog: InMemoryCatalog) -> None:

Reply via email to