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: