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

lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 58819c9885 [python] Add table_type parameter support for list_tables 
API (#7291)
58819c9885 is described below

commit 58819c988524cd535b99c389e80dfca62a124166
Author: Jiajia Li <[email protected]>
AuthorDate: Wed Feb 25 10:22:17 2026 +0800

    [python] Add table_type parameter support for list_tables API (#7291)
---
 paimon-python/pypaimon/api/rest_api.py             |   9 +-
 .../pypaimon/catalog/rest/rest_catalog.py          |   6 +-
 paimon-python/pypaimon/tests/rest/api_test.py      | 130 +++++++++++++++++++++
 paimon-python/pypaimon/tests/rest/rest_server.py   |  12 ++
 4 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/paimon-python/pypaimon/api/rest_api.py 
b/paimon-python/pypaimon/api/rest_api.py
index 6b871ca58e..dc2c02104b 100755
--- a/paimon-python/pypaimon/api/rest_api.py
+++ b/paimon-python/pypaimon/api/rest_api.py
@@ -46,6 +46,7 @@ class RESTApi:
     PAGE_TOKEN = "pageToken"
     DATABASE_NAME_PATTERN = "databaseNamePattern"
     TABLE_NAME_PATTERN = "tableNamePattern"
+    TABLE_TYPE = "tableType"
     TOKEN_EXPIRATION_SAFE_TIME_MILLIS = 3_600_000
 
     def __init__(self, options: Union[Options, Dict[str, str]], 
config_required: bool = True):
@@ -228,6 +229,7 @@ class RESTApi:
             max_results: Optional[int] = None,
             page_token: Optional[str] = None,
             table_name_pattern: Optional[str] = None,
+            table_type: Optional[str] = None,
     ) -> PagedList[str]:
         if not database_name or not database_name.strip():
             raise ValueError("Database name cannot be empty")
@@ -235,7 +237,12 @@ class RESTApi:
         response = self.client.get_with_params(
             self.resource_paths.tables(database_name),
             self.__build_paged_query_params(
-                max_results, page_token, {self.TABLE_NAME_PATTERN: 
table_name_pattern}
+                max_results,
+                page_token,
+                {
+                    self.TABLE_NAME_PATTERN: table_name_pattern,
+                    self.TABLE_TYPE: table_type,
+                },
             ),
             ListTablesResponse,
             self.rest_auth_function,
diff --git a/paimon-python/pypaimon/catalog/rest/rest_catalog.py 
b/paimon-python/pypaimon/catalog/rest/rest_catalog.py
index c7c0e91052..9cf138c254 100644
--- a/paimon-python/pypaimon/catalog/rest/rest_catalog.py
+++ b/paimon-python/pypaimon/catalog/rest/rest_catalog.py
@@ -172,14 +172,16 @@ class RESTCatalog(Catalog):
             database_name: str,
             max_results: Optional[int] = None,
             page_token: Optional[str] = None,
-            table_name_pattern: Optional[str] = None
+            table_name_pattern: Optional[str] = None,
+            table_type: Optional[str] = None
     ) -> PagedList[str]:
         try:
             return self.rest_api.list_tables_paged(
                 database_name,
                 max_results,
                 page_token,
-                table_name_pattern
+                table_name_pattern,
+                table_type
             )
         except NoSuchResourceException as e:
             raise DatabaseNotExistException(database_name) from e
diff --git a/paimon-python/pypaimon/tests/rest/api_test.py 
b/paimon-python/pypaimon/tests/rest/api_test.py
index e70d99fe42..b43c16a81e 100644
--- a/paimon-python/pypaimon/tests/rest/api_test.py
+++ b/paimon-python/pypaimon/tests/rest/api_test.py
@@ -331,3 +331,133 @@ class ApiTest(unittest.TestCase):
         with self.assertRaises(ValueError) as context:
             rest_api.commit_snapshot(Mock(), "uuid", Mock(), None)
         self.assertIn("Statistics cannot be None", str(context.exception))
+
+    def test_list_tables_paged_with_table_type_param(self):
+        config = ConfigResponse(defaults={"prefix": "mock-test"})
+        token = str(uuid.uuid4())
+        server = RESTCatalogServer(
+            data_path="/tmp/test_warehouse",
+            auth_provider=BearTokenAuthProvider(token),
+            config=config,
+            warehouse="test_warehouse"
+        )
+        try:
+            server.start()
+
+            server.database_store.update({
+                "default": server.mock_database("default", {"env": "test"})
+            })
+
+            data_fields = [
+                DataField(0, "id", AtomicType("INT"), "id"),
+            ]
+            table_schema = TableSchema(
+                TableSchema.CURRENT_VERSION,
+                len(data_fields),
+                data_fields,
+                len(data_fields),
+                [],
+                [],
+                {"type": "table"},
+                "",
+            )
+            format_table_schema = TableSchema(
+                TableSchema.CURRENT_VERSION,
+                len(data_fields),
+                data_fields,
+                len(data_fields),
+                [],
+                [],
+                {"type": "format-table"},
+                "",
+            )
+            iceberg_table_schema = TableSchema(
+                TableSchema.CURRENT_VERSION,
+                len(data_fields),
+                data_fields,
+                len(data_fields),
+                [],
+                [],
+                {"type": "iceberg-table"},
+                "",
+            )
+            server.table_metadata_store.update({
+                "default.normal_table_1": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=table_schema
+                ),
+                "default.format_table_1": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=format_table_schema
+                ),
+                "default.iceberg_table_1": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=iceberg_table_schema
+                ),
+                "default.normal_table_2": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=table_schema
+                ),
+                "default.format_table_2": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=format_table_schema
+                ),
+                "default.iceberg_table_2": TableMetadata(
+                    uuid=str(uuid.uuid4()),
+                    is_external=True,
+                    schema=iceberg_table_schema
+                ),
+            })
+
+            options = {
+                'uri': f"http://localhost:{server.port}";,
+                'warehouse': 'test_warehouse',
+                'dlf.region': 'cn-hangzhou',
+                "token.provider": "bear",
+                'token': token
+            }
+            rest_api = RESTApi(options)
+
+            all_result = rest_api.list_tables_paged("default")
+            table_result = rest_api.list_tables_paged("default", 
table_type="table")
+            format_table_result = rest_api.list_tables_paged("default", 
table_type="format-table")
+            iceberg_table_result = rest_api.list_tables_paged("default", 
table_type="iceberg-table")
+
+            self.assertEqual(
+                [
+                    "format_table_1",
+                    "format_table_2",
+                    "iceberg_table_1",
+                    "iceberg_table_2",
+                    "normal_table_1",
+                    "normal_table_2",
+                ],
+                all_result.elements,
+            )
+            self.assertEqual(["normal_table_1", "normal_table_2"], 
table_result.elements)
+            self.assertEqual(["format_table_1", "format_table_2"], 
format_table_result.elements)
+            self.assertEqual(["iceberg_table_1", "iceberg_table_2"], 
iceberg_table_result.elements)
+
+            filtered_with_pattern = rest_api.list_tables_paged(
+                "default", table_type="table", table_name_pattern="%_2"
+            )
+            self.assertEqual(["normal_table_2"], 
filtered_with_pattern.elements)
+
+            first_page = rest_api.list_tables_paged(
+                "default", max_results=1, table_type="table"
+            )
+            self.assertEqual(["normal_table_1"], first_page.elements)
+            self.assertIsNotNone(first_page.next_page_token)
+
+            second_page = rest_api.list_tables_paged(
+                "default", max_results=1, 
page_token=first_page.next_page_token, table_type="table"
+            )
+            self.assertEqual(["normal_table_2"], second_page.elements)
+            self.assertEqual("normal_table_2", second_page.next_page_token)
+        finally:
+            server.shutdown()
diff --git a/paimon-python/pypaimon/tests/rest/rest_server.py 
b/paimon-python/pypaimon/tests/rest/rest_server.py
index cb7b321083..fbfa5a487a 100755
--- a/paimon-python/pypaimon/tests/rest/rest_server.py
+++ b/paimon-python/pypaimon/tests/rest/rest_server.py
@@ -79,6 +79,7 @@ AUTHORIZATION_HEADER_KEY = "Authorization"
 # REST API parameter constants
 DATABASE_NAME_PATTERN = "databaseNamePattern"
 TABLE_NAME_PATTERN = "tableNamePattern"
+TABLE_TYPE = "tableType"
 VIEW_NAME_PATTERN = "viewNamePattern"
 FUNCTION_NAME_PATTERN = "functionNamePattern"
 PARTITION_NAME_PATTERN = "partitionNamePattern"
@@ -871,11 +872,22 @@ class RESTCatalogServer:
     def _list_tables(self, database_name: str, parameters: Dict[str, str]) -> 
List[str]:
         """List tables in database"""
         table_name_pattern = parameters.get(TABLE_NAME_PATTERN)
+        table_type = parameters.get(TABLE_TYPE)
         tables = []
 
         for full_name, metadata in self.table_metadata_store.items():
             identifier = Identifier.from_string(full_name)
+            metadata_table_type = (
+                metadata.schema.options.get(TYPE, "table")
+                if metadata and metadata.schema and metadata.schema.options
+                else "table"
+            )
+            table_type_matches = (
+                not table_type
+                or metadata_table_type == table_type
+            )
             if (identifier.get_database_name() == database_name and
+                    table_type_matches and
                     (not table_name_pattern or 
self._match_name_pattern(identifier.get_table_name(),
                                                                         
table_name_pattern))):
                 tables.append(identifier.get_table_name())

Reply via email to