This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-4153-c8502b3925519ca7907de91eddb44d120994d512 in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
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:
